rugnux: record in the report how the run was invoked, what it cost and what it ran on
The results report said what the run determined but nothing about how it was produced, so a report read next to a lost shell history could not be reproduced or compared. Four keys in the header block, all new, none renamed - a consumer that greps for what it needs is unaffected, so REPORT_VERSION does not move: COMMAND_LINE= rugnux -o myrun --model model.pdb dataset_master.h5 WALL_TIME= 262.41 GPU_COUNT= 4 GPU= 4x NVIDIA A100-SXM4-80GB The command line is argv as one shell-ready line; an argument that would not survive being pasted back into a shell is single-quoted, so a file prefix with a space comes back as the one argument it was. It replaces the raw argv echo at the top of the run, which had no quoting at all. WALL_TIME is the whole invocation, timed from the top of the CLI. It is deliberately not result.total_time_s, which starts inside Rugnux::Run and so counts neither opening the file nor setting up the analysis - and which --mode scale never sets at all, having no ProcessResult of its own. It is printed on stdout as well, next to the processing time it is slightly larger than. The GPUs are the reason rugnux is fast, and until now nothing said whether any were being used. get_gpu_names() reports them per device and get_gpu_description() collapses repeats, so four identical cards read as one line rather than the same name four times and a mixed machine keeps one group per model. Both have a CPU-only implementation, so the JFJOCH_USE_CUDA=OFF build reports GPU_COUNT= 0 rather than failing to link. The same line is printed at startup, before the run rather than after it: a machine that turns out to have no GPU - a driver mismatch, a CUDA_VISIBLE_DEVICES left over from another job - is worth knowing about while there is still time to stop, not once the run has taken an order of magnitude longer than it should. GPU_COUNT= 0 is written with no GPU= line beside it, because the absence is the statement. The header comment claiming timing is deliberately absent from the report is now wrong and says so: rates and per-image costs stay on stdout, the total does not. Verified on the rotation test dataset in both build configurations, with and without CUDA_VISIBLE_DEVICES, in --mode mx and --mode scale. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WmryXe8ASbNi632sUMfsa
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
#include "../image_analysis/scale_merge/Merge.h"
|
||||
#include "../reader/JFJochHDF5Reader.h"
|
||||
#include "../rugnux/ResultReport.h"
|
||||
#include "../common/CUDAWrapper.h"
|
||||
#include "../writer/FileWriter.h"
|
||||
|
||||
// Two synthetic ranges, one of each shape the report has to handle.
|
||||
@@ -182,3 +183,56 @@ TEST_CASE("SweepQuality_HDF5RoundTrip", "[HDF5][Full][Diagnostics]") {
|
||||
REQUIRE(H5Fget_obj_count(H5F_OBJ_ALL, H5F_OBJ_ALL) == 0);
|
||||
remove("sweep_quality_roundtrip_master.h5");
|
||||
}
|
||||
|
||||
// The command line, the wall time and the GPUs say how the result was produced, what it cost and what
|
||||
// it ran on, so the report can be read on its own once the shell history is gone. They come from the
|
||||
// CLI, which is the only caller that knows them; a caller that does not - the library, the viewer -
|
||||
// must get a report without them rather than one claiming the run was invoked by nobody, took no
|
||||
// time, and saw no GPU.
|
||||
TEST_CASE("ResultReport_ProvenanceKeys", "[Diagnostics]") {
|
||||
DiffractionExperiment x(DetJF(1));
|
||||
x.ImagesPerTrigger(600);
|
||||
|
||||
ProcessResult result;
|
||||
result.images_processed = 600;
|
||||
result.consensus_cell = UnitCell{.a = 79.0f, .b = 79.0f, .c = 38.0f,
|
||||
.alpha = 90.0f, .beta = 90.0f, .gamma = 90.0f};
|
||||
|
||||
RunProvenance provenance;
|
||||
provenance.command_line = "rugnux -o prefix in.h5";
|
||||
provenance.wall_time_s = 262.409;
|
||||
provenance.gpu_count = 4;
|
||||
provenance.gpu_description = "4x NVIDIA A100-SXM4-80GB";
|
||||
|
||||
const auto text = RenderResultReport("prefix", "in.h5", x, result, provenance);
|
||||
CHECK(text.find("\nCOMMAND_LINE= rugnux -o prefix in.h5\n") != std::string::npos);
|
||||
CHECK(text.find("\nWALL_TIME= 262.41\n") != std::string::npos);
|
||||
CHECK(text.find("\nGPU_COUNT= 4\n") != std::string::npos);
|
||||
CHECK(text.find("\nGPU= 4x NVIDIA A100-SXM4-80GB\n") != std::string::npos);
|
||||
|
||||
// A machine with no GPU says so - GPU_COUNT= 0 is a statement about why the run took as long as
|
||||
// it did, and only the name list has nothing to report.
|
||||
RunProvenance cpu_only;
|
||||
cpu_only.gpu_count = 0;
|
||||
const auto cpu_text = RenderResultReport("prefix", "in.h5", x, result, cpu_only);
|
||||
CHECK(cpu_text.find("\nGPU_COUNT= 0\n") != std::string::npos);
|
||||
CHECK(cpu_text.find("\nGPU= ") == std::string::npos);
|
||||
|
||||
const auto without = RenderResultReport("prefix", "in.h5", x, result);
|
||||
CHECK(without.find("COMMAND_LINE=") == std::string::npos);
|
||||
CHECK(without.find("WALL_TIME=") == std::string::npos);
|
||||
CHECK(without.find("GPU_COUNT=") == std::string::npos);
|
||||
}
|
||||
|
||||
// get_gpu_description collapses repeats, so a four-card machine reads as one line rather than the
|
||||
// same name four times. Build-independent: without CUDA there are no names and it is empty.
|
||||
TEST_CASE("ResultReport_GpuDescription", "[Diagnostics]") {
|
||||
const auto names = get_gpu_names();
|
||||
CHECK(names.size() == static_cast<size_t>(std::max(0, get_gpu_count())));
|
||||
|
||||
const auto description = get_gpu_description();
|
||||
if (names.empty())
|
||||
CHECK(description.empty());
|
||||
else
|
||||
CHECK(description.find(names.front()) != std::string::npos);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user