Performance Benchmark

Diffoniq can measure its own compare engine from the command line, without opening a window. This is the mode behind the published speed figures — it is fully reproducible, so you can verify the numbers on your own hardware and data instead of taking them on trust.

Diffoniq /benchmark <left> <right> [options]

The two paths are the same kind as an ordinary comparison: two folders run a directory-tree compare, anything else runs a two-file line diff. The GUI is never created — the process runs the real ItemSelection::analyze path and exits, printing wall-clock timings to the console.

What is measured

Reported times are engine wall-clock only: no window creation, no painting, no message loop. A run is split into phases — scanning each side, matching/comparing, and (for a directory compare with --content) the content-verify pass that hashes equal-sized file pairs across the same worker pool the interactive background compare uses.

Each measurement is repeated (--repeat, default 3). When more than two repeats are taken the first is dropped as warmup; the result block prints both the fastest run (min) and the median, so a single slow outlier does not distort the figure.

Options

--contentDirectory compare only: run the content-verify pass — equal-sized pairs are hash-compared (the same XXH3 hash as the interactive compare), not just checked by size and date.
--repeat NNumber of runs (default 3). With N>2 the first run is dropped as warmup.
--levels NSub-folder recursion depth for a tree compare (default 64 = the full tree).
--cache <file.db>Attach a persistent hash cache for the content pass (needs --content). The first run populates it and later runs resolve from it — this measures the warm-cache case, and each run prints its hit/miss counts. Leave it off to measure a cold compare.
--out <file.csv>Append one summary row to a CSV file (a header row is written when the file is new). See below.
--label <name>A free-text label stored in the CSV row — handy when several runs share one output file.

--replica also exists; it runs the content pass on a stand-alone thread pool instead of the live queue, as an internal cross-check of the two code paths. It is not needed to reproduce the published figures.

Example

Diffoniq /benchmark C:\build\v1 C:\build\v2 --content --repeat 5 --out runs.csv --label v1-vs-v2

Compares two build trees by content, five times, and appends the median timings to runs.csv. Console output ends with a results block:

results (warmup dropped when repeat>2):
  entries=12480
  scan-left : min=210.4  median=214.9 ms
  scan-right: min=208.1  median=211.7 ms
  match     : min=44.6   median=45.2 ms
  content   : min=612.0  median=640.3 ms  (318 pairs, 512 MB hashed, 800 MB/s)
  total     : min=1080.2 median=1112.1 ms  (11220 files/s)

CSV output

With --out the summary is appended as one line per run; the first line of a new file is a self-describing header. The columns are:

label,mode,scenario,engine,repeat,entries,content_pairs,
scan_left_med_ms,scan_right_med_ms,match_med_ms,content_med_ms,
total_min_ms,total_med_ms,left,right,version,build

mode is tree or file; scenario is quick, content or linediff; all timings are milliseconds; entries is the number of rows produced. The file appends, so repeated runs accumulate for comparison in a spreadsheet.

version and build name the binary that produced the row — the build is the short commit hash, with a trailing + when the working tree held uncommitted changes. Both also appear in the console header, so a measurement series identifies its own build instead of relying on a note kept beside it. The header line is only written when the file is new, so start a fresh CSV after upgrading rather than appending to one written by an older version — otherwise the old header no longer matches the rows below it.

Hashing micro-benchmark

A separate in-memory mode compares the raw throughput of the candidate hash algorithms with no file I/O and no queue involved:

Diffoniq /benchmark --hashbench [--size <MB>] [--block <KB>]
        [--repeat <N>] [--out <file.csv>] [--label <name>]

It fills a buffer (--size, default 256 MB) and times CRC32, XXH3-64 and XXH3-128 over it, both chunked (the 32 KB read-loop the real code uses, tunable with --block) and as one shot, printing GB/s and the speed-up over CRC32. Its --out file uses its own header (label,algorithm,size_mb,block_kb,repeat,chunk_ms,chunk_gbs, oneshot_ms,oneshot_gbs,speedup_vs_crc32,version,build), with the same version/build provenance columns as above.

Exit codes

0Benchmark completed
1Compare failed (invalid path or unusable file type)
2Missing or invalid arguments (usage printed)