|
14 | 14 |
|
15 | 15 | #include <algorithm> |
16 | 16 | #include <cerrno> |
| 17 | +#include <chrono> |
17 | 18 | #include <cstdint> |
18 | 19 | #include <cstdio> |
19 | 20 | #include <cstdlib> |
20 | 21 | #include <cstring> |
| 22 | +#include <filesystem> |
21 | 23 | #include <fstream> |
22 | 24 | #include <iostream> |
23 | 25 | #include <stdexcept> |
@@ -76,6 +78,11 @@ void print_usage(char const* prog) |
76 | 78 | << " Open <plotfile> and run N random challenges through the CPU prover.\n" |
77 | 79 | << " Zero proofs across a sensible sample (>=100) strongly indicates a\n" |
78 | 80 | << " corrupt plot. Default N=100.\n" |
| 81 | + << " " << prog << " parity-check [--dir PATH]\n" |
| 82 | + << " Run every *_parity binary in PATH and summarize PASS/FAIL.\n" |
| 83 | + << " Default PATH is ./build/tools/parity. Build the tests with\n" |
| 84 | + << " `cmake --build <build-dir>` first. Useful for post-refactor\n" |
| 85 | + << " regression screening.\n" |
79 | 86 | << "\n" |
80 | 87 | << " test-mode positional args:\n" |
81 | 88 | << " <k> : even integer in [18, 32]\n" |
@@ -305,6 +312,80 @@ extern "C" int xchplot2_main(int argc, char* argv[]) |
305 | 312 | } |
306 | 313 | } |
307 | 314 |
|
| 315 | + if (mode == "parity-check") { |
| 316 | + std::string dir = "./build/tools/parity"; |
| 317 | + for (int i = 2; i < argc; ++i) { |
| 318 | + std::string a = argv[i]; |
| 319 | + if ((a == "--dir" || a == "-d") && i + 1 < argc) { |
| 320 | + dir = argv[++i]; |
| 321 | + } else { |
| 322 | + std::cerr << "Error: unknown argument: " << a << "\n"; |
| 323 | + print_usage(argv[0]); |
| 324 | + return 1; |
| 325 | + } |
| 326 | + } |
| 327 | + |
| 328 | + // Glob every *_parity binary in `dir`. Same code path works for |
| 329 | + // both branches — main ships sycl_*_parity extras that cuda-only |
| 330 | + // doesn't, and the wildcard picks up whichever actually exists. |
| 331 | + std::vector<std::filesystem::path> tests; |
| 332 | + std::error_code ec; |
| 333 | + if (std::filesystem::is_directory(dir, ec)) { |
| 334 | + for (auto const& entry : |
| 335 | + std::filesystem::directory_iterator(dir, ec)) |
| 336 | + { |
| 337 | + auto const name = entry.path().filename().string(); |
| 338 | + constexpr char const kSuffix[] = "_parity"; |
| 339 | + constexpr size_t kLen = sizeof(kSuffix) - 1; |
| 340 | + bool const ends = |
| 341 | + name.size() >= kLen && |
| 342 | + name.compare(name.size() - kLen, kLen, kSuffix) == 0; |
| 343 | + if (ends && entry.is_regular_file(ec)) { |
| 344 | + tests.push_back(entry.path()); |
| 345 | + } |
| 346 | + } |
| 347 | + } |
| 348 | + if (tests.empty()) { |
| 349 | + std::cerr << "No `*_parity` binaries found under " << dir << ".\n" |
| 350 | + "Build them first:\n" |
| 351 | + " cmake -B build -S . -DCMAKE_BUILD_TYPE=Release\n" |
| 352 | + " cmake --build build --parallel\n" |
| 353 | + "Then re-run from the repo root, or pass --dir <path>.\n"; |
| 354 | + return 2; |
| 355 | + } |
| 356 | + std::sort(tests.begin(), tests.end()); |
| 357 | + |
| 358 | + int pass = 0, fail = 0; |
| 359 | + std::cerr << "==> parity tests (" << tests.size() << " found in " |
| 360 | + << dir << ")\n"; |
| 361 | + for (auto const& test : tests) { |
| 362 | + auto const name = test.filename().string(); |
| 363 | + std::string const log_path = |
| 364 | + "/tmp/xchplot2-parity-" + name + ".log"; |
| 365 | + // Redirecting through the shell: `test` is a path we |
| 366 | + // generated ourselves from a directory listing — no user- |
| 367 | + // controlled shell metachars reach this string. |
| 368 | + std::string const cmd = |
| 369 | + test.string() + " >" + log_path + " 2>&1"; |
| 370 | + auto const t0 = std::chrono::steady_clock::now(); |
| 371 | + int const rc = std::system(cmd.c_str()); |
| 372 | + auto const ms = std::chrono::duration<double, std::milli>( |
| 373 | + std::chrono::steady_clock::now() - t0).count(); |
| 374 | + if (rc == 0) { |
| 375 | + std::fprintf(stderr, " PASS %-32s (%.1f ms)\n", |
| 376 | + name.c_str(), ms); |
| 377 | + ++pass; |
| 378 | + } else { |
| 379 | + std::fprintf(stderr, |
| 380 | + " FAIL %-32s (exit %d; log: %s)\n", |
| 381 | + name.c_str(), rc, log_path.c_str()); |
| 382 | + ++fail; |
| 383 | + } |
| 384 | + } |
| 385 | + std::fprintf(stderr, "\n==> %d passed, %d failed\n", pass, fail); |
| 386 | + return fail > 0 ? 1 : 0; |
| 387 | + } |
| 388 | + |
308 | 389 | if (mode == "plot") { |
309 | 390 | // Standalone farmable-plot path: derive plot_id + memo internally. |
310 | 391 | int k = 28; |
|
0 commit comments