bench(bsim): reproducible corpus + weighted-vs-unweighted at scale - #52
Draft
rdmmf wants to merge 1 commit into
Draft
bench(bsim): reproducible corpus + weighted-vs-unweighted at scale#52rdmmf wants to merge 1 commit into
rdmmf wants to merge 1 commit into
Conversation
The comparison in #50 ran on 21 and 20 shared function names, where one dataset saturated at 100% recall for every algorithm. This replaces it with a corpus large enough to separate them, and with unrelated programs on the reference side so a wrong top-1 is a real false positive. Corpus (doc/bench_corpus.md): 5 open-source C projects pinned by version and sha256, cross-compiled to 6 targets x 3 optimisation levels x dynamic/static by direct compiler invocation -- no autotools, no container, so it rebuilds identically anywhere the Debian cross toolchains exist. 180 binaries, 313,685 defined functions, unstripped (symbol names are the ground truth), half statically linked so libc boilerplate is actually present. Results (doc/bench_weighted_vs_unweighted.md), 46 binaries / 166 build pairs / 18,239 queries so far: - weighted 86.4% recall@1 vs unweighted 80.3%, jaccard 86.2% - on the optimisation axis, the hard case: 75.0% vs 63.3% (+11.7 points) - cross-program false positives 2.59% vs 4.00% - per-pair cost 1.16-1.19x unweighted, parity on large vectors - Ghidra's shipped IDF table fits this corpus: 0/50 top features absent Also adds a Ghidra BSim H2 baseline (bsim_baseline.py + BSimQueryAll.java), which shows 12.9% of true matches never survive its LSH candidate selection. It drives support/bsim from the vendored bin/ install; no BSim dependency is added to BSimVis. CLI: --save-json was silently ignored on the --local-analysis chunked path. Fixed, and added --no-upload plus --save-vectors, which writes compact {function: {hash: tf}} vectors -- the full dump of a static binary is several GB, which no offline consumer can load. wt-test.sh: 326/326 pass.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacks on
worktree-bsim-weights(#50). Replaces the 21-function comparison posted there with a corpus that can actually separate the algorithms.The corpus (
doc/bench_corpus.md)5 open-source C projects — sqlite, zlib, lua, zstd, mbedtls — pinned by version and sha256, cross-compiled to 6 targets × 3 optimisation levels × dynamic/static: 180 binaries, 313,685 defined functions. One direct compiler invocation per binary, no autotools and no container, so it rebuilds identically on any machine with the Debian cross toolchains. Nothing is vendored here;
build_corpus.shfetches and verifies.Two deliberate choices: binaries are unstripped, because symbol names are the ground truth (same name across builds = known match, no labelling pass); and half are statically linked, so libc — the boilerplate weighting is supposed to suppress — is really in the corpus, and unrelated programs genuinely share code.
The reference side of every query is every other project's binary of the same variant, so a wrong top-1 is a cross-program false positive rather than a same-program near-miss. That is what #50's single-project dataset could not measure at all.
Results (
doc/bench_weighted_vs_unweighted.md)46 binaries extracted so far, 166 build pairs, 18,239 queried functions:
compare()to 7.8e-16.Ghidra BSim baseline
bsim_baseline.py+bsim/BSimQueryAll.javabuild a real BSim H2 database, commit signatures and query it headlessly. 12.9% of true matches never appear in BSim's results at all — eliminated by LSH binning before scoring.oracle_compare.pyproves our arithmetic matches Ghidra's; this shows what its candidate-selection stage costs, which that test cannot.Benchmark-only: it drives
support/bsimandsupport/analyzeHeadlessfrom the Ghidra already inbin/. No BSim dependency, driver or config is added to BSimVis.Throughput, and one honest gap
jaccard 34.2 s / 6,359 sims vs unweighted_cosine 80.4 s / 34,568 sims on 5,709 functions (cosine admits 5.4x more pairs at the same threshold, so it is cheaper per similarity written). Ingest is ~7 min/binary, all decompiler — scoring changes are noise against it.
weighted_cosinecannot be measured end to end: the build path rejects it, so all quality numbers above come from offline scoring. Landing weighting in the build path is the prerequisite for a real throughput comparison.CLI fix
--save-jsonwas silently ignored on the--local-analysischunked path. Fixed, plus--no-upload(offline extraction, no stack) and--save-vectors, which writes compact{function: {hash: tf}}— the full dump of a static binary is several GB, which no offline consumer can load without OOM.Verification
./scripts/wt-test.sh: 326/326 pass.Extraction of the remaining 134 binaries is Ghidra-bound and still running; the corpus, scripts and conclusions do not change, the numbers will move slightly.
🤖 Generated with Claude Code