Symmetric Rust and C# benchmarks of Doublets vs SQLite by category, language, address/id space and size - #108
Conversation
Adding .gitkeep for PR creation (default mode). This file will be removed when the task is complete. Issue: #107
- One CLI runs links or objects benchmarks for 32 or 64 bit ids at any size - SQLite stores links(id, from, to) with (from, to) and (to, from) indexes - Doublets objects mirror Platform.Data.Doublets.Sequences, with and without a sequences cache - Every timed batch is validated by count and order-sensitive checksum - Work around a doublets 0.5.0 split store bug with links updated to reference themselves
Replace the legacy BenchmarkDotNet project with a small CLI and an xunit v3 test project. Both languages now share the dataset, the validated lifecycle, the variant names and the JSON results format, for 32 and 64 bit ids. Doublets links are deleted with the Platform.Data.Doublets overload that resets them first, and objects stores enable external references for raw numbers.
….=10 Raw numbers stored by the objects layout are external references, as in C#. Repetitions default to 3M / size clamped to 1..=10 in both languages, and experiments/sizing times one repetition of each variant to plan CI jobs.
The united store's size balanced trees degenerate in the objects workload, which made every blog post creation linear in the number of stored posts. experiments/csharp_objects_profile measures it per tree type and experiments/csharp_tree_delete shows why links are deleted with the resetting Platform.Data.Doublets overload.
…rarchy One JSON report per (category, language, bits, size); Doublets are compared with SQLite of the same durability, and overlapping ranges or medians within 5% are reported as the same.
Repetitions are work / size clamped to 1..=10; objects now use 500,000 posts of work (5 repetitions at 100,000 posts, 1 at 1,000,000), so that the slowest C# objects table still fits a 6 hour CI job.
…EADME results; dependabot for cargo and actions
…ion; compare interquartile ranges
doublets 0.5.0 takes the slice returned by RawMem::grow for the whole memory, but platform-mem 0.3.0 returns only the grown part, so a fresh store sees 1,040,384 of its 2^20 links and panics when it creates more (Rust objects at 1,000,000 posts and links at 10,000,000 failed on CI). memory::Whole returns the whole memory; experiments/unit_store_growth reproduces the bug and a test grows unit and split stores past 2^20.
…ords too Manual runs with 100,000,000 records then measure only the links tables.
🚨 Solution Draft FailedThe automated solution draft encountered an error: 🤖 Models used:
📎 Failure log uploaded as Gist (14731KB)Now working session is ended, feel free to review and add any feedback on the solution draft. |
📎 Intermediate working-session log (killed session)This log file contains the complete execution trace of the AI solution draft process. 📎 Log file uploaded as Gist (9581KB)Now working session is ended, feel free to review and add any feedback on the solution draft. |
|
|
We need to recover from https://gist.githubusercontent.com/konard/b7b614bf7feef932de7864cff3a5d710/raw/7324688fe747447f55d7854b33961d59d0ffc64a/tmp-hive-mind-log-upload-OLcnzK-sanitized.log.txt, double check that all CI/CD checks will pass like CodeFactor and so on, and that #107 is fully addressed. |
|
🤖 AI Work Session Started Starting automated work session at 2026-10-05T00:19:21.566Z The PR has been converted to draft mode while work is in progress. This comment marks the beginning of an AI work session. Please wait for the session to finish, and provide your feedback. Runtime: solve |
…plit the tree delete experiment into methods
…o 999.6 ns is 1 µs instead of 1e+03 ns
Wrap the prose, put the badges below the title, add the blank lines around headings, fences and tables, and keep the wide generated tables and repeated hierarchy headings in a markdownlint-disable block that the report script writes. The benchmarks workflow lints the committed and regenerated READMEs. Module and comparison docstrings start on the second line (pydocstyle D213).
Required external flag instead of optional parameters (S2360), a static property for the warm-up size (S2339), a local for the Unicode sequence marker (S1450), a parameter name that differs from its method (S3872), and named swapped link ends instead of reordered arguments (S2234), mirrored in Rust. The default work is a separate statement like in Rust (S3358).
…, BEGIN IMMEDIATE in Rust C# inserted with RETURNING id, which makes SQLite inserts about three times slower than the last_insert_rowid that Rust reads (experiments/sqlite_returning: 2.0 vs 6.0 µs per insert), so C# SQLite create looked 2-3x slower than it is (14.3 -> 5.1 µs per link in memory). C# now reads sqlite3_last_insert_rowid through SQLitePCLRaw. Rust transactions start with BEGIN IMMEDIATE like Microsoft.Data.Sqlite's BeginTransaction().
One warm-up repetition left the .NET tiered JIT unfinished, so whichever C# variant ran first looked up to 3x slower than its identical twin (experiments/csharp_warm_up_order.sh). Warm-ups now repeat until a second has passed, and the reports record warm_up_seconds.
…stores are timed The Rust dataset and sequences cache copied every title and content String, while C# shares string references; both now share (Arc<str> in Rust), and the C# checksum no longer allocates a UTF-8 array per string (experiments/rust_objects_ab.sh compares the working tree with HEAD).
experiments/csharp_split_linked_list compares the default useLinkedList=true with false: updates take about 1.1 instead of 1.8 µs per link, the other operations about the same time. doublets 0.5.0 (Rust) has no such list.
Codacy enables both pydocstyle rules, and they contradict each other for every multi-line docstring, so the details move into comments.
… sizes Run 37228604862 measured links at 100,000,000: one SQLite Memory repetition took 1-1.4 hours, and one SQLite File repetition did not finish in the remaining 4.5 hours before the job limit, so even a job per variant would not fit. 1,000,000 blog posts take 53-66 minutes in C# (run 37226110636), so ten millions would need several jobs per table, whose variants would then be compared across machines.
Working session summaryI recovered the interrupted session, finished issue #107 and marked PR #108 ready for review. Every check passes on the last commit (e500f13), including CodeFactor and Codacy (0 new issues), and GitHub reports the merge state as clean. Fixes since the recovered session:
Rest of the working session summary (1 KB)This summary was automatically extracted from the AI working session output. |
🤖 Solution Draft LogThis log file contains the complete execution trace of the AI solution draft process. 💰 Cost: $11.084839📊 Context and tokens usage:Claude Opus 5.5: (4 sub-sessions)
Total: (10.3K new + 594.8K cache writes + 17.7M cache reads) input tokens, 167.1K output tokens, $11.046742 cost Claude Haiku 4.5:
Total: 24.9K input tokens, 644 output tokens, $0.038097 cost 🤖 Models used:
📎 Log file uploaded as Gist (7754KB)Now working session is ended, feel free to review and add any feedback on the solution draft. |
✅ Ready to mergeThis pull request is now ready to be merged:
Monitored by hive-mind with --auto-restart-until-mergeable flag |
Fixes #107
What changed
Rust doublets vs SQLite,C# doublets vs SQLite) →32/64 bit address/id space benchmarks→ size.scripts/benchmark_report.pyregenerates the section between the markers from the JSON reports, with one chart per category, language and bits. Groups without results yet show_No results yet._.u32/uint) and 64 bit (u64/ulong) ids:links(id INTEGER PRIMARY KEY, "from", "to")with the indices("from", "to")and("to", "from"); create, read all, read by id, search by(from, to), read byfrom, read byto, update and delete;Cached/Uncached);≈ same).last_insert_rowid(RETURNING idmakes SQLite inserts about 3× slower, seeexperiments/sqlite_returning);BEGIN IMMEDIATE;experiments/csharp_warm_up_order.sh).experiments/split_store_delete);platform-memgrows their memory, at 1,040,384 links (memory::Whole,experiments/unit_store_growth);Delete(id)leaves links in the index trees, soDelete(id, handler: null)is used (experiments/csharp_tree_delete);experiments/csharp_objects_profile);experiments/csharp_split_linked_list).rust/Cargo.lockno longer has thelibsqlite3-sys,attyandremove_dir_allversions Dependabot flags onmain.-D warnings, tests on Linux, macOS and Windows) and .NET 10 (-warnaserror, tests) checks;mainpublish the README results and charts.The README results come from run 37226110636, which ran before the
last_insert_rowid, warm-up and shared-strings fixes. The first push tomainregenerates them.Reproduction and regression coverage
split_store_keeps_links_updated_to_reference_themselves/SplitStoreKeepsLinksUpdatedToReferenceThemselves: a split store keeps a link updated to(id, id).stores_keep_their_links_when_their_memory_growsandgrow_returns_the_whole_memory: Rust stores keep working past 1,040,384 links.every_links_variant_passes_the_lifecycle/EveryLinksVariantPassesTheLifecycleand the objects equivalents run every operation of every variant with checksum validation. In C#, this covers theDelete(id, handler: null)and AVL-tree workarounds.LifecycleRejectsAStorageThatLosesRecords: a storage that loses a record fails instead of looking fast.every_objects_storage_returns_the_stored_posts/EveryObjectsStorageReturnsTheStoredPosts: titles and contents round-trip with and without the cache, including the empty string.test_outlier_repetitions_do_not_hide_a_differenceuses real C# samples where the old min–max overlap called a 5× difference≈ same;test_rounding_up_moves_to_the_next_unit_instead_of_an_exponentcovers the 999.6 ns →1e+03 nsbug;test_hierarchy_is_category_language_bits_sizechecks the README hierarchy.Verification
cargo fmt --check,cargo clippy --all-targets --release -- -D warnings,cargo test --release: 9 testsdotnet build -c Release -warnaserror,dotnet test --project SQLiteVSDoublets.Tests -c Release --no-build: 28 testspython -m unittest discover -s scripts: 17 tests, including chart generation;markdownlinton both READMEsThis is benchmark and documentation infrastructure; there are no UI changes or screenshots.