Skip to content

Commit 97a8b3e

Browse files
committed
cost_analysis: use portable compare_files for reference tests
Add --omit-revision to drop the volatile git-revision line, and end the report with a single trailing newline (leading section separators instead of trailing ones) so it is byte-stable. The tests then use plain cmake -E compare_files instead of sed/diff, making them portable. The tree dump is diffed against a new R2.tree.txt.expected fixture.
1 parent f4b9966 commit 97a8b3e

8 files changed

Lines changed: 36 additions & 30 deletions

File tree

utilities/cost_analysis/CMakeLists.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,26 @@ target_link_libraries(cost_analysis PRIVATE
1010
target_set_warning_flags(cost_analysis)
1111

1212
foreach(NAME IN ITEMS "ccsd_r2" "df_r1")
13+
# --omit-revision drops the volatile git-revision line so a plain
14+
# compare_files suffices; the tool writes the report next to the driver.
1315
add_test(
1416
NAME "sequant/cost_analysis/${NAME}/generate"
15-
COMMAND cost_analysis --driver "${CMAKE_CURRENT_LIST_DIR}/examples/${NAME}.json")
17+
COMMAND cost_analysis --driver "${CMAKE_CURRENT_LIST_DIR}/examples/${NAME}.json" --omit-revision)
1618
set_tests_properties("sequant/cost_analysis/${NAME}/generate"
1719
PROPERTIES FIXTURES_SETUP "COST_ANALYSIS_${NAME}")
1820

19-
# Strip the volatile git-revision line before diffing; -B ignores the extra
20-
# trailing blank line the live report carries but the fixture doesn't.
2121
add_test(
2222
NAME "sequant/cost_analysis/${NAME}/verify"
23-
COMMAND bash -c "diff -B <(sed '/^_SeQuant:/d' '${NAME}.md') <(sed '/^_SeQuant:/d' '${NAME}.md.expected')"
23+
COMMAND "${CMAKE_COMMAND}" -E compare_files "${NAME}.md" "${NAME}.md.expected"
2424
WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/examples")
2525
set_tests_properties("sequant/cost_analysis/${NAME}/verify"
2626
PROPERTIES FIXTURES_REQUIRED "COST_ANALYSIS_${NAME}")
2727
endforeach()
2828

29-
# ccsd_r2 exercises --dump_tree; check the tree file was produced.
29+
# ccsd_r2 exercises --dump_tree; diff the tree dump against its fixture.
3030
add_test(
3131
NAME "sequant/cost_analysis/ccsd_r2/dump_tree"
32-
COMMAND bash -c "test -f R2.tree.txt"
32+
COMMAND "${CMAKE_COMMAND}" -E compare_files "R2.tree.txt" "R2.tree.txt.expected"
3333
WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/examples")
3434
set_tests_properties("sequant/cost_analysis/ccsd_r2/dump_tree"
3535
PROPERTIES FIXTURES_REQUIRED "COST_ANALYSIS_ccsd_r2")

utilities/cost_analysis/README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,11 @@ The quantities that aren't self-evident:
108108
## Tests
109109

110110
Reference tests (`ctest -R sequant/cost_analysis`) run the tool on `examples/`
111-
and diff the report against a frozen `*.md.expected` (the volatile git-revision
112-
line is stripped before diffing):
111+
with `--omit-revision` (which drops the volatile git-revision line, making the
112+
report byte-stable) and compare it against a frozen `*.md.expected` via
113+
`cmake -E compare_files`:
113114

114115
- `.../ccsd_r2/*` — spin-orbital CCSD R2 (a `Sum` of terms) whose two ladder
115-
terms share one `g*t` intermediate, exercising the reuse census; also checks
116-
the `--dump_tree` output was produced.
116+
terms share one `g*t` intermediate, exercising the reuse census; also diffs
117+
the `--dump_tree` output against `R2.tree.txt.expected`.
117118
- `.../df_r1/*` — a single density-fitted product (the non-`Sum` path).

utilities/cost_analysis/cost_analysis.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,9 @@ int main(int argc, char** argv) {
337337
std::filesystem::path driver;
338338
app.add_option("--driver", driver, "Path to the JSON driver file")
339339
->required();
340+
bool omit_revision = false;
341+
app.add_flag("--omit-revision", omit_revision,
342+
"Omit the git-revision line (for reproducible test diffs)");
340343
CLI11_PARSE(app, argc, argv);
341344

342345
try {
@@ -349,7 +352,8 @@ int main(int argc, char** argv) {
349352
std::filesystem::current_path(
350353
std::filesystem::absolute(driver).parent_path());
351354

352-
const Config cfg = load_config(d);
355+
Config cfg = load_config(d);
356+
cfg.out.omit_revision = omit_revision;
353357
setup_context(cfg); // registry baked before any parse
354358

355359
std::vector<std::pair<std::string, CellResult>> results;

utilities/cost_analysis/cost_analysis.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ struct OutSpec {
4141
std::string path = "cost_analysis.md";
4242
std::size_t top_n = 20; ///< rows in the largest/expensive tables
4343
bool dump_tree = false; ///< also write each result's binarized tree
44+
bool omit_revision =
45+
false; ///< drop the git-revision line (reproducible diffs)
4446
};
4547

4648
/// One `equations[]` entry: a named equation file to analyze.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
(g(a_1,a_2,i_1,i_2) * 1)
2+
((g(a_3,a_4,i_1,i_2) * t(i_3,i_4,a_3,a_4)) * R(a_1,a_2,i_3,i_4))
3+
((g(a_3,a_4,i_1,i_2) * t(i_3,i_4,a_3,a_4)) * t(a_1,a_2,i_3,i_4))

utilities/cost_analysis/examples/ccsd_r2.md.expected

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# SeQuant cost analysis
22

3-
_SeQuant: <version>_
4-
53
Sizes in MB (8 bytes/element).
64

75
## R2

utilities/cost_analysis/examples/df_r1.md.expected

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# SeQuant cost analysis
22

3-
_SeQuant: <version>_
4-
53
Sizes in MB (16 bytes/element).
64

75
## R1

utilities/cost_analysis/report.cpp

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ void report_largest(const CellResult& cell, std::size_t top_n,
3636
rec->label, rec->spaces, mb(rec->memory, bytes_per_elem),
3737
rec->uses, full_expr(*node), rec->flops.text());
3838
}
39-
out << "\n";
4039
}
4140

4241
void report_expensive(const CellResult& cell, std::size_t top_n,
@@ -59,7 +58,6 @@ void report_expensive(const CellResult& cell, std::size_t top_n,
5958
rec->spaces, rec->uses, full_expr(*node),
6059
rec->flops.text());
6160
}
62-
out << "\n";
6361
}
6462

6563
void report_shape_histogram(const CellResult& cell, double bytes_per_elem,
@@ -92,7 +90,6 @@ void report_shape_histogram(const CellResult& cell, double bytes_per_elem,
9290
for (const auto& [shape, g] : rows)
9391
out << std::format("| {} | {:.4f} | {} | {} |\n", shape,
9492
mb(g.mem, bytes_per_elem), g.count, g.uses);
95-
out << "\n";
9693
}
9794

9895
} // namespace
@@ -109,37 +106,40 @@ void write_report(
109106
const std::vector<std::pair<std::string, CellResult>>& results,
110107
const SimResult& sim, std::ostream& out) {
111108
const double bytes_per_elem = cfg.real_field ? 8.0 : 16.0;
112-
out << "# SeQuant cost analysis\n\n"
113-
<< std::format("_SeQuant: {}_\n\n", git_revision())
114-
<< std::format("Sizes in MB ({} bytes/element).\n\n", bytes_per_elem);
109+
// Sections are separated by a leading blank line rather than a trailing one,
110+
// so the report ends with a single newline (matches the committed fixtures).
111+
out << "# SeQuant cost analysis\n";
112+
if (!cfg.out.omit_revision)
113+
out << std::format("\n_SeQuant: {}_\n", git_revision());
114+
out << std::format("\nSizes in MB ({} bytes/element).\n", bytes_per_elem);
115115
for (const auto& [name, cell] : results) {
116-
out << std::format("## {}\n\n", name);
116+
out << std::format("\n## {}\n", name);
117117
out << std::format(
118-
"Terms: {}; distinct intermediates: {}; reused: {}; largest: {:.4f} "
119-
"MB; peak storage: {:.4f} MB.\n\n",
118+
"\nTerms: {}; distinct intermediates: {}; reused: {}; largest: {:.4f} "
119+
"MB; peak storage: {:.4f} MB.\n",
120120
cell.n_terms, cell.n_distinct, cell.n_reused,
121121
mb(cell.largest_mem, bytes_per_elem),
122122
mb(cell.peak_storage, bytes_per_elem));
123123
// Op-count only; no concrete FLOP number.
124-
out << std::format("Total operations (symbolic): {}\n\n",
124+
out << std::format("\nTotal operations (symbolic): {}\n",
125125
cell.total_flops.text());
126-
out << "### Largest intermediates\n\n";
126+
out << "\n### Largest intermediates\n\n";
127127
report_largest(cell, cfg.out.top_n, bytes_per_elem, out);
128-
out << "### Most expensive contractions\n\n";
128+
out << "\n### Most expensive contractions\n\n";
129129
report_expensive(cell, cfg.out.top_n, out);
130-
out << "### Shape census\n\n";
130+
out << "\n### Shape census\n\n";
131131
report_shape_histogram(cell, bytes_per_elem, out);
132132
}
133133
if (cfg.cache.enabled) {
134134
out << std::format(
135-
"## Cache (gated, volatile leaf = \"{}\", min_repeats = {})\n\n",
135+
"\n## Cache (gated, volatile leaf = \"{}\", min_repeats = {})\n\n",
136136
cfg.optimize.volatile_leaf, cfg.cache.min_repeats);
137137
out << "| Metric | Value |\n|---|---|\n";
138138
out << std::format("| Cached | {} |\n", sim.n_cached);
139139
out << std::format("| Persistent | {} |\n", sim.n_persistent);
140140
out << std::format("| Persistent footprint (MB) | {:.4f} |\n",
141141
mb(sim.persistent_footprint, bytes_per_elem));
142-
out << std::format("| Total cached footprint (MB) | {:.4f} |\n\n",
142+
out << std::format("| Total cached footprint (MB) | {:.4f} |\n",
143143
mb(sim.cached_footprint, bytes_per_elem));
144144
}
145145
}

0 commit comments

Comments
 (0)