mirror of
https://github.com/NVIDIA/nvbench.git
synced 2026-07-12 18:17:49 +00:00
* Store jsonbin sidecar paths relative to JSON output Keep --jsonbin sidecar files written next to the JSON output file, but record their filenames relative to the JSON file directory. This makes generated JSON and its sidecar directories relocatable as a unit and avoids embedding the benchmark process working-directory relationship into the JSON payload. Add a focused json_printer test that verifies sample-time and sample-frequency sidecars are written beside the JSON file while summary filename fields contain JSON-relative paths. * Factor out jsonbin sidecar writing helper Extract the duplicated sample-times and sample-frequencies jsonbin sidecar write paths into a shared helper. This keeps directory creation, file writing, warning logging, summary metadata, and write-duration logging in one place for both sidecar types. * Test jsonbin sidecar write failure handling Cover the case where the expected sidecar directory path collides with a regular file. Verify that json_printer keeps descriptive summary metadata but omits filename and size when the sidecar file was not written. Register printer and verify output. * Clean up jsonbin sidecar logging Factor repeated optional benchmark-printer logging in write_jsonbin_sidecar into a local helper used by both warning and success paths. Also tidy the jsonbin summary names for sample time and frequency sidecar files.
163 lines
4.8 KiB
Plaintext
163 lines
4.8 KiB
Plaintext
/*
|
|
* Copyright 2026 NVIDIA Corporation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 with the LLVM exception
|
|
* (the "License"); you may not use this file except in compliance with
|
|
* the License.
|
|
*
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://llvm.org/foundation/relicensing/LICENSE.txt
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <nvbench/benchmark.cuh>
|
|
#include <nvbench/callable.cuh>
|
|
#include <nvbench/json_printer.cuh>
|
|
#include <nvbench/printer_base.cuh>
|
|
#include <nvbench/state.cuh>
|
|
#include <nvbench/summary.cuh>
|
|
#include <nvbench/types.cuh>
|
|
|
|
#include <chrono>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <system_error>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "test_asserts.cuh"
|
|
|
|
#if __has_include(<filesystem>)
|
|
#include <filesystem>
|
|
namespace fs = std::filesystem;
|
|
#elif __has_include(<experimental/filesystem>)
|
|
#include <experimental/filesystem>
|
|
namespace fs = std::experimental::filesystem;
|
|
#else
|
|
#error "No <filesystem> or <experimental/filesystem> found."
|
|
#endif
|
|
|
|
void dummy_generator(nvbench::state &) {}
|
|
NVBENCH_DEFINE_CALLABLE(dummy_generator, dummy_callable);
|
|
using dummy_bench = nvbench::benchmark<dummy_callable>;
|
|
|
|
struct recording_printer : nvbench::printer_base
|
|
{
|
|
explicit recording_printer(std::ostream &stream)
|
|
: nvbench::printer_base{stream}
|
|
{}
|
|
|
|
std::vector<std::pair<nvbench::log_level, std::string>> logs;
|
|
|
|
protected:
|
|
void do_log(nvbench::log_level level, const std::string &msg) override
|
|
{
|
|
logs.emplace_back(level, msg);
|
|
}
|
|
};
|
|
|
|
struct temp_directory
|
|
{
|
|
temp_directory()
|
|
: path{fs::temp_directory_path() /
|
|
("nvbench-json-printer-test-" +
|
|
std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()))}
|
|
{
|
|
fs::create_directories(path);
|
|
}
|
|
|
|
~temp_directory()
|
|
{
|
|
std::error_code ec;
|
|
fs::remove_all(path, ec);
|
|
}
|
|
|
|
fs::path path;
|
|
};
|
|
|
|
namespace nvbench::detail
|
|
{
|
|
// nvbench::state construction is private to the state generator and this test
|
|
// hook; use the friend type to build a minimal state for printer testing.
|
|
struct state_tester : public nvbench::state
|
|
{
|
|
state_tester(const nvbench::benchmark_base &bench)
|
|
: nvbench::state{bench}
|
|
{}
|
|
};
|
|
} // namespace nvbench::detail
|
|
|
|
void test_jsonbin_filenames_are_json_relative()
|
|
{
|
|
const temp_directory tmp_dir;
|
|
const auto json_path = tmp_dir.path / "result.json";
|
|
|
|
std::ofstream json_stream{json_path};
|
|
nvbench::json_printer printer{json_stream, json_path.string(), true};
|
|
|
|
dummy_bench bench;
|
|
nvbench::detail::state_tester state{bench};
|
|
|
|
printer.process_bulk_data(state, "nv/cold/sample_times", "sample_times", {1.0, 2.0});
|
|
printer.process_bulk_data(state, "nv/cold/sample_freqs", "sample_freqs", {3.0, 4.0});
|
|
|
|
const auto samples_filename =
|
|
state.get_summary("nv/json/bin:nv/cold/sample_times").get_string("filename");
|
|
const auto freqs_filename =
|
|
state.get_summary("nv/json/freqs-bin:nv/cold/sample_freqs").get_string("filename");
|
|
|
|
ASSERT(fs::path{samples_filename} == fs::path{"result.json-bin"} / "0.bin");
|
|
ASSERT(fs::path{freqs_filename} == fs::path{"result.json-freqs-bin"} / "0.bin");
|
|
ASSERT(fs::exists(tmp_dir.path / samples_filename));
|
|
ASSERT(fs::exists(tmp_dir.path / freqs_filename));
|
|
}
|
|
|
|
void test_jsonbin_write_failure_omits_file_metadata()
|
|
{
|
|
const temp_directory tmp_dir;
|
|
const auto json_path = tmp_dir.path / "result.json";
|
|
const auto collision_path = tmp_dir.path / "result.json-bin";
|
|
|
|
{
|
|
std::ofstream collision{collision_path};
|
|
collision << "not a directory";
|
|
}
|
|
|
|
std::ofstream json_stream{json_path};
|
|
nvbench::json_printer printer{json_stream, json_path.string(), true};
|
|
|
|
std::ostringstream log_stream;
|
|
recording_printer log_printer{log_stream};
|
|
|
|
dummy_bench bench;
|
|
bench.set_printer(log_printer);
|
|
nvbench::detail::state_tester state{bench};
|
|
|
|
printer.process_bulk_data(state, "nv/cold/sample_times", "sample_times", {1.0, 2.0});
|
|
|
|
const auto &summary = state.get_summary("nv/json/bin:nv/cold/sample_times");
|
|
ASSERT(summary.has_value("name"));
|
|
ASSERT(summary.has_value("hint"));
|
|
ASSERT(summary.has_value("description"));
|
|
ASSERT(!summary.has_value("filename"));
|
|
ASSERT(!summary.has_value("size"));
|
|
ASSERT(fs::is_regular_file(collision_path));
|
|
ASSERT(log_printer.logs.size() == 1);
|
|
ASSERT(log_printer.logs[0].first == nvbench::log_level::warn);
|
|
ASSERT(log_printer.logs[0].second.find("Error writing nv/cold/sample_times (sample_times)") !=
|
|
std::string::npos);
|
|
}
|
|
|
|
int main()
|
|
{
|
|
test_jsonbin_filenames_are_json_relative();
|
|
test_jsonbin_write_failure_omits_file_metadata();
|
|
}
|