Skip to content

Check freed debug block fill patterns 32 bytes at a time#97

Closed
janrysavy wants to merge 1 commit into
pleriche:masterfrom
janrysavy:perf/debug-fill-validation
Closed

Check freed debug block fill patterns 32 bytes at a time#97
janrysavy wants to merge 1 commit into
pleriche:masterfrom
janrysavy:perf/debug-fill-validation

Conversation

@janrysavy

@janrysavy janrysavy commented Jul 21, 2026

Copy link
Copy Markdown

Summary

This changes CheckFreedDebugBlockFillPatternIntact to validate 32 bytes per main-loop iteration instead of one 8-byte word. At 4 KiB, throughput improved by 40.18% on AMD Win64 and 14.45% on AMD Win32; Intel improved by 38.31% on Win64 but only 3.30% on Win32. The change adds four UInt64 comparisons before the existing 8-byte remainder loop, while preserving the freed-object prefix check, 4/2/1-byte remainder handling, corruption result, and logging path. The diff adds 16 lines and changes one comment.

This is complementary to #92: that PR can disable fill-pattern diagnostics for selected configurations, while this change speeds up the unchanged diagnostic path when freed-block validation remains enabled.

Tracking issue: #99

Benchmark

The benchmark repeatedly allocates and frees one block in FastMM5 debug mode with stack-trace collection disabled. Results are medians of 25 alternating baseline/candidate process pairs after three warmups. Throughput gain is (baseline time / candidate time - 1) * 100; the 95% interval is a deterministic 10,000-resample bootstrap interval for the paired median.

AMD Ryzen 9 7950X:

Target User size Operations Baseline median Candidate median Throughput gain (95% CI)
Win64 64 B 4,000,000 190.79 ms 178.72 ms 6.58% (6.12% to 8.03%)
Win32 64 B 4,000,000 173.38 ms 171.36 ms 1.28% (0.24% to 1.69%)
Win64 4 KiB 750,000 336.83 ms 240.14 ms 40.18% (40.11% to 40.43%)
Win32 4 KiB 750,000 358.24 ms 312.89 ms 14.45% (14.34% to 14.66%)
Win64 64 KiB 50,000 310.49 ms 217.46 ms 42.91% (42.68% to 43.23%)
Win32 64 KiB 50,000 331.14 ms 284.16 ms 16.34% (14.86% to 17.69%)

Intel Core i7-8750H:

Target User size Operations Baseline median Candidate median Throughput gain (95% CI)
Win64 64 B 2,100,000 203.97 ms 192.86 ms 5.15% (3.94% to 7.62%)
Win32 64 B 2,000,000 188.55 ms 179.00 ms 4.18% (3.00% to 5.04%)
Win64 4 KiB 268,000 311.63 ms 224.39 ms 38.31% (36.36% to 39.89%)
Win32 4 KiB 286,000 364.46 ms 353.56 ms 3.30% (2.68% to 3.45%)
Win64 64 KiB 17,000 291.12 ms 203.33 ms 43.69% (42.19% to 44.60%)
Win32 64 KiB 18,000 340.18 ms 325.99 ms 4.29% (3.85% to 4.82%)

The 4 KiB and 64 KiB gains reproduced on AMD Win32 and Win64 and on Intel Win64, but Intel Win32 improved by only 3.30% to 4.29%, so the result depends strongly on architecture and CPU. Additional 25-pair tests cover 15, 39, 40, and 41 bytes. The 39-byte case exercises the new failed 32-byte loop guard before the existing 8-byte path; the 40/41-byte cases enter the new loop.

The worst AMD result was -2.12% at 39 bytes on Win32, with all Win64 controls positive. The worst Intel result was -1.58% at 15 bytes on Win32 (CI -2.93% to -0.33%), again with all Win64 controls positive. Avoiding those boundary losses would require an additional fallback path, which does not seem justified for debug mode.

Tests ran on an AMD Ryzen 9 7950X and an Intel Core i7-8750H under Windows 11 build 26200, using Delphi Win32/Win64 37.0.59082.6021 with release-style -O+ builds. The Intel runs use fewer operations to keep process duration similar; both builds still perform identical work within each pair, and the pairing and analysis are unchanged.

Correctness

FastMMDebugPatternTest.dpr passes for the DCC 37 baseline and candidate on Win32 and Win64 on both CPUs. Additional compatibility runs pass with DCC 35 and 36 Win32/Win64 and with DCC 37 PurePascal. The test verifies every allocated fill byte for sizes 1 through 1025, then corrupts and restores every byte for freed-block sizes 1 through 65 and 257. It accepts only the expected EInvalidPointer and requires a clean scan afterward, covering the object marker and every 32/8/4/2/1-byte validation remainder.

Full benchmark source, raw AMD and Intel samples, summaries, and correctness tests: https://github.com/janrysavy/FastMM5/tree/ed3229e678bbe4b2455b8435168442d51f430996/perf-review

Scope

The change keeps the current comparison strategy and only reduces loop overhead. It adds no SIMD requirement and does not change the public API or diagnostic contract.

@janrysavy
janrysavy marked this pull request as ready for review July 21, 2026 09:44
pleriche pushed a commit that referenced this pull request Jul 22, 2026
…by checking chunks of 32 bytes at a time.
@pleriche

Copy link
Copy Markdown
Owner

Thanks for the suggestion. I've further improved the routine by coaxing the compiler into reducing the number of branches. The code isn't pretty though.

This routine seems like a good candidate for a SIMD assembly implementation. I'll put it on my to-do list.

@janrysavy janrysavy closed this Jul 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants