diff --git a/.gitattributes b/.gitattributes index a5b7932f..7c6c6b1b 100644 --- a/.gitattributes +++ b/.gitattributes @@ -20,3 +20,23 @@ # Preserve the exact issue 615 benchmark verification archive bytes. .github/assets/benchmark-615/verification.zip binary +# Preserve the exact issue 614 attribution archive bytes. +.github/assets/perf-614/attribution.zip binary +.github/assets/perf-614/platform-gates.zip binary +.github/assets/perf-614/v1-measurements.zip binary +.github/assets/perf-614/v2-structural.zip binary +.github/assets/perf-614/v2-original-platform.zip binary +.github/assets/perf-614/v2-test-fix-evidence.zip binary +.github/assets/perf-614/v2-measurements.zip binary +.github/assets/perf-614/v3-structural.zip binary +.github/assets/perf-614/v2-corrected-platform.zip binary +.github/assets/perf-614/v4-structural.zip binary +.github/assets/perf-614/v3-measurements.zip binary +.github/assets/perf-614/v3-platform.zip binary +.github/assets/perf-614/v4-platform.zip binary +.github/assets/perf-614/v4-measurements.zip binary +.github/assets/perf-614/v5-preflight.zip binary +.github/assets/perf-614/v6-structural.zip binary +.github/assets/perf-614/v6-measurements.zip binary +.github/assets/perf-614/v6-platform.zip binary +.github/assets/perf-614/v7-validation-evidence.zip binary diff --git a/.github/assets/perf-614/README.md b/.github/assets/perf-614/README.md new file mode 100644 index 00000000..190a2334 --- /dev/null +++ b/.github/assets/perf-614/README.md @@ -0,0 +1,337 @@ +# Issue 614 attribution evidence + +This archive records local attribution and structural correctness evidence. +It is not a performance acceptance result. The first CPU candidate is rejected for delivery: its three original target +cohorts found no supported CPU/throughput gain. The nine platform workflows +passed; that does not establish a performance benefit. + +## Mechanism and provenance + +Frozen baseline: `227eef06ff03f92966f38508441d6c2f60a75135`. +Candidate source: `287cac2f664a46703ebb6522eef8c8dbeb984cbb`. + +Baseline profiles identified `_mi_page_unpurge_all` entering a substantial +register-save/stack-frame prologue even when neither unformed nor formed +blocks require restoration. The candidate moves the original no-work checks +into a small wrapper, returning immediately for clean pages and tail-calling +the unchanged restoration body when needed. It does not change purge policy, +geometry, retention, or page selection. + +Count-only baseline probes observed: + +| Original workload | Calls | Calls with restoration work | +| --- | ---: | ---: | +| large-class/8 | 1,078,045 | 0 | +| large-class-ephemeral/8 | 1,073,032 | 0 | +| short-generation chart ephemeral/8 | 265,819 | 0 | + +These are observations of the recorded traces, not a claim that dirty pages +never occur. Atomic count probes and diagnostic event builds are unsuitable +for acceptance timing. Sampled profiles use debug/frame-pointer builds on a +Ryzen 7 3700X; restricted kernel symbols and limited sample counts constrain +attribution. Any local replay timing is diagnostic only. + +## Correctness evidence + +`red-instrumented.patch` adds the restoration-entry diagnostic counter to the +original body. The clean-page test fails against that body (`red-test.log`). +The candidate passes the event-counter, purge-hole and large-span C tests +(`green-tests.log`). The test verifies both that the clean page header remains +byte-for-byte unchanged and that the restoration body is not entered. +The original RED executable was overwritten during rebuilding; the patch and +log preserve its reproducible failing condition, not the original binary. + +C++ Debug/full event-counter and large-span tests also passed. The first +C++ test invocation ran the event test but could not run the not-yet-built +large-span binary (`cxx-tests.log`). After building it, the later large-span +run passed (`cxx-large-test.log`). The optional +C++ purge-hole target failed on existing goto-across-initialization errors in +unchanged `test/test-purge-holes.c`; its failing build log is retained. This +archive does not claim the entire C++ suite passed. + +The first local gate failed on missing `sys/sdt.h`. Supplying the existing Nix +libsystemtap include path allowed all 45 checks to pass; both gate logs remain. + +## Archive verification + +`attribution-archive.json` records the ZIP SHA-256. Its internal `manifest.json` +records the byte length and SHA-256 of all 43 other members. Verify both the +outer digest and each member before using the evidence. Files include original +sampled data/reports, baseline and probe executables, event/residency reports, +probe patches, test/build logs and host/compiler provenance. + +Restore executable permissions when replaying archived binaries. The baseline +profile binaries have no build IDs; restore their recorded paths or configure +perf's symbol root explicitly. No acceptance inference follows from archive +integrity alone. + +## Platform gates + +`platform-gates.zip` contains metadata and original logs for all nine successful +platform workflows on candidate `287cac2f664a46703ebb6522eef8c8dbeb984cbb`. +The API tree records in `source-equivalence.json` verify that CI's test merge +`c9eab6aebbc68a4763b6063f1ebbf6060b6fe39e` has the identical source tree. + +- [asan](https://github.com/zackees/mimalloc-pprof/actions/runs/39817378819): success. +- [c-unit](https://github.com/zackees/mimalloc-pprof/actions/runs/39817378654): success. +- [cross](https://github.com/zackees/mimalloc-pprof/actions/runs/39817378542): success. +- [fuzz](https://github.com/zackees/mimalloc-pprof/actions/runs/39817378855): success. +- [macos](https://github.com/zackees/mimalloc-pprof/actions/runs/39817378817): success. +- [purge](https://github.com/zackees/mimalloc-pprof/actions/runs/39817379021): success. +- [python](https://github.com/zackees/mimalloc-pprof/actions/runs/39817378317): success. +- [rust](https://github.com/zackees/mimalloc-pprof/actions/runs/39817378888): success. +- [windows](https://github.com/zackees/mimalloc-pprof/actions/runs/39817378954): success. + +The cancelled runs from the earlier PR-open event are superseded by these +label-triggered runs. Their cancellation-derived failures are not represented +as passing tests. These results establish platform validation of this source; +they do not establish CPU, RSS or latency acceptance. The archive has an outer +SHA-256 in `platform-gates-archive.json` and per-member hashes in its manifest. + +## V1 measurement disposition + +[V1 full original ledger](ledger-v1.md): **10 PASS, 8 INCONCLUSIVE, zero FAIL**. +All three original cohorts reached 120 samples per arm, with zero memory +credit and passing release bounds. No target CPU or throughput interval +establishes a gain, so the predeclared condition for the remaining ten rows +was not met. No unchanged rerun or stage-two expansion was dispatched. +The candidate is rejected for lack of demonstrated benefit; its inconclusive +metrics have not been converted to PASS or invented FAIL verdicts. + +`v1-measurements.zip` preserves all three original sample files, actual +throughput/latency executables and original SHA manifests, workflow metadata +and logs, exact dispatch requests/responses, independently recomputed ledgers, +and exact source snapshots for the baseline and measured candidate. Source +snapshots omit only historical `.github/assets/` evidence; every included +file was verified against its original Git blob ID. The archive also retains +disassembly from the measured binaries and the rebase source-equivalence proof. +`v1-measurements-archive.json` records its outer digest; its internal manifest +records each member's byte length and digest. No cross-host pooling is used. + +## V2: guard the call at retirement publication (acceptance pending) + +Candidate `59d369609ab47358df0f883b6419252f1ffbf03a` replaces the rejected +wrapper with an inline condition at `_mi_page_publish_retired`. Clean pages +skip the call entirely; dirty pages and other callers retain the original +restore function. Optimized assembly confirms the skipped call, but the +caller prologue remains. This is structural evidence, not a CPU gain. + +`v2-structural.zip` retains RED patch/log/executable, GREEN test logs and +executables, source diff, code-generation object/settings/disassembly and +review disposition. Its manifest hashes every other member; the external +JSON hashes the archive. The RED patch applies to `a98a43c1` (the preserved V1 +history), restoring the original restore body and adding the entry-count test. +The assertion fails because clean retirement still invokes restoration. + +With V2, the clean-retirement test passes and same-page reuse works. Real OS +discards exercise formed-only and tail-only conditions independently; the +formed test explicitly restores only its tail before checking the guard. +C Release event/purge-hole/large-span pass 3/3; C++ Debug/full event/large-span +pass 2/2. The final isolation checks also pass separately in C and C++. +The existing C++ purge-hole compile limitation described above remains. +Source review is clean after correcting the test isolation gap. + +The archive retains setup failures and superseded logs transparently: +`v2-red-build.log` is the corrected target build; the initial target name was +invalid. `v2-green-tests.log` was collected while the test binary was being +rebuilt and is superseded by `v2-complete-tests.log` after build completion. +Initial codegen configuration omitted soldr's `cc` argument; fixing it left +an empty Release flag cache. Only the `optimized` codegen logs/disassembly, +object and settings establish the optimized result (`-O3 -DNDEBUG`). The +unoptimized disassembly is not acceptance evidence. The successful Rust +amalgamation command ran from `rust/`; an earlier root invocation could not +find the pinned toolchain. No build failure was treated as a passing test. + +Local gate passed all 45 checks in 55 seconds, stamped the candidate above. +`v2-campaign-plan.json` and `v2-dispatches.json` retain the predeclared plan +and three original target dispatches, announced in issue comment +[6348172962](https://github.com/zackees/mimalloc-pprof/issues/614#issuecomment-6348172962). +Frozen baseline, sample caps, workloads, null/sanity arms and zero-credit +acceptance remain unchanged. V1 results are not pooled with V2. Fresh full +platform checks and complete performance acceptance remain pending. + +The candidate source snapshot in the campaign scratch was verified against +all 855 original Git blobs excluding only historical `.github/assets/` +evidence (`v2-source-manifest.json`). Retain that snapshot with the eventual +measured artifacts; this manifest alone does not ship the source tar. + +## Original V2 platform outcome and test correction + +All eleven original platform/check workflows are terminal: ten succeeded; +ASan failed in the owner-gate Debug lane. The new event-counter test called +`_mi_page_free_collect` without acquiring the owner gate. Its assertion is a +real failure, retained in `v2-original-platform.zip` (25 members, outer digest +in the matching JSON, per-member digests inside). Native MSVC, win-GNU, +both native Macs, Rust, memory/default-path checks and the other ASan lanes +passed. These do not erase the failed owner-gate lane. + +`v2-test-fix-evidence.zip` retains the failing CI logs and local reproduction, +the test-only correction and focused GREEN evidence. The first local build +was named `v2-owner-asan` but sanitizer support was disabled by a missing +header: its RED/GREEN proves the owner-gate assertion, not ASan coverage. +The later `v2-owner-sanitized` build supplied the existing compiler-rt header, +explicitly enabled ASan and linked `__asan_init`; the corrected test passed. +The disabled-gate configuration also passed. Review was clean and independently +reran the sanitized test. Original setup and warning logs remain in the archive. + +The correction acquires the owner gate before internal page accesses and +releases it before heap deletion. Stamped corrected head +`876d7c313026090b0dbeaadb8d0cf2f03f0c9c13` passed 45/45 local checks in 59 seconds +(`v2-test-fix-local-gate.log`). The source-equivalence JSON verifies the only +changes from measured V2 are the test and evidence; allocator, Rust, build +settings and benchmark harness are unchanged. The three original performance +cohorts are retained without duplicate dispatches. Fresh platform validation +of the corrected tests is running; no final platform or performance acceptance +is claimed here. + +## V2 measurement disposition: rejected + +[Original V2 ledger](ledger-v2.md): **11 PASS, 7 INCONCLUSIVE, zero FAIL**. +All three original cohorts completed; large-class stopped at 60 samples per +arm under the unchanged adaptive protocol, both ephemeral rows reached 120. +All release bounds passed. No target CPU/throughput interval establishes a +gain. The predeclared stage-two criterion therefore failed; the remaining ten +rows were not dispatched, and no unchanged candidate was rerun. + +Plain-ephemeral p99 has a positive interval (+0.4727% to +1.5848%) and remains +INCONCLUSIVE against its noise allowance. Its after-drain RSS interval +(-0.7276% to +10.9645%) also remains INCONCLUSIVE and is not accepted. No +uncertainty is waived, no memory credit claimed and no hosts pooled. V2 is +rejected for lack of demonstrated benefit; numeric verdicts are retained. + +`v2-measurements.zip` retains original raw samples, actual measured binaries +and SHA manifests, workflow metadata/logs, exact dispatch requests/responses, +independent per-cell ledgers, the predeclared campaign and disposition, +verifiers, and exact baseline/candidate source snapshots. Historical evidence +alone is excluded from source snapshots. `v2-source-manifest.json` records +verification of all candidate source files against Git blobs; the baseline +snapshot's verification is retained from V1. Check the external digest and +all internal manifest members before using the archive. + +The test-only owner-gate correction changes no measured allocator or harness +code; source equivalence is retained. Fresh corrected platform CI remains +separate and cannot establish a performance benefit. Do not merge the rejected +restore-guard mechanism on the strength of correctness checks alone. + +## V3 rejected: skip zero-state reuse accounting + +The first completed original cohort (run39840357033, plain ephemeral) +confirmed a throughput regression of -0.8333% (95% CI -1.0046% to -0.5076%) +beyond its 0.3310% noise allowance. V3 is rejected and removed. All three +original cohorts are now complete; no stage two or unchanged rerun was +dispatched. [Initial rejection ledger](https://github.com/zackees/mimalloc-pprof/issues/614#issuecomment-6349925978). + +V1 and V2 production changes have been removed. The new candidate skips the +full span/accounting call after successful retired-page selection when its +demand-state byte is zero. The result was discarded, the state remains zero +under every runtime cap/enable value, and no grow/shrink event is emitted. +Nonzero states retain the original call. Selection, geometry, aging, +retention and purge policies are unchanged. + +`v3-structural.zip` preserves three count-only baseline probe variants and +their original executables, patches, commands and logs. The narrowest probe +observed 426,264 / 392,636 / 95,960 repeated zero-state accounting calls in +the three target replays. These instrumented counts prove occurrence, not +performance benefit; their timings are not acceptance evidence. + +The archive also contains focused RED and GREEN executables/logs, exhaustive +state/bin/runtime-option equivalence tests, C++ and actual ASan owner-gate +results, optimized codegen, and review disposition. Reproducing either source +patch requires its separately archived new header. See the internal notes +and external archive digest. Performance acceptance remains pending. + +## Corrected V2 platform evidence + +`v2-corrected-platform.zip` preserves corrected source `876d7c31` validation: +ten workflows completed successfully, including C/native MSVC, Windows GNU, +native Mac arches, Rust, and ASan owner-gate. The fuzz workflow still reported +`in_progress` at collection despite all three jobs completing successfully. +The complete job list and individual job logs are retained; this is unresolved +workflow finalization, not a claimed successful workflow. No rerun or manual +cancellation was requested. The original ASan test failure remains separately +preserved. These correctness results do not change V2's performance rejection. + +A subsequent fresh REST observation confirms that corrected V2 fuzz run +`39835530789` completed successfully, with all three jobs successful. +`v2-corrected-fuzz-finalization.json` retains that run and complete job record. +The earlier pending-status snapshot stays unchanged. All eleven corrected +V2 platform workflows therefore completed successfully; V2 remains rejected +for lack of demonstrated performance benefit. + +## V4 candidate: accounting without an unused size result + +After removing rejected V3, V4 calls the original demand-transition helper +through a dedicated internal API with the known bin index. Every state uses +the original transition and runtime option checks. Optimized assembly removes +the repeated bin classification and unused size-result calculation. This +uses the repeated-call attribution preserved in `v3-structural.zip`. + +`v4-structural.zip` preserves focused RED/GREEN executables, patches with +separate new headers, exhaustive state/bin/runtime-option equivalence tests, +C/C++/actual ASan results, optimized code and review. Its internal notes +explain reproduction and limitations. V4 is rejected for lack of a supported CPU/throughput gain; +V3's confirmed throughput regression is not waived by this new candidate. + +## Complete V3 disposition + +[Original full ledger](ledger-v3.md): **6 PASS, 10 INCONCLUSIVE, 2 FAIL**. +Large-class CPU also regressed beyond noise (+0.6433%, CI +0.4006% to ++0.8918%, allowance 0.3584%). Short-chart throughput improved (+0.3585%, +CI +0.0259% to +0.7054%); that cannot offset either confirmed regression. +All release bounds held. Zero memory credit, no cross-host pooling, no +threshold relaxation, no unchanged rerun and no stage-two expansion. + +`v3-measurements.zip` preserves original raw samples, exact binaries, hashes, +workflow records/logs, dispatch requests/responses, plans, verifiers, ledger, +and exact baseline/candidate source snapshots. `v3-platform.zip` preserves +all eleven successful platform workflows and exact candidate/test-merge tree +equivalence. Every archive has an internal member manifest and external +digest. Platform success does not change V3's rejection. + +## V4 platform validation complete + +`v4-platform.zip` preserves all eleven successful workflows for exact +candidate `8fda62c6`, including native MSVC, Windows GNU, native Mac x64 and +ARM64, Rust, sanitizers, memory and default-path gates. Every job is completed +with success or an expected skipped configuration. The candidate and PR test +merge have identical trees; the source-equivalence record is included. + +All three original cohorts completed: **14 PASS, 4 INCONCLUSIVE, zero FAIL**. +None demonstrates a statistically supported CPU/throughput gain, so V4 is +rejected under the declared stage-one screen. No stage-two expansion or +unchanged rerun is authorized by these results. All release bounds held; +zero memory credit. The plain ephemeral p99 improvement does not satisfy +the required CPU/throughput gain. + +[Full original ledger](ledger-v4.md). `v4-measurements.zip` preserves raw +samples, exact binaries, workflow records/logs, dispatch requests/responses, +plans, verification scripts, and exact baseline/candidate source snapshots. +The internal manifest and external digest cover every archived member. + +## V5 rejected during safety review + +Moving publication after retired-bin bounds updates reduced register saves +and enabled a tail call in local optimized code. However, an OS-reuse failure +can invoke an output callback that reenters collection. Earlier bounds could +make the page collectible while publication still uses it. This static safety +finding was not reproduced as a crash; it is sufficient to reject the candidate. + +C, C++ and ASan tests passed but did not cover that failure callback. The +candidate was removed before any performance dispatch. Production source +again matches the fixed baseline. `v5-preflight.zip` preserves the diagnostic +profiles, commands, source patch, RED/GREEN codegen checks, test executables, +logs, review and disposition. No CPU gain or platform validation is claimed. + +## V6: omit the overwritten final free-list link + +The baseline initializer writes every new block's next pointer, then +overwrites the last pointer with the old free-list head. V6 stops the loop +before the last block, whose required final link is still written once. +The optimized baseline retains the redundant iteration/store; the shared +initializer test is RED at two writes for a singleton, GREEN at one. + +`v6-structural.zip` preserves RED/GREEN evidence, exact objects/executables, +source patch, test configurations, commands and clean review. C tests passed +4/4, secure C++ 3/3, and ASan with owner gate 3/3. No publication reordering +or allocator policy change is included. Performance acceptance and full +platform validation remain pending; no CPU gain is claimed. diff --git a/.github/assets/perf-614/attribution-archive.json b/.github/assets/perf-614/attribution-archive.json new file mode 100644 index 00000000..2a7e368a --- /dev/null +++ b/.github/assets/perf-614/attribution-archive.json @@ -0,0 +1,6 @@ +{ + "file": "attribution.zip", + "sha256": "91ffc47dfe119a5d8bb78c4aefa511685f855f06f41955c54d8f88d8163690cd", + "files": 43, + "purpose": "local attribution and structural evidence, no timing acceptance" +} diff --git a/.github/assets/perf-614/attribution.zip b/.github/assets/perf-614/attribution.zip new file mode 100644 index 00000000..8430ab24 Binary files /dev/null and b/.github/assets/perf-614/attribution.zip differ diff --git a/.github/assets/perf-614/ledger-v1.md b/.github/assets/perf-614/ledger-v1.md new file mode 100644 index 00000000..27a7e23d --- /dev/null +++ b/.github/assets/perf-614/ledger-v1.md @@ -0,0 +1,44 @@ +## Stage-one result: candidate not accepted + +Exact baseline `227eef06ff03f92966f38508441d6c2f60a75135`, candidate `287cac2f664a46703ebb6522eef8c8dbeb984cbb`. All three original cohorts completed with 120 actual samples per arm (base/head/null), unchanged traces and sanity gates. Original executables/hash manifests, raw samples, workflow logs and independently recomputed ledgers are retained. No hosts are pooled. + +**No statistically supported target CPU or throughput gain.** Across 18 metrics: 10 PASS, 8 INCONCLUSIVE, 0 FAIL; zero memory credit in every row, all release bounds held. The stage-two condition is not met. I will not expand this candidate to the remaining rows or rerun it unchanged. It is rejected for delivery despite successful correctness/platform gates. + +The measured chart binaries confirm the intended prologue removal, but structural work reduction is not a measured benefit. CPU changes in both ephemeral targets lean worse, and the plain-ephemeral RSS interval is unresolved; neither is silently relabelled as equivalence. Further implementation requires fresh attribution within the original CPU-only scope, not weaker thresholds. + +### large-class/8 + +Original run: https://github.com/zackees/mimalloc-pprof/actions/runs/39823333694 + +base `227eef06ff03` head `287cac2f664a` on AMD EPYC 7763 64-Core Processor, 60 reps (up to 120); 4 logical CPUs, 8-worker cells have 2.00 workers per logical CPU (above 1 means oversubscription); arm order: rotating-reversed-blocks-v1 + +Rule-12 ledger (CLAUDE.md; ci/perf_ab_ledger.py): `saved%` of the reducible peak-RSS gap, then per metric the paired change [95% sign-test interval] against its allowance (saved%/3 for CPU, throughput and faults; noise for memory and for cells that saved none). INCONCLUSIVE is not a pass. + +| workload | saved% | verdict | ops/s | cpu s | minor faults | p99 operation ns | peak RSS MiB | RSS 0.5 s after drain MiB | +|---|---|---|---|---|---|---|---|---| +| large-class/8 | 0% | **INCONCLUSIVE** | +0.1% [-0.6, +0.6] / 0.7% **PASS** | -0.0% [-0.4, +0.3] / 0.3% **INCONCLUSIVE** | -0.6% [-2.0, +1.4] / 2.2% **PASS** | +0.1% [-1.0, +0.6] / 1.1% **PASS** | -0.0% [-0.2, +0.0] / 0.1% **PASS** | -0.4% [-1.8, +0.1] / 1.8% **PASS** | + +### large-class-ephemeral/8 + +Original run: https://github.com/zackees/mimalloc-pprof/actions/runs/39823337377 + +base `227eef06ff03` head `287cac2f664a` on AMD EPYC 7763 64-Core Processor, 60 reps (up to 120); 4 logical CPUs, 8-worker cells have 2.00 workers per logical CPU (above 1 means oversubscription); arm order: rotating-reversed-blocks-v1 + +Rule-12 ledger (CLAUDE.md; ci/perf_ab_ledger.py): `saved%` of the reducible peak-RSS gap, then per metric the paired change [95% sign-test interval] against its allowance (saved%/3 for CPU, throughput and faults; noise for memory and for cells that saved none). INCONCLUSIVE is not a pass. + +| workload | saved% | verdict | ops/s | cpu s | minor faults | p99 operation ns | peak RSS MiB | RSS 0.5 s after drain MiB | +|---|---|---|---|---|---|---|---|---| +| large-class-ephemeral/8 | 0% | **INCONCLUSIVE** | -0.4% [-0.7, -0.1] / 0.5% **INCONCLUSIVE** | +0.3% [+0.2, +0.4] / 0.3% **INCONCLUSIVE** | +0.0% [+0.0, +0.8] / 0.8% **INCONCLUSIVE** | -0.0% [-1.0, +0.6] / 1.0% **PASS** | +0.0% [-0.0, +2.6] / 0.1% **INCONCLUSIVE** | +0.0% [-9.4, +0.8] / 9.8% **PASS** | + +### large-class-ephemeral/8 short generations (chart build) + +Original run: https://github.com/zackees/mimalloc-pprof/actions/runs/39823341873 + +base `227eef06ff03` head `287cac2f664a` on AMD EPYC 9V74 80-Core Processor, 60 reps (up to 120); 4 logical CPUs, 8-worker cells have 2.00 workers per logical CPU (above 1 means oversubscription); arm order: rotating-reversed-blocks-v1 + +Rule-12 ledger (CLAUDE.md; ci/perf_ab_ledger.py): `saved%` of the reducible peak-RSS gap, then per metric the paired change [95% sign-test interval] against its allowance (saved%/3 for CPU, throughput and faults; noise for memory and for cells that saved none). INCONCLUSIVE is not a pass. + +| workload | saved% | verdict | ops/s | cpu s | minor faults | p99 operation ns | peak RSS MiB | RSS 0.5 s after drain MiB | +|---|---|---|---|---|---|---|---|---| +| large-class-ephemeral/8 short generations (chart build) | 0% | **INCONCLUSIVE** | -0.3% [-0.9, +0.4] / 0.8% **INCONCLUSIVE** | +0.4% [+0.1, +0.9] / 0.4% **INCONCLUSIVE** | -0.4% [-0.8, +0.0] / 0.7% **PASS** | +1.4% [-0.7, +2.1] / 1.4% **INCONCLUSIVE** | +0.0% [-0.0, +0.0] / 2.6% **PASS** | +0.0% [-0.0, +0.0] / 2.6% **PASS** | + diff --git a/.github/assets/perf-614/ledger-v2.md b/.github/assets/perf-614/ledger-v2.md new file mode 100644 index 00000000..5fb0fe73 --- /dev/null +++ b/.github/assets/perf-614/ledger-v2.md @@ -0,0 +1,52 @@ +# V2 original stage-one ledger + +Baseline `227eef06ff03f92966f38508441d6c2f60a75135`; candidate `59d369609ab47358df0f883b6419252f1ffbf03a`. + +STOP: no statistically supported target CPU/throughput gain + +Original per-host paired cohorts only; zero memory credit. Intervals and verdicts are retained. + +## large-class/8 + +Run 39831495052; Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz; samples per arm: {'base': 60, 'head': 60, 'null': 60}. + +| Metric | Change % [95% CI] | Allowance % | Verdict | +| --- | --- | --- | --- | +| ops/s | +0.5714 [-1.3148, +1.2130] | 1.4155 | PASS | +| cpu s | -0.4897 [-1.0908, +0.5073] | 0.8227 | PASS | +| minor faults | -1.4996 [-3.8674, +0.4237] | 2.0921 | PASS | +| p99 operation ns | +0.9573 [-0.6498, +1.7575] | 2.1407 | PASS | +| peak RSS MiB | +0.0559 [-0.0766, +2.5338] | 2.5809 | PASS | +| RSS 0.5 s after drain MiB | -0.1192 [-2.1851, +1.9511] | 3.7011 | PASS | + +Release p95: 1100.0 ms; bound: 1300 ms; held: True. + +## large-class-ephemeral/8 + +Run 39831499063; AMD EPYC 7763 64-Core Processor; samples per arm: {'base': 120, 'head': 120, 'null': 120}. + +| Metric | Change % [95% CI] | Allowance % | Verdict | +| --- | --- | --- | --- | +| ops/s | +0.3751 [-0.0942, +0.5970] | 0.4314 | PASS | +| cpu s | -0.0879 [-0.1899, +0.0749] | 0.1690 | PASS | +| minor faults | +0.0000 [-0.7722, +0.3906] | 0.7812 | PASS | +| p99 operation ns | +0.8061 [+0.4727, +1.5848] | 0.5456 | INCONCLUSIVE | +| peak RSS MiB | +0.0000 [-0.0733, +0.1626] | 2.5703 | PASS | +| RSS 0.5 s after drain MiB | +0.0227 [-0.7276, +10.9645] | 0.7329 | INCONCLUSIVE | + +Release p95: 1050.0 ms; bound: 1300 ms; held: True. + +## large-class-ephemeral/8 short generations (chart build) + +Run 39831504283; AMD EPYC 7763 64-Core Processor; samples per arm: {'base': 120, 'head': 120, 'null': 120}. + +| Metric | Change % [95% CI] | Allowance % | Verdict | +| --- | --- | --- | --- | +| ops/s | -0.4759 [-1.2258, +0.3828] | 0.7212 | INCONCLUSIVE | +| cpu s | +0.2379 [-0.0983, +0.5851] | 0.3687 | INCONCLUSIVE | +| minor faults | +0.1873 [-0.3861, +0.7722] | 0.7692 | INCONCLUSIVE | +| p99 operation ns | +0.5108 [-0.0539, +1.1457] | 1.0678 | INCONCLUSIVE | +| peak RSS MiB | +0.0000 [-0.0314, +0.0054] | 0.0430 | PASS | +| RSS 0.5 s after drain MiB | +0.0000 [-0.0314, +0.0052] | 0.0052 | INCONCLUSIVE | + +Release p95: 1010.0 ms; bound: 1300 ms; held: True. diff --git a/.github/assets/perf-614/ledger-v3.md b/.github/assets/perf-614/ledger-v3.md new file mode 100644 index 00000000..bc395fe7 --- /dev/null +++ b/.github/assets/perf-614/ledger-v3.md @@ -0,0 +1,53 @@ +# V3 original stage-one ledger + +Baseline `227eef06ff03f92966f38508441d6c2f60a75135`; candidate `5b2d8f960297fda825b05b7471893fc4cf6c2f33`. + +REJECT V3: two confirmed per-cell regressions; no stage two or unchanged rerun + +Original per-host paired cohorts only; zero memory credit. Intervals and verdicts are retained. + +## large-class/8 + +Run 39840352295; AMD EPYC 9V74 80-Core Processor; samples per arm: {'base': 110, 'head': 110, 'null': 110}. + +| Metric | Change % [95% CI] | Allowance % | Verdict | +| --- | --- | --- | --- | +| ops/s | -0.4470 [-1.0644, -0.0539] | 0.9693 | INCONCLUSIVE | +| cpu s | +0.6433 [+0.4006, +0.8918] | 0.3584 | FAIL | +| minor faults | -0.4376 [-1.7021, +1.3158] | 1.7621 | PASS | +| p99 operation ns | +1.8763 [+0.7396, +2.9586] | 1.5129 | INCONCLUSIVE | +| peak RSS MiB | +0.0000 [-0.0052, +0.0051] | 0.0052 | PASS | +| RSS 0.5 s after drain MiB | +0.0000 [-0.0052, +0.0051] | 0.0052 | PASS | + +Release p95: 1120.0 ms; bound: 1300 ms; held: True. + +## large-class-ephemeral/8 + +Run 39840357033; AMD EPYC 7763 64-Core Processor; samples per arm: {'base': 75, 'head': 75, 'null': 75}. + +| Metric | Change % [95% CI] | Allowance % | Verdict | +| --- | --- | --- | --- | +| ops/s | -0.8333 [-1.0046, -0.5076] | 0.3310 | FAIL | +| cpu s | +0.3109 [+0.0964, +0.4994] | 0.1852 | INCONCLUSIVE | +| minor faults | +0.0000 [-0.3906, +0.7968] | 1.5444 | PASS | +| p99 operation ns | +0.6169 [-0.0564, +1.6256] | 1.0839 | INCONCLUSIVE | +| peak RSS MiB | +0.1045 [+0.0052, +2.6618] | 2.6071 | INCONCLUSIVE | +| RSS 0.5 s after drain MiB | +10.9141 [+0.0000, +14.1152] | 13.1240 | INCONCLUSIVE | + +Release p95: 1050.0 ms; bound: 1300 ms; held: True. + +## large-class-ephemeral/8 short generations (chart build) + +Run 39840362233; AMD EPYC 9V74 80-Core Processor; samples per arm: {'base': 120, 'head': 120, 'null': 120}. + +| Metric | Change % [95% CI] | Allowance % | Verdict | +| --- | --- | --- | --- | +| ops/s | +0.3585 [+0.0259, +0.7054] | 1.1761 | PASS | +| cpu s | +0.1323 [-0.0657, +0.4696] | 0.4251 | INCONCLUSIVE | +| minor faults | +0.0000 [-0.3831, +0.7547] | 0.7634 | PASS | +| p99 operation ns | +1.0573 [-0.6935, +2.0647] | 0.7289 | INCONCLUSIVE | +| peak RSS MiB | +0.0052 [-0.0052, +2.6757] | 2.5398 | INCONCLUSIVE | +| RSS 0.5 s after drain MiB | +0.0052 [-0.0052, +2.6705] | 2.5398 | INCONCLUSIVE | + +Release p95: 1030.0 ms; bound: 1300 ms; held: True. + diff --git a/.github/assets/perf-614/ledger-v4.md b/.github/assets/perf-614/ledger-v4.md new file mode 100644 index 00000000..956f9f36 --- /dev/null +++ b/.github/assets/perf-614/ledger-v4.md @@ -0,0 +1,53 @@ +# V4 original stage-one ledger + +Baseline `227eef06ff03f92966f38508441d6c2f60a75135`; candidate `8fda62c6d05a68ea4c0ffe2859f07eabf5e72d97`. + +STOP: no statistically supported target CPU/throughput gain + +Original per-host paired cohorts only; zero memory credit. Intervals and verdicts are retained. + +## large-class/8 + +Run 39845980415; AMD EPYC 7763 64-Core Processor; samples per arm: {'base': 120, 'head': 120, 'null': 120}. + +| Metric | Change % [95% CI] | Allowance % | Verdict | +| --- | --- | --- | --- | +| ops/s | +0.1033 [-0.5035, +0.5822] | 0.8696 | PASS | +| cpu s | -0.1548 [-0.3298, +0.0418] | 0.3071 | PASS | +| minor faults | -1.0087 [-3.5398, +0.4444] | 3.0435 | PASS | +| p99 operation ns | -0.0280 [-1.1577, +1.1211] | 1.1280 | PASS | +| peak RSS MiB | -0.0570 [-2.5930, +0.0158] | 0.1688 | PASS | +| RSS 0.5 s after drain MiB | +0.1305 [-1.4765, +1.6039] | 1.2146 | INCONCLUSIVE | + +Release p95: 1040.0 ms; bound: 1300 ms; held: True. + +## large-class-ephemeral/8 + +Run 39845983742; AMD EPYC 7763 64-Core Processor; samples per arm: {'base': 120, 'head': 120, 'null': 120}. + +| Metric | Change % [95% CI] | Allowance % | Verdict | +| --- | --- | --- | --- | +| ops/s | -0.3513 [-0.5710, +0.0413] | 0.3058 | INCONCLUSIVE | +| cpu s | +0.3114 [+0.1776, +0.4774] | 0.2455 | INCONCLUSIVE | +| minor faults | -0.1901 [-0.7663, +0.3891] | 0.7782 | PASS | +| p99 operation ns | -1.8827 [-2.6022, -1.1088] | 1.0971 | PASS | +| peak RSS MiB | +0.0052 [-0.0472, +0.1258] | 0.0629 | INCONCLUSIVE | +| RSS 0.5 s after drain MiB | +0.0000 [-0.0455, +0.7329] | 10.8636 | PASS | + +Release p95: 1050.0 ms; bound: 1300 ms; held: True. + +## large-class-ephemeral/8 short generations (chart build) + +Run 39845987944; AMD EPYC 9V45 96-Core Processor; samples per arm: {'base': 95, 'head': 95, 'null': 95}. + +| Metric | Change % [95% CI] | Allowance % | Verdict | +| --- | --- | --- | --- | +| ops/s | -0.2938 [-0.8665, +0.5941] | 0.9289 | PASS | +| cpu s | +0.2126 [-0.2354, +0.7039] | 0.7425 | PASS | +| minor faults | -0.3774 [-0.7782, +0.3831] | 1.1236 | PASS | +| p99 operation ns | +0.0000 [-0.5043, +0.4993] | 1.0188 | PASS | +| peak RSS MiB | -0.0052 [-2.7441, +0.0054] | 2.6757 | PASS | +| RSS 0.5 s after drain MiB | -0.0052 [-2.7441, +0.0054] | 2.6757 | PASS | + +Release p95: 1090.0 ms; bound: 1300 ms; held: True. + diff --git a/.github/assets/perf-614/ledger-v6.md b/.github/assets/perf-614/ledger-v6.md new file mode 100644 index 00000000..c756de02 --- /dev/null +++ b/.github/assets/perf-614/ledger-v6.md @@ -0,0 +1,53 @@ +# V6 original stage-one ledger + +Baseline `227eef06ff03f92966f38508441d6c2f60a75135`; candidate `a40d8d6e717df31859103a034bf349d32e7760fc`. + +Rejected: no statistically supported target CPU/throughput gain. 14 PASS, 4 INCONCLUSIVE, zero FAIL. No stage two or unchanged rerun. + +Original per-host paired cohorts only; zero memory credit. All ten platform workflows passed. Platform success does not establish performance acceptance. + +## large-class/8 + +Run 39855326807; AMD EPYC 7763 64-Core Processor; samples per arm: {'base': 80, 'head': 80, 'null': 80}. + +| Metric | Change % [95% CI] | Allowance % | Verdict | +| --- | --- | --- | --- | +| ops/s | +0.8402 [-0.0645, +1.4413] | 0.6799 | PASS | +| cpu s | +0.0272 [-0.2649, +0.3017] | 0.4542 | PASS | +| minor faults | -0.4357 [-2.6087, +2.2026] | 2.6432 | PASS | +| p99 operation ns | -0.5771 [-1.1513, +0.5482] | 1.6103 | PASS | +| peak RSS MiB | +0.0131 [-0.0578, +0.0684] | 0.0893 | PASS | +| RSS 0.5 s after drain MiB | -0.1289 [-1.9111, +1.5691] | 2.0848 | PASS | + +Release p95: 1040.0 ms; bound: 1300 ms; held: True. + +## large-class-ephemeral/8 + +Run 39855330463; AMD EPYC 7763 64-Core Processor; samples per arm: {'base': 120, 'head': 120, 'null': 120}. + +| Metric | Change % [95% CI] | Allowance % | Verdict | +| --- | --- | --- | --- | +| ops/s | -0.1958 [-0.4755, +0.1010] | 0.6521 | PASS | +| cpu s | +0.1477 [+0.0069, +0.3486] | 0.2342 | INCONCLUSIVE | +| minor faults | +0.3929 [-0.3802, +0.7905] | 0.3968 | INCONCLUSIVE | +| p99 operation ns | +0.5028 [+0.0000, +1.0616] | 1.0037 | INCONCLUSIVE | +| peak RSS MiB | +0.0230 [-0.0210, +0.0839] | 0.1020 | PASS | +| RSS 0.5 s after drain MiB | +0.0000 [-0.7731, +10.9190] | 0.8235 | INCONCLUSIVE | + +Release p95: 1050.0 ms; bound: 1300 ms; held: True. + +## large-class-ephemeral/8 short generations (chart build) short generations (chart build) + +Run 39855334782; AMD EPYC 7763 64-Core Processor; samples per arm: {'base': 110, 'head': 110, 'null': 110}. + +| Metric | Change % [95% CI] | Allowance % | Verdict | +| --- | --- | --- | --- | +| ops/s | -0.1823 [-0.5360, +0.2481] | 0.5711 | PASS | +| cpu s | +0.1091 [-0.1198, +0.2890] | 0.2946 | PASS | +| minor faults | +0.0000 [-0.3861, +0.7605] | 1.1407 | PASS | +| p99 operation ns | -0.0517 [-0.9932, +0.5873] | 1.0965 | PASS | +| peak RSS MiB | -2.5124 [-2.6753, +0.0000] | 2.5489 | PASS | +| RSS 0.5 s after drain MiB | -2.5124 [-2.6753, +0.0000] | 2.5489 | PASS | + +Release p95: 1010.0 ms; bound: 1300 ms; held: True. + diff --git a/.github/assets/perf-614/platform-gates-archive.json b/.github/assets/perf-614/platform-gates-archive.json new file mode 100644 index 00000000..ca6111aa --- /dev/null +++ b/.github/assets/perf-614/platform-gates-archive.json @@ -0,0 +1,8 @@ +{ + "file": "platform-gates.zip", + "sha256": "a07e1ba71344bd5a9e93337e180ab6a4fdd58becbb47c6107a306449c942408a", + "files": 20, + "candidate": "287cac2f664a46703ebb6522eef8c8dbeb984cbb", + "test_merge": "c9eab6aebbc68a4763b6063f1ebbf6060b6fe39e", + "source_tree": "a910b85e21192b946f9d7acda1096c60d437c582" +} diff --git a/.github/assets/perf-614/platform-gates.zip b/.github/assets/perf-614/platform-gates.zip new file mode 100644 index 00000000..78051264 Binary files /dev/null and b/.github/assets/perf-614/platform-gates.zip differ diff --git a/.github/assets/perf-614/v1-measurements-archive.json b/.github/assets/perf-614/v1-measurements-archive.json new file mode 100644 index 00000000..d4fda160 --- /dev/null +++ b/.github/assets/perf-614/v1-measurements-archive.json @@ -0,0 +1,15 @@ +{ + "file": "v1-measurements.zip", + "sha256": "e6420a419201fb609dd6d17d90d53c95b4d55f751ed985bd14fa70d3b10b9b5d", + "bytes": 10185953, + "files": 52, + "baseline": "227eef06ff03f92966f38508441d6c2f60a75135", + "candidate": "287cac2f664a46703ebb6522eef8c8dbeb984cbb", + "disposition": "rejected: no supported target CPU/throughput gain", + "stage_two_dispatched": false, + "metric_verdicts": { + "PASS": 10, + "INCONCLUSIVE": 8, + "FAIL": 0 + } +} diff --git a/.github/assets/perf-614/v1-measurements.zip b/.github/assets/perf-614/v1-measurements.zip new file mode 100644 index 00000000..03f09c9d Binary files /dev/null and b/.github/assets/perf-614/v1-measurements.zip differ diff --git a/.github/assets/perf-614/v2-campaign-plan.json b/.github/assets/perf-614/v2-campaign-plan.json new file mode 100644 index 00000000..f618f1fd --- /dev/null +++ b/.github/assets/perf-614/v2-campaign-plan.json @@ -0,0 +1,18 @@ +{ + "baseline": "227eef06ff03f92966f38508441d6c2f60a75135", + "candidate": "59d369609ab47358df0f883b6419252f1ffbf03a", + "status": "V2 predeclared; not dispatched", + "initial_samples_per_arm": 60, + "adaptive_cap_per_arm": 120, + "null_arm": true, + "sanity_gate": true, + "stage_one": [ + "large-class/8", + "large-class-ephemeral/8", + "large-class-ephemeral/8 short generations (chart build)" + ], + "stage_two": "all remaining rows from the 12 default perf-ab workloads plus sparse-large-buffers 64-slot budget/8 (#422)", + "rules": "No unchanged reruns; one original cohort per candidate/cell; all six metrics; zero memory credit; no cross-host pooling; reject confirmed per-cell FAIL or service-bound violation. Stage two only if stage one has no FAIL/incomplete/sanity failures and supported target CPU or throughput gain. INCONCLUSIVE retains its label. No new numerical risk waiver: automatic acceptance only under existing rule12 with supported target gain and passing CPU/throughput controls; unresolved material risk needs attribution or owner disposition.", + "mechanism": "Skip the restore-function call at retirement publication when both discard records are empty. Original restore function retained for dirty retirement and all other callers.", + "previous_candidate_disposition": "V1 rejected: no supported target CPU/throughput gain; original cohorts retained, no stage two or unchanged rerun." +} diff --git a/.github/assets/perf-614/v2-corrected-fuzz-finalization.json b/.github/assets/perf-614/v2-corrected-fuzz-finalization.json new file mode 100644 index 00000000..04e28754 --- /dev/null +++ b/.github/assets/perf-614/v2-corrected-fuzz-finalization.json @@ -0,0 +1,495 @@ +{ + "note": "Fresh REST observation confirms successful finalization. Earlier archived pending workflow status remains preserved as observation history; no rerun or manual cancellation was requested.", + "run": { + "id": 39835530789, + "name": "fuzz", + "node_id": "WFR_kwLOTg_oos8AAAAJRmH2JQ", + "head_branch": "perf/614-large-reuse-cpu", + "head_sha": "876d7c313026090b0dbeaadb8d0cf2f03f0c9c13", + "path": ".github/workflows/fuzz.yml", + "display_title": "perf: bypass unpurge restoration for clean pages (#614)", + "run_number": 992, + "event": "pull_request", + "status": "completed", + "conclusion": "success", + "workflow_id": 324911951, + "check_suite_id": 107968595701, + "check_suite_node_id": "CS_kwDOTg_oos8AAAAZI24G9Q", + "url": "https://api.github.com/repos/zackees/mimalloc-pprof/actions/runs/39835530789", + "html_url": "https://github.com/zackees/mimalloc-pprof/actions/runs/39835530789", + "pull_requests": [ + { + "url": "https://api.github.com/repos/zackees/mimalloc-pprof/pulls/616", + "id": 4970966907, + "number": 616, + "head": { + "ref": "perf/614-large-reuse-cpu", + "sha": "5b2d8f960297fda825b05b7471893fc4cf6c2f33", + "repo": { + "id": 1309665442, + "url": "https://api.github.com/repos/zackees/mimalloc-pprof", + "name": "mimalloc-pprof" + } + }, + "base": { + "ref": "main", + "sha": "5a5e97e16cf872bb5d66220bbb8827db3e1822dc", + "repo": { + "id": 1309665442, + "url": "https://api.github.com/repos/zackees/mimalloc-pprof", + "name": "mimalloc-pprof" + } + } + } + ], + "created_at": "2026-10-22T18:54:56Z", + "updated_at": "2026-10-22T19:39:09Z", + "actor": { + "login": "zackees", + "id": 6856673, + "node_id": "MDQ6VXNlcjY4NTY2NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/6856673?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/zackees", + "html_url": "https://github.com/zackees", + "followers_url": "https://api.github.com/users/zackees/followers", + "following_url": "https://api.github.com/users/zackees/following{/other_user}", + "gists_url": "https://api.github.com/users/zackees/gists{/gist_id}", + "starred_url": "https://api.github.com/users/zackees/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/zackees/subscriptions", + "organizations_url": "https://api.github.com/users/zackees/orgs", + "repos_url": "https://api.github.com/users/zackees/repos", + "events_url": "https://api.github.com/users/zackees/events{/privacy}", + "received_events_url": "https://api.github.com/users/zackees/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "run_attempt": 1, + "referenced_workflows": [ + { + "path": "zackees/mimalloc-pprof/.github/workflows/pr-ci-mode.yml@70b59985ddc42892bb156b99c90d129325749efa", + "sha": "70b59985ddc42892bb156b99c90d129325749efa", + "ref": "refs/pull/616/merge" + }, + { + "path": "zackees/mimalloc-pprof/.github/workflows/pr-ci-gate.yml@70b59985ddc42892bb156b99c90d129325749efa", + "sha": "70b59985ddc42892bb156b99c90d129325749efa", + "ref": "refs/pull/616/merge" + } + ], + "run_started_at": "2026-10-22T18:54:56Z", + "triggering_actor": { + "login": "zackees", + "id": 6856673, + "node_id": "MDQ6VXNlcjY4NTY2NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/6856673?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/zackees", + "html_url": "https://github.com/zackees", + "followers_url": "https://api.github.com/users/zackees/followers", + "following_url": "https://api.github.com/users/zackees/following{/other_user}", + "gists_url": "https://api.github.com/users/zackees/gists{/gist_id}", + "starred_url": "https://api.github.com/users/zackees/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/zackees/subscriptions", + "organizations_url": "https://api.github.com/users/zackees/orgs", + "repos_url": "https://api.github.com/users/zackees/repos", + "events_url": "https://api.github.com/users/zackees/events{/privacy}", + "received_events_url": "https://api.github.com/users/zackees/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "jobs_url": "https://api.github.com/repos/zackees/mimalloc-pprof/actions/runs/39835530789/jobs", + "logs_url": "https://api.github.com/repos/zackees/mimalloc-pprof/actions/runs/39835530789/logs", + "check_suite_url": "https://api.github.com/repos/zackees/mimalloc-pprof/check-suites/107968595701", + "artifacts_url": "https://api.github.com/repos/zackees/mimalloc-pprof/actions/runs/39835530789/artifacts", + "cancel_url": "https://api.github.com/repos/zackees/mimalloc-pprof/actions/runs/39835530789/cancel", + "rerun_url": "https://api.github.com/repos/zackees/mimalloc-pprof/actions/runs/39835530789/rerun", + "previous_attempt_url": null, + "workflow_url": "https://api.github.com/repos/zackees/mimalloc-pprof/actions/workflows/324911951", + "head_commit": { + "id": "876d7c313026090b0dbeaadb8d0cf2f03f0c9c13", + "tree_id": "1d0585c56d062fe6a32a2b51a9462195b14f61aa", + "message": "test: acquire owner gate in retirement restore checks (#614)\n\nLocal-Gate: v1 tree=1d0585c56d062fe6a32a2b51a9462195b14f61aa secs=59 lanes=lint:run\nCi-Attestation: {\"at\":1792694310,\"gate\":\"python/all/lint\",\"host\":\"linux-x86_64\",\"key\":\"8c80351474c69b33f5060c32ff132be34c1f04cf0b56011cbcf755e1354237a7\",\"lane\":\"lint\",\"parents\":[\"24d291e0927520b5de35876697c57c947f0b6703\"],\"secs\":59,\"stamp\":\"eccb7bea086448bda04b4f066143f90d\",\"tree\":\"1d0585c56d062fe6a32a2b51a9462195b14f61aa\",\"v\":1,\"via\":\"run\"}", + "timestamp": "2026-10-22T18:38:30Z", + "author": { + "name": "Zach Vorhies", + "email": "zachvorhies@protonmail.com" + }, + "committer": { + "name": "Zach Vorhies", + "email": "zachvorhies@protonmail.com" + } + }, + "repository": { + "id": 1309665442, + "node_id": "R_kgDOTg_oog", + "name": "mimalloc-pprof", + "full_name": "zackees/mimalloc-pprof", + "private": false, + "owner": { + "login": "zackees", + "id": 6856673, + "node_id": "MDQ6VXNlcjY4NTY2NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/6856673?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/zackees", + "html_url": "https://github.com/zackees", + "followers_url": "https://api.github.com/users/zackees/followers", + "following_url": "https://api.github.com/users/zackees/following{/other_user}", + "gists_url": "https://api.github.com/users/zackees/gists{/gist_id}", + "starred_url": "https://api.github.com/users/zackees/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/zackees/subscriptions", + "organizations_url": "https://api.github.com/users/zackees/orgs", + "repos_url": "https://api.github.com/users/zackees/repos", + "events_url": "https://api.github.com/users/zackees/events{/privacy}", + "received_events_url": "https://api.github.com/users/zackees/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "html_url": "https://github.com/zackees/mimalloc-pprof", + "description": "4th generation Mimalloc: fixes large alloc peak memory, same speed class. Cut large-buffer peak RSS > 50%. Memory purging, pprof heap profiling. Drop-in for C and Rust", + "fork": false, + "url": "https://api.github.com/repos/zackees/mimalloc-pprof", + "forks_url": "https://api.github.com/repos/zackees/mimalloc-pprof/forks", + "keys_url": "https://api.github.com/repos/zackees/mimalloc-pprof/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/zackees/mimalloc-pprof/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/zackees/mimalloc-pprof/teams", + "hooks_url": "https://api.github.com/repos/zackees/mimalloc-pprof/hooks", + "issue_events_url": "https://api.github.com/repos/zackees/mimalloc-pprof/issues/events{/number}", + "events_url": "https://api.github.com/repos/zackees/mimalloc-pprof/events", + "assignees_url": "https://api.github.com/repos/zackees/mimalloc-pprof/assignees{/user}", + "branches_url": "https://api.github.com/repos/zackees/mimalloc-pprof/branches{/branch}", + "tags_url": "https://api.github.com/repos/zackees/mimalloc-pprof/tags", + "blobs_url": "https://api.github.com/repos/zackees/mimalloc-pprof/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/zackees/mimalloc-pprof/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/zackees/mimalloc-pprof/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/zackees/mimalloc-pprof/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/zackees/mimalloc-pprof/statuses/{sha}", + "languages_url": "https://api.github.com/repos/zackees/mimalloc-pprof/languages", + "stargazers_url": "https://api.github.com/repos/zackees/mimalloc-pprof/stargazers", + "contributors_url": "https://api.github.com/repos/zackees/mimalloc-pprof/contributors", + "subscribers_url": "https://api.github.com/repos/zackees/mimalloc-pprof/subscribers", + "subscription_url": "https://api.github.com/repos/zackees/mimalloc-pprof/subscription", + "commits_url": "https://api.github.com/repos/zackees/mimalloc-pprof/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/zackees/mimalloc-pprof/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/zackees/mimalloc-pprof/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/zackees/mimalloc-pprof/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/zackees/mimalloc-pprof/contents/{+path}", + "compare_url": "https://api.github.com/repos/zackees/mimalloc-pprof/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/zackees/mimalloc-pprof/merges", + "archive_url": "https://api.github.com/repos/zackees/mimalloc-pprof/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/zackees/mimalloc-pprof/downloads", + "issues_url": "https://api.github.com/repos/zackees/mimalloc-pprof/issues{/number}", + "pulls_url": "https://api.github.com/repos/zackees/mimalloc-pprof/pulls{/number}", + "milestones_url": "https://api.github.com/repos/zackees/mimalloc-pprof/milestones{/number}", + "notifications_url": "https://api.github.com/repos/zackees/mimalloc-pprof/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/zackees/mimalloc-pprof/labels{/name}", + "releases_url": "https://api.github.com/repos/zackees/mimalloc-pprof/releases{/id}", + "deployments_url": "https://api.github.com/repos/zackees/mimalloc-pprof/deployments" + }, + "head_repository": { + "id": 1309665442, + "node_id": "R_kgDOTg_oog", + "name": "mimalloc-pprof", + "full_name": "zackees/mimalloc-pprof", + "private": false, + "owner": { + "login": "zackees", + "id": 6856673, + "node_id": "MDQ6VXNlcjY4NTY2NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/6856673?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/zackees", + "html_url": "https://github.com/zackees", + "followers_url": "https://api.github.com/users/zackees/followers", + "following_url": "https://api.github.com/users/zackees/following{/other_user}", + "gists_url": "https://api.github.com/users/zackees/gists{/gist_id}", + "starred_url": "https://api.github.com/users/zackees/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/zackees/subscriptions", + "organizations_url": "https://api.github.com/users/zackees/orgs", + "repos_url": "https://api.github.com/users/zackees/repos", + "events_url": "https://api.github.com/users/zackees/events{/privacy}", + "received_events_url": "https://api.github.com/users/zackees/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "html_url": "https://github.com/zackees/mimalloc-pprof", + "description": "4th generation Mimalloc: fixes large alloc peak memory, same speed class. Cut large-buffer peak RSS > 50%. Memory purging, pprof heap profiling. Drop-in for C and Rust", + "fork": false, + "url": "https://api.github.com/repos/zackees/mimalloc-pprof", + "forks_url": "https://api.github.com/repos/zackees/mimalloc-pprof/forks", + "keys_url": "https://api.github.com/repos/zackees/mimalloc-pprof/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/zackees/mimalloc-pprof/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/zackees/mimalloc-pprof/teams", + "hooks_url": "https://api.github.com/repos/zackees/mimalloc-pprof/hooks", + "issue_events_url": "https://api.github.com/repos/zackees/mimalloc-pprof/issues/events{/number}", + "events_url": "https://api.github.com/repos/zackees/mimalloc-pprof/events", + "assignees_url": "https://api.github.com/repos/zackees/mimalloc-pprof/assignees{/user}", + "branches_url": "https://api.github.com/repos/zackees/mimalloc-pprof/branches{/branch}", + "tags_url": "https://api.github.com/repos/zackees/mimalloc-pprof/tags", + "blobs_url": "https://api.github.com/repos/zackees/mimalloc-pprof/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/zackees/mimalloc-pprof/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/zackees/mimalloc-pprof/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/zackees/mimalloc-pprof/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/zackees/mimalloc-pprof/statuses/{sha}", + "languages_url": "https://api.github.com/repos/zackees/mimalloc-pprof/languages", + "stargazers_url": "https://api.github.com/repos/zackees/mimalloc-pprof/stargazers", + "contributors_url": "https://api.github.com/repos/zackees/mimalloc-pprof/contributors", + "subscribers_url": "https://api.github.com/repos/zackees/mimalloc-pprof/subscribers", + "subscription_url": "https://api.github.com/repos/zackees/mimalloc-pprof/subscription", + "commits_url": "https://api.github.com/repos/zackees/mimalloc-pprof/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/zackees/mimalloc-pprof/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/zackees/mimalloc-pprof/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/zackees/mimalloc-pprof/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/zackees/mimalloc-pprof/contents/{+path}", + "compare_url": "https://api.github.com/repos/zackees/mimalloc-pprof/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/zackees/mimalloc-pprof/merges", + "archive_url": "https://api.github.com/repos/zackees/mimalloc-pprof/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/zackees/mimalloc-pprof/downloads", + "issues_url": "https://api.github.com/repos/zackees/mimalloc-pprof/issues{/number}", + "pulls_url": "https://api.github.com/repos/zackees/mimalloc-pprof/pulls{/number}", + "milestones_url": "https://api.github.com/repos/zackees/mimalloc-pprof/milestones{/number}", + "notifications_url": "https://api.github.com/repos/zackees/mimalloc-pprof/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/zackees/mimalloc-pprof/labels{/name}", + "releases_url": "https://api.github.com/repos/zackees/mimalloc-pprof/releases{/id}", + "deployments_url": "https://api.github.com/repos/zackees/mimalloc-pprof/deployments" + } + }, + "jobs": { + "total_count": 3, + "jobs": [ + { + "id": 120022721547, + "run_id": 39835530789, + "workflow_name": "fuzz", + "head_branch": "perf/614-large-reuse-cpu", + "run_url": "https://api.github.com/repos/zackees/mimalloc-pprof/actions/runs/39835530789", + "run_attempt": 1, + "node_id": "CR_kwDOTg_oos8AAAAb8elkCw", + "head_sha": "876d7c313026090b0dbeaadb8d0cf2f03f0c9c13", + "url": "https://api.github.com/repos/zackees/mimalloc-pprof/actions/jobs/120022721547", + "html_url": "https://github.com/zackees/mimalloc-pprof/actions/runs/39835530789/job/120022721547", + "status": "completed", + "conclusion": "success", + "created_at": "2026-10-22T18:54:57Z", + "started_at": "2026-10-22T18:55:00Z", + "completed_at": "2026-10-22T18:55:14Z", + "name": "pr-ci-mode / decide", + "steps": [ + { + "name": "Set up job", + "status": "completed", + "conclusion": "success", + "number": 1, + "started_at": "2026-10-22T18:55:01Z", + "completed_at": "2026-10-22T18:55:02Z" + }, + { + "name": "Run actions/checkout@v4", + "status": "completed", + "conclusion": "success", + "number": 2, + "started_at": "2026-10-22T18:55:02Z", + "completed_at": "2026-10-22T18:55:11Z" + }, + { + "name": "Run python3 ci/pr_ci_mode.py --event \"$EVENT\" --repository \"$REPOSITORY\" --author \"$AUTHOR\"", + "status": "completed", + "conclusion": "success", + "number": 3, + "started_at": "2026-10-22T18:55:11Z", + "completed_at": "2026-10-22T18:55:12Z" + }, + { + "name": "Post Run actions/checkout@v4", + "status": "completed", + "conclusion": "success", + "number": 6, + "started_at": "2026-10-22T18:55:12Z", + "completed_at": "2026-10-22T18:55:12Z" + }, + { + "name": "Complete job", + "status": "completed", + "conclusion": "success", + "number": 7, + "started_at": "2026-10-22T18:55:12Z", + "completed_at": "2026-10-22T18:55:12Z" + } + ], + "check_run_url": "https://api.github.com/repos/zackees/mimalloc-pprof/check-runs/120022721547", + "labels": [ + "ubuntu-latest" + ], + "runner_id": 1001331769, + "runner_name": "GitHub Actions 1001331769", + "runner_group_id": 0, + "runner_group_name": "GitHub Actions" + }, + { + "id": 120022870553, + "run_id": 39835530789, + "workflow_name": "fuzz", + "head_branch": "perf/614-large-reuse-cpu", + "run_url": "https://api.github.com/repos/zackees/mimalloc-pprof/actions/runs/39835530789", + "run_attempt": 1, + "node_id": "CR_kwDOTg_oos8AAAAb8euqGQ", + "head_sha": "876d7c313026090b0dbeaadb8d0cf2f03f0c9c13", + "url": "https://api.github.com/repos/zackees/mimalloc-pprof/actions/jobs/120022870553", + "html_url": "https://github.com/zackees/mimalloc-pprof/actions/runs/39835530789/job/120022870553", + "status": "completed", + "conclusion": "success", + "created_at": "2026-10-22T18:55:15Z", + "started_at": "2026-10-22T18:55:34Z", + "completed_at": "2026-10-22T19:01:37Z", + "name": "fuzz", + "steps": [ + { + "name": "Set up job", + "status": "completed", + "conclusion": "success", + "number": 1, + "started_at": "2026-10-22T18:55:35Z", + "completed_at": "2026-10-22T18:55:36Z" + }, + { + "name": "Run actions/checkout@v4", + "status": "completed", + "conclusion": "success", + "number": 2, + "started_at": "2026-10-22T18:55:36Z", + "completed_at": "2026-10-22T18:55:38Z" + }, + { + "name": "Build harnesses (libFuzzer + ASan)", + "status": "completed", + "conclusion": "success", + "number": 3, + "started_at": "2026-10-22T18:55:38Z", + "completed_at": "2026-10-22T18:55:53Z" + }, + { + "name": "Fuzz", + "status": "completed", + "conclusion": "success", + "number": 4, + "started_at": "2026-10-22T18:55:53Z", + "completed_at": "2026-10-22T19:01:32Z" + }, + { + "name": "Positive control -- the fuzzer must find a planted bug", + "status": "completed", + "conclusion": "success", + "number": 5, + "started_at": "2026-10-22T19:01:32Z", + "completed_at": "2026-10-22T19:01:36Z" + }, + { + "name": "Run actions/upload-artifact@v4", + "status": "completed", + "conclusion": "skipped", + "number": 6, + "started_at": "2026-10-22T19:01:36Z", + "completed_at": "2026-10-22T19:01:36Z" + }, + { + "name": "Post Run actions/checkout@v4", + "status": "completed", + "conclusion": "success", + "number": 12, + "started_at": "2026-10-22T19:01:36Z", + "completed_at": "2026-10-22T19:01:36Z" + }, + { + "name": "Complete job", + "status": "completed", + "conclusion": "success", + "number": 13, + "started_at": "2026-10-22T19:01:36Z", + "completed_at": "2026-10-22T19:01:36Z" + } + ], + "check_run_url": "https://api.github.com/repos/zackees/mimalloc-pprof/check-runs/120022870553", + "labels": [ + "ubuntu-latest" + ], + "runner_id": 1001331827, + "runner_name": "GitHub Actions 1001331827", + "runner_group_id": 0, + "runner_group_name": "GitHub Actions" + }, + { + "id": 120026026949, + "run_id": 39835530789, + "workflow_name": "fuzz", + "head_branch": "perf/614-large-reuse-cpu", + "run_url": "https://api.github.com/repos/zackees/mimalloc-pprof/actions/runs/39835530789", + "run_attempt": 1, + "node_id": "CR_kwDOTg_oos8AAAAb8hvTxQ", + "head_sha": "876d7c313026090b0dbeaadb8d0cf2f03f0c9c13", + "url": "https://api.github.com/repos/zackees/mimalloc-pprof/actions/jobs/120026026949", + "html_url": "https://github.com/zackees/mimalloc-pprof/actions/runs/39835530789/job/120026026949", + "status": "completed", + "conclusion": "success", + "created_at": "2026-10-22T19:01:38Z", + "started_at": "2026-10-22T19:01:41Z", + "completed_at": "2026-10-22T19:01:47Z", + "name": "PR test gate (fuzz) / verify", + "steps": [ + { + "name": "Set up job", + "status": "completed", + "conclusion": "success", + "number": 1, + "started_at": "2026-10-22T19:01:41Z", + "completed_at": "2026-10-22T19:01:42Z" + }, + { + "name": "Run actions/checkout@v4", + "status": "completed", + "conclusion": "success", + "number": 2, + "started_at": "2026-10-22T19:01:42Z", + "completed_at": "2026-10-22T19:01:46Z" + }, + { + "name": "Run python3 ci/pr_ci_gate.py --workflow \"$WORKFLOW\"", + "status": "completed", + "conclusion": "success", + "number": 3, + "started_at": "2026-10-22T19:01:46Z", + "completed_at": "2026-10-22T19:01:46Z" + }, + { + "name": "Post Run actions/checkout@v4", + "status": "completed", + "conclusion": "success", + "number": 6, + "started_at": "2026-10-22T19:01:46Z", + "completed_at": "2026-10-22T19:01:46Z" + }, + { + "name": "Complete job", + "status": "completed", + "conclusion": "success", + "number": 7, + "started_at": "2026-10-22T19:01:46Z", + "completed_at": "2026-10-22T19:01:46Z" + } + ], + "check_run_url": "https://api.github.com/repos/zackees/mimalloc-pprof/check-runs/120026026949", + "labels": [ + "ubuntu-latest" + ], + "runner_id": 1001331866, + "runner_name": "GitHub Actions 1001331866", + "runner_group_id": 0, + "runner_group_name": "GitHub Actions" + } + ] + } +} diff --git a/.github/assets/perf-614/v2-corrected-platform-archive.json b/.github/assets/perf-614/v2-corrected-platform-archive.json new file mode 100644 index 00000000..b1a56982 --- /dev/null +++ b/.github/assets/perf-614/v2-corrected-platform-archive.json @@ -0,0 +1,5 @@ +{ + "sha256": "11d1ea8931d42536fcfdb3fb06dff4efa2fbd2b03737893792c89a82f33d641a", + "members": 37, + "note": "Corrected V2: ten complete successful workflows; fuzz all three jobs success with individual logs preserved, workflow-level in_progress at collection. No claim of complete workflow finalization." +} diff --git a/.github/assets/perf-614/v2-corrected-platform.zip b/.github/assets/perf-614/v2-corrected-platform.zip new file mode 100644 index 00000000..8420782b Binary files /dev/null and b/.github/assets/perf-614/v2-corrected-platform.zip differ diff --git a/.github/assets/perf-614/v2-dispatches.json b/.github/assets/perf-614/v2-dispatches.json new file mode 100644 index 00000000..1c2c3a26 --- /dev/null +++ b/.github/assets/perf-614/v2-dispatches.json @@ -0,0 +1,118 @@ +{ + "baseline": "227eef06ff03f92966f38508441d6c2f60a75135", + "candidate": "59d369609ab47358df0f883b6419252f1ffbf03a", + "ref": "perf/614-large-reuse-cpu", + "analysis_sha256": { + "ci/perf_ab.py": "905c078f16ee1a71e4d8623c1e0c14def3235b8c6be424be1b8c568320f95d89", + "ci/perf_ab.c": "2be8bd64d1e17c142b5773f3cbfdc95174f6c261748456f3622716194d162756", + "ci/perf_ab_ledger.py": "870dc4d72132034a398d310261231820c5ebf7de4cf44d81e94711ea5393df6a", + "ci/perf_ab_stats.py": "deee6c17d8e0b9be84219638c43abc97c85354a7c3129480ddb93eee17ac9bdd" + }, + "runs": [ + { + "workload": "large-class/8", + "stage": 1, + "kind": "plain", + "params": { + "threads": 8, + "generations": 1, + "min_size": 98304, + "max_size": 524288, + "ops": 400000, + "pause_ms": 0, + "table_slots": 0, + "sizes": "uniform", + "slots": 8 + }, + "dispatch": { + "ref": "perf/614-large-reuse-cpu", + "return_run_details": true, + "inputs": { + "base": "227eef06ff03f92966f38508441d6c2f60a75135", + "head_sha": "59d369609ab47358df0f883b6419252f1ffbf03a", + "workloads": "=large-class/8", + "reps": "60", + "max_reps": "120", + "null_arm": "true", + "sanity_gate": "true", + "holes_report": "false" + } + }, + "response": { + "workflow_run_id": 39831495052, + "run_url": "https://api.github.com/repos/zackees/mimalloc-pprof/actions/runs/39831495052", + "html_url": "https://github.com/zackees/mimalloc-pprof/actions/runs/39831495052" + } + }, + { + "workload": "large-class-ephemeral/8", + "stage": 1, + "kind": "plain", + "params": { + "threads": 8, + "generations": 8, + "min_size": 98304, + "max_size": 524288, + "ops": 400000, + "pause_ms": 0, + "table_slots": 0, + "sizes": "uniform", + "slots": 8 + }, + "dispatch": { + "ref": "perf/614-large-reuse-cpu", + "return_run_details": true, + "inputs": { + "base": "227eef06ff03f92966f38508441d6c2f60a75135", + "head_sha": "59d369609ab47358df0f883b6419252f1ffbf03a", + "workloads": "=large-class-ephemeral/8", + "reps": "60", + "max_reps": "120", + "null_arm": "true", + "sanity_gate": "true", + "holes_report": "false" + } + }, + "response": { + "workflow_run_id": 39831499063, + "run_url": "https://api.github.com/repos/zackees/mimalloc-pprof/actions/runs/39831499063", + "html_url": "https://github.com/zackees/mimalloc-pprof/actions/runs/39831499063" + } + }, + { + "workload": "large-class-ephemeral/8 short generations (chart build)", + "stage": 1, + "kind": "chart", + "params": { + "threads": 8, + "generations": 8, + "min_size": 98304, + "max_size": 524288, + "ops": 100000, + "pause_ms": 0, + "table_slots": 0, + "sizes": "uniform", + "slots": 8 + }, + "dispatch": { + "ref": "perf/614-large-reuse-cpu", + "return_run_details": true, + "inputs": { + "base": "227eef06ff03f92966f38508441d6c2f60a75135", + "head_sha": "59d369609ab47358df0f883b6419252f1ffbf03a", + "workloads": "=large-class-ephemeral/8 short generations (chart build)", + "reps": "60", + "max_reps": "120", + "null_arm": "true", + "sanity_gate": "true", + "holes_report": "false" + } + }, + "response": { + "workflow_run_id": 39831504283, + "run_url": "https://api.github.com/repos/zackees/mimalloc-pprof/actions/runs/39831504283", + "html_url": "https://github.com/zackees/mimalloc-pprof/actions/runs/39831504283" + } + } + ] +} diff --git a/.github/assets/perf-614/v2-measurements-archive.json b/.github/assets/perf-614/v2-measurements-archive.json new file mode 100644 index 00000000..82d8bbb2 --- /dev/null +++ b/.github/assets/perf-614/v2-measurements-archive.json @@ -0,0 +1,5 @@ +{ + "sha256": "5ec7338326949986dda22126e00831883cab093c1e3c71692b6d0a7c310ca745", + "bytes": 10177133, + "members": 55 +} diff --git a/.github/assets/perf-614/v2-measurements.zip b/.github/assets/perf-614/v2-measurements.zip new file mode 100644 index 00000000..3d18833a Binary files /dev/null and b/.github/assets/perf-614/v2-measurements.zip differ diff --git a/.github/assets/perf-614/v2-original-platform-archive.json b/.github/assets/perf-614/v2-original-platform-archive.json new file mode 100644 index 00000000..0f866094 --- /dev/null +++ b/.github/assets/perf-614/v2-original-platform-archive.json @@ -0,0 +1,5 @@ +{ + "sha256": "00c66cedcb842c7ae8f0062e68c20831fffdec817b747bc3ac65797dce3503c5", + "members": 25, + "conclusions": "10workflowssuccess,1ASANfailure; no relabeling" +} diff --git a/.github/assets/perf-614/v2-original-platform.zip b/.github/assets/perf-614/v2-original-platform.zip new file mode 100644 index 00000000..0bc41920 Binary files /dev/null and b/.github/assets/perf-614/v2-original-platform.zip differ diff --git a/.github/assets/perf-614/v2-source-manifest.json b/.github/assets/perf-614/v2-source-manifest.json new file mode 100644 index 00000000..a0d70c1a --- /dev/null +++ b/.github/assets/perf-614/v2-source-manifest.json @@ -0,0 +1,8 @@ +{ + "sha": "59d369609ab47358df0f883b6419252f1ffbf03a", + "file": "59d369609ab47358df0f883b6419252f1ffbf03a.tar", + "bytes": 20387840, + "sha256": "7d009652343a536799ac199c08e6ba9e75b328dc265aba59bfebdd5d0e9d47ca", + "excluded": ".github/assets/ (historical binary evidence only)", + "verified_git_blobs": 855 +} diff --git a/.github/assets/perf-614/v2-stamped-test-fix-source-equivalence.json b/.github/assets/perf-614/v2-stamped-test-fix-source-equivalence.json new file mode 100644 index 00000000..1a8e77b7 --- /dev/null +++ b/.github/assets/perf-614/v2-stamped-test-fix-source-equivalence.json @@ -0,0 +1,15 @@ +{ + "measured": "59d369609ab47358df0f883b6419252f1ffbf03a", + "corrected_stamped": "876d7c313026090b0dbeaadb8d0cf2f03f0c9c13", + "changed_paths": [ + ".gitattributes", + ".github/assets/perf-614/README.md", + ".github/assets/perf-614/v2-campaign-plan.json", + ".github/assets/perf-614/v2-dispatches.json", + ".github/assets/perf-614/v2-source-manifest.json", + ".github/assets/perf-614/v2-structural-archive.json", + ".github/assets/perf-614/v2-structural.zip", + "test/test-event-counters.c" + ], + "allocator_build_harness_rust_unchanged": true +} diff --git a/.github/assets/perf-614/v2-structural-archive.json b/.github/assets/perf-614/v2-structural-archive.json new file mode 100644 index 00000000..07b73177 --- /dev/null +++ b/.github/assets/perf-614/v2-structural-archive.json @@ -0,0 +1,5 @@ +{ + "sha256": "fddcb2e544a8d6717d965b924a82a8450ba5da00c7239bcf270c9542c806cfa9", + "members": 33, + "note": "Scratch structural evidence; unoptimized codegen logs retained as failed setup evidence, optimized named files use explicit -O3 -DNDEBUG. Local gate and campaign evidence separate." +} diff --git a/.github/assets/perf-614/v2-structural.zip b/.github/assets/perf-614/v2-structural.zip new file mode 100644 index 00000000..65438633 Binary files /dev/null and b/.github/assets/perf-614/v2-structural.zip differ diff --git a/.github/assets/perf-614/v2-test-fix-evidence-archive.json b/.github/assets/perf-614/v2-test-fix-evidence-archive.json new file mode 100644 index 00000000..575434b6 --- /dev/null +++ b/.github/assets/perf-614/v2-test-fix-evidence-archive.json @@ -0,0 +1,5 @@ +{ + "sha256": "6961df730eb2cbb685bd8570403c2d4b0223dbdd3d1eb2bb02959f66def0ac07", + "members": 23, + "note": "Original CI ASAN failure retained. v2-owner-asan local setup disabledASAN; v2-owner-sanitized explicitlyON and __asan_init verified. Test-only correction; no performance rerun." +} diff --git a/.github/assets/perf-614/v2-test-fix-evidence.zip b/.github/assets/perf-614/v2-test-fix-evidence.zip new file mode 100644 index 00000000..cc1cb87d Binary files /dev/null and b/.github/assets/perf-614/v2-test-fix-evidence.zip differ diff --git a/.github/assets/perf-614/v2-test-fix-local-gate.log b/.github/assets/perf-614/v2-test-fix-local-gate.log new file mode 100644 index 00000000..ceae043c --- /dev/null +++ b/.github/assets/perf-614/v2-test-fix-local-gate.log @@ -0,0 +1,3 @@ +local-gate: lane lint: started (heavy) +local-gate: lane lint: passed in 59s -- local gate: 45/45 checks passed +local-gate run: passed in 59s [lint:run]; stamped 876d7c313026 (Local-Gate tree=1d0585c56d06) diff --git a/.github/assets/perf-614/v3-measurements-archive.json b/.github/assets/perf-614/v3-measurements-archive.json new file mode 100644 index 00000000..17269ae9 --- /dev/null +++ b/.github/assets/perf-614/v3-measurements-archive.json @@ -0,0 +1,5 @@ +{ + "sha256": "0a632414a3fcb00d5fb16fd3f8e71a886a6f7d6485e9da095bfd2a976c18b9f7", + "members": 67, + "bytes": 10194165 +} diff --git a/.github/assets/perf-614/v3-measurements.zip b/.github/assets/perf-614/v3-measurements.zip new file mode 100644 index 00000000..980fb2f6 Binary files /dev/null and b/.github/assets/perf-614/v3-measurements.zip differ diff --git a/.github/assets/perf-614/v3-platform-archive.json b/.github/assets/perf-614/v3-platform-archive.json new file mode 100644 index 00000000..c1207426 --- /dev/null +++ b/.github/assets/perf-614/v3-platform-archive.json @@ -0,0 +1,5 @@ +{ + "sha256": "cc86631cde8e47fbf0421bb249ffc00db62d564ab50b717051bfe4934470c5a0", + "members": 58, + "bytes": 4206243 +} diff --git a/.github/assets/perf-614/v3-platform.zip b/.github/assets/perf-614/v3-platform.zip new file mode 100644 index 00000000..275be373 Binary files /dev/null and b/.github/assets/perf-614/v3-platform.zip differ diff --git a/.github/assets/perf-614/v3-source-manifest.json b/.github/assets/perf-614/v3-source-manifest.json new file mode 100644 index 00000000..0ef5e76f --- /dev/null +++ b/.github/assets/perf-614/v3-source-manifest.json @@ -0,0 +1,8 @@ +{ + "sha": "5b2d8f960297fda825b05b7471893fc4cf6c2f33", + "file": "5b2d8f960297fda825b05b7471893fc4cf6c2f33.tar", + "bytes": 20387840, + "sha256": "3ffd0897c29a0d840836b37a3f0122be517aef41d0b98ca071d41f012eaa9a92", + "excluded": ".github/assets/ (historical binary evidence only)", + "verified_git_blobs": 855 +} diff --git a/.github/assets/perf-614/v3-structural-archive.json b/.github/assets/perf-614/v3-structural-archive.json new file mode 100644 index 00000000..54f89551 --- /dev/null +++ b/.github/assets/perf-614/v3-structural-archive.json @@ -0,0 +1,5 @@ +{ + "sha256": "0396b986435a3652b450766cb52942e314ad52866c0b7d4e2c505c6fedf49847", + "members": 56, + "note": "V3 count-only baseline attribution, RED/GREEN and optimized codegen; no performance acceptance claim." +} diff --git a/.github/assets/perf-614/v3-structural.zip b/.github/assets/perf-614/v3-structural.zip new file mode 100644 index 00000000..78370f6b Binary files /dev/null and b/.github/assets/perf-614/v3-structural.zip differ diff --git a/.github/assets/perf-614/v4-measurements-archive.json b/.github/assets/perf-614/v4-measurements-archive.json new file mode 100644 index 00000000..d4d2fabb --- /dev/null +++ b/.github/assets/perf-614/v4-measurements-archive.json @@ -0,0 +1,5 @@ +{ + "sha256": "4906c9ba0b9b0f2729192c9199c81dc73af77c4b0de224c985fce3336916afe2", + "members": 58, + "bytes": 10119115 +} diff --git a/.github/assets/perf-614/v4-measurements.zip b/.github/assets/perf-614/v4-measurements.zip new file mode 100644 index 00000000..7acf61b8 Binary files /dev/null and b/.github/assets/perf-614/v4-measurements.zip differ diff --git a/.github/assets/perf-614/v4-platform-archive.json b/.github/assets/perf-614/v4-platform-archive.json new file mode 100644 index 00000000..c617576c --- /dev/null +++ b/.github/assets/perf-614/v4-platform-archive.json @@ -0,0 +1,5 @@ +{ + "sha256": "80304105173bf27334df7ca784d319ee943bfa53fd70c0a392d838a808ac2a70", + "members": 59, + "bytes": 4199975 +} diff --git a/.github/assets/perf-614/v4-platform.zip b/.github/assets/perf-614/v4-platform.zip new file mode 100644 index 00000000..1734321a Binary files /dev/null and b/.github/assets/perf-614/v4-platform.zip differ diff --git a/.github/assets/perf-614/v4-source-manifest.json b/.github/assets/perf-614/v4-source-manifest.json new file mode 100644 index 00000000..d9f57def --- /dev/null +++ b/.github/assets/perf-614/v4-source-manifest.json @@ -0,0 +1,8 @@ +{ + "sha": "8fda62c6d05a68ea4c0ffe2859f07eabf5e72d97", + "file": "8fda62c6d05a68ea4c0ffe2859f07eabf5e72d97.tar", + "bytes": 20387840, + "sha256": "186c90f2424a51f4c08046151648aa02787db201fff5df0e7e4dd958039bed6b", + "excluded": ".github/assets/ (historical binary evidence only)", + "verified_git_blobs": 855 +} diff --git a/.github/assets/perf-614/v4-structural-archive.json b/.github/assets/perf-614/v4-structural-archive.json new file mode 100644 index 00000000..c1704ab7 --- /dev/null +++ b/.github/assets/perf-614/v4-structural-archive.json @@ -0,0 +1,5 @@ +{ + "sha256": "008a3f13f8d5921f1b885725d835936fdd6d3e8725451b6f17ad5c0dd7a8a9d8", + "members": 23, + "note": "V4 accounting-only RED/GREEN, original transition equivalence, optimized codegen; no performance acceptance." +} diff --git a/.github/assets/perf-614/v4-structural.zip b/.github/assets/perf-614/v4-structural.zip new file mode 100644 index 00000000..a7cc9222 Binary files /dev/null and b/.github/assets/perf-614/v4-structural.zip differ diff --git a/.github/assets/perf-614/v5-preflight-archive.json b/.github/assets/perf-614/v5-preflight-archive.json new file mode 100644 index 00000000..d3d16b40 --- /dev/null +++ b/.github/assets/perf-614/v5-preflight-archive.json @@ -0,0 +1,5 @@ +{ + "sha256": "cbc1b0475e0f774b240b3099d92bc8d72f8889383250cdc1a2bb94b141236d1f", + "bytes": 6858013, + "members": 49 +} diff --git a/.github/assets/perf-614/v5-preflight.zip b/.github/assets/perf-614/v5-preflight.zip new file mode 100644 index 00000000..c28faddd Binary files /dev/null and b/.github/assets/perf-614/v5-preflight.zip differ diff --git a/.github/assets/perf-614/v6-measurements-archive.json b/.github/assets/perf-614/v6-measurements-archive.json new file mode 100644 index 00000000..bc82d073 --- /dev/null +++ b/.github/assets/perf-614/v6-measurements-archive.json @@ -0,0 +1,5 @@ +{ + "sha256": "b0a22c3a452c55a56e76fde26f5cfa003d01b86a5bc445439e4208cb624cb2bd", + "members": 57, + "bytes": 6078640 +} diff --git a/.github/assets/perf-614/v6-measurements.zip b/.github/assets/perf-614/v6-measurements.zip new file mode 100644 index 00000000..9a9ba870 Binary files /dev/null and b/.github/assets/perf-614/v6-measurements.zip differ diff --git a/.github/assets/perf-614/v6-platform-archive.json b/.github/assets/perf-614/v6-platform-archive.json new file mode 100644 index 00000000..547d18fe --- /dev/null +++ b/.github/assets/perf-614/v6-platform-archive.json @@ -0,0 +1,6 @@ +{ + "file": "v6-platform.zip", + "members": 54, + "bytes": 4196987, + "sha256": "7dbde31bdf3672301e870c10df148575db96cd391c430e8c7537cb8032f575db" +} diff --git a/.github/assets/perf-614/v6-platform-review.txt b/.github/assets/perf-614/v6-platform-review.txt new file mode 100644 index 00000000..f7f4c146 --- /dev/null +++ b/.github/assets/perf-614/v6-platform-review.txt @@ -0,0 +1,5 @@ +No findings. Verified archive size/digest, 54 members, member hashes, and complete job lists. All ten workflows succeeded for exact candidate a40d8d6e717df31859103a034bf349d32e7760fc; candidate tree matches archived test-merge tree and local Git. +Coverage: native MSVC, Windows GNU, native Mac x64/ARM64, Rust, default fast-path identity, memory tests, sanitizers. Minimal-only memory job skipped in full lane; full-lane memory coverage retained. +Platform validation only, not performance acceptance. +review agents launched: 1 +clud-review: clean diff --git a/.github/assets/perf-614/v6-platform.zip b/.github/assets/perf-614/v6-platform.zip new file mode 100644 index 00000000..5cb26d99 Binary files /dev/null and b/.github/assets/perf-614/v6-platform.zip differ diff --git a/.github/assets/perf-614/v6-source-manifest.json b/.github/assets/perf-614/v6-source-manifest.json new file mode 100644 index 00000000..2ae2bf26 --- /dev/null +++ b/.github/assets/perf-614/v6-source-manifest.json @@ -0,0 +1,8 @@ +{ + "sha": "a40d8d6e717df31859103a034bf349d32e7760fc", + "file": "a40d8d6e717df31859103a034bf349d32e7760fc.tar", + "bytes": 20387840, + "sha256": "fc2f0f6cb0cdd8ade7cb7dcbb6517d1ab315a639d4ee195ea5274119501c38a9", + "excluded": ".github/assets/ (historical binary evidence only)", + "verified_git_blobs": 857 +} diff --git a/.github/assets/perf-614/v6-structural-archive.json b/.github/assets/perf-614/v6-structural-archive.json new file mode 100644 index 00000000..79254fdb --- /dev/null +++ b/.github/assets/perf-614/v6-structural-archive.json @@ -0,0 +1,5 @@ +{ + "sha256": "0890a148ca76c8315ab660ab7d841902a5af64e99112945b2a838ac0895eab54", + "bytes": 7983361, + "members": 47 +} diff --git a/.github/assets/perf-614/v6-structural.zip b/.github/assets/perf-614/v6-structural.zip new file mode 100644 index 00000000..9d1359bb Binary files /dev/null and b/.github/assets/perf-614/v6-structural.zip differ diff --git a/.github/assets/perf-614/v7-amalgamate.log b/.github/assets/perf-614/v7-amalgamate.log new file mode 100644 index 00000000..99f9b0c9 --- /dev/null +++ b/.github/assets/perf-614/v7-amalgamate.log @@ -0,0 +1,6 @@ +# t0=1792723536.595 + 0.33 Finished `dev` profile [unoptimized] target(s) in 0.31s + 0.33 Running `/tmp/mimalloc-614-campaign/xtask-target/debug/xtask amalgamate-c` +wrote /home/niteris/.clud/worktrees/mimalloc-pprof-wt-614/rust/mimalloc-pprof/vendor/mimalloc-pprof-amalgamated.c +wrote /home/niteris/.clud/worktrees/mimalloc-pprof-wt-614/rust/mimalloc-pprof/vendor/mimalloc.h +wrote /home/niteris/.clud/worktrees/mimalloc-pprof-wt-614/rust/mimalloc-pprof/vendor/mimalloc-stats.h diff --git a/.github/assets/perf-614/v7-design-review.txt b/.github/assets/perf-614/v7-design-review.txt new file mode 100644 index 00000000..4386c95f --- /dev/null +++ b/.github/assets/perf-614/v7-design-review.txt @@ -0,0 +1 @@ +Reviewer614: no design blocker. Selection establishes normal large singleton; unpublication restores exclusive access; full-bit relaxed atomic clear changes neither flags nor pages_full_size. No synchronization dependency apparent. Assert singleton/count/links, normallargequeue/matchingblocksize/owner/gate/fullclear/pagecount. Verify full-size accounting, flags, cache, neighbors. Clean design preflight only. diff --git a/.github/assets/perf-614/v7-handoff.md b/.github/assets/perf-614/v7-handoff.md new file mode 100644 index 00000000..eedd2eb4 --- /dev/null +++ b/.github/assets/perf-614/v7-handoff.md @@ -0,0 +1,22 @@ +# V7 draft handoff + +Implementation C commit `2ec4d32e`; generated Rust C commit `28ef6ad7`. +Baseline: `227eef06ff03f92966f38508441d6c2f60a75135`. + +V7 specializes only removal of the selected retired large singleton. It avoids the already-clear full-queue flag atomic RMW and generic linked-list checks, preserving ownership, queue/page counts, geometry and callback/failure ordering. No policy change. + +## Evidence + +- Original shared removal: focused work-count RED (one redundant flag write; two flag cases fail), actual executable retained. +- Candidate: C large-span PASS; secure C++ large-span PASS; actual ASan + owner-gate large-span PASS. Tests include generic control, state/flags/accounting/cache checks and 121 ordered recarve pairs. +- Design and implementation reviews clean. Generated Rust source regenerated separately. +- Secure C++ purge suite cannot compile: goto crosses initialized locals. Reproduced on byte-identical frozen-baseline test with matching compiler flags. +- Candidate ASan + owner-gate purge suite: 34 passed, 1 failed (`new-thread-does-not-sweep-at-once`, six global discards vs zero). Matching baseline run passed. No unchanged candidate retry and no waiver. +- Both purge processes recorded zero successful large repurposes, so V7's specialized path did not execute in that failing suite. Global discard accounting may include background activity; root cause remains unresolved. +- Archive contains exact binaries, source patch/new headers, commands, build flags, logs and internal member hashes; external digest is adjacent. The preserved RED test header was reconstructed from the test before the later generic-control addition; the actual failing executable and log are preserved. + +## Remaining work + +Resolve validation blockers with focused RED/GREEN evidence. Then validate generated Rust and applicable platforms, predeclare and run V7 performance against the frozen baseline, and apply #614's complete acceptance criteria. No V7 performance runs have been dispatched; no CPU/RSS benefit is claimed. PR must remain draft. V1–V6 rejections and full ledgers are retained alongside this evidence. + +This handoff publishes the current work, not completion of #614. Final merge, task-owned cleanup and original-checkout synchronization remain outstanding. diff --git a/.github/assets/perf-614/v7-implementation-review.txt b/.github/assets/perf-614/v7-implementation-review.txt new file mode 100644 index 00000000..25fc0079 --- /dev/null +++ b/.github/assets/perf-614/v7-implementation-review.txt @@ -0,0 +1 @@ +Reviewer614: no actionable findings. Singleton/large-bin/owner invariants preserve observable state. Same postunpublication, pregeometry/failure ordering. Generic remover unchanged except exact flagsetter counting macro. Tests cover counter/control,flags,queue/page/full-size accounting,cache,neighbors. Independently ran test-large-span1/1PASS. Rust parity and remaining validation pending. review agents launched:1; clud-review:clean. diff --git a/.github/assets/perf-614/v7-investigation.md b/.github/assets/perf-614/v7-investigation.md new file mode 100644 index 00000000..78954d3e --- /dev/null +++ b/.github/assets/perf-614/v7-investigation.md @@ -0,0 +1,11 @@ +# V7 investigation: retired large singleton queue removal + +Not implemented or measured. No performance claim. + +Fixed baseline 227eef06ff03f92966f38508441d6c2f60a75135. Baseline dense ephemeral profile attributes 0.71% self samples to mi_page_queue_remove (perturbed attribution only). Existing original event runs record large_repurpose 554050 large, 530645 plain ephemeral, 130788 chart ephemeral; repeated report lines are the same process counters, not additional samples. + +Selection in page-retired-search.h requires first == last, retired, used == 0, separate arena metadata, and a large-bin queue. Generic mi_page_queue_remove nonetheless loads/tests linked neighbors and performs mi_page_set_in_full(false). Optimized baseline disassembly v7-baseline-queue-remove.asm retains lock btr at 0x1f00b to clear the already-clear full-queue bit. The source helper updates pages_full_size only if the flag changes. Generic push similarly clears the full flag, but optimizing push is not yet selected. + +Proposed bounded candidate: specialized removal for the selected large singleton, preserving all queue count/page count updates and failure sequencing, proving the full bit is already clear and owner-only. No page-selection, geometry, aging, retention, purge, publication order or service policy change. Keep generic removal for all other callers. New logic belongs in a new file; focused shared-function RED/GREEN test must count flag RMWs and verify queue/page state. Must verify failure paths and concurrency before implementation acceptance. + +Next: inspect all full-bit writers and ownership preconditions, build shared structural test RED on generic removal, then implement and inspect optimized code. Existing timings cannot predict any gain; original declared perf campaign remains required for a new candidate. diff --git a/.github/assets/perf-614/v7-validation-attribution.md b/.github/assets/perf-614/v7-validation-attribution.md new file mode 100644 index 00000000..2bc5774f --- /dev/null +++ b/.github/assets/perf-614/v7-validation-attribution.md @@ -0,0 +1,11 @@ +# V7 validation attribution + +Candidate purge test: 34 pass, 1 pacing failure (6 discards vs 0). Baseline matched build passes. No unchanged candidate rerun. + +Additional source/log evidence: MI_DIAGNOSTICS=1 in actual candidate compiler flags. Event counter implementation is unsampled monotonic atomic counts; print omits zero values. No test event resets and no production reset callers. Both final candidate and baseline event lines omit large_repurpose, meaning zero successful repurposes in those processes. MI_EVENT_LARGE_REPURPOSE occurs before the specialized removal call. Thus candidate specialization was not executed by this failing suite; this does not prove a test-only bug or waive the pacing assertion. Generic removal source is unchanged except extraction and a macro resolving to the exact original setter in production. + +The test computes global discard-count change around thread C. Other threads including the scavenger remain enabled; it does not attribute the discards to C. This is a potential attribution defect, not yet proven root cause. A diagnostic should identify the discarding thread and reason before changing the assertion or allocator. + +Secure C++ compile error is independently reproduced against frozen baseline identical purge test source and flags. A narrow compile repair would move initialized locals before reachable goto edges without changing checks. + +Rule7 stop on optimization work and measurement remains in effect. Asked owner whether to expand work order to diagnose/fix validation blockers. No new approval inferred from elapsed time. diff --git a/.github/assets/perf-614/v7-validation-evidence-digest.json b/.github/assets/perf-614/v7-validation-evidence-digest.json new file mode 100644 index 00000000..070cff00 --- /dev/null +++ b/.github/assets/perf-614/v7-validation-evidence-digest.json @@ -0,0 +1,5 @@ +{ + "sha256": "c1a9c4ff57f1694031ed38aeee4b1e1dc9f9f05802fe925b76afe642d06465e1", + "bytes": 4864167, + "members": 46 +} diff --git a/.github/assets/perf-614/v7-validation-evidence.zip b/.github/assets/perf-614/v7-validation-evidence.zip new file mode 100644 index 00000000..9e1b5a08 Binary files /dev/null and b/.github/assets/perf-614/v7-validation-evidence.zip differ diff --git a/CMakeLists.txt b/CMakeLists.txt index a41921ec..1fb8cea1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1574,6 +1574,11 @@ if (MI_BUILD_TESTS) add_test(NAME test-reserved-page-reuse-off COMMAND mimalloc-test-purge-holes --serial-reserve-reuse) set_tests_properties(test-reserved-page-reuse-off PROPERTIES TIMEOUT 600 ENVIRONMENT "MIMALLOC_SCAVENGER=0;MIMALLOC_PURGE_HOLES=0") + # #618: the #478 owner-side pacing case counts process-wide discards, so a background + # scavenger sweep during the measured thread's life polluted it. Fresh process, no scanner. + add_test(NAME test-new-thread-pacing COMMAND mimalloc-test-purge-holes --new-thread-pacing) + set_tests_properties(test-new-thread-pacing PROPERTIES TIMEOUT 600 + ENVIRONMENT "MIMALLOC_SCAVENGER=0;MIMALLOC_PURGE_HOLES=1") endif() # test-purge-zero: imported from oven-sh/mimalloc @ 942b8342, MIT (issue #272 / diff --git a/rust/mimalloc-pprof/vendor/mimalloc-pprof-amalgamated.c b/rust/mimalloc-pprof/vendor/mimalloc-pprof-amalgamated.c index e769e8f6..a6f9d658 100644 --- a/rust/mimalloc-pprof/vendor/mimalloc-pprof-amalgamated.c +++ b/rust/mimalloc-pprof/vendor/mimalloc-pprof-amalgamated.c @@ -1,4 +1,4 @@ -/* GENERATED FILE -- DO NOT EDIT. Produced by rust/xtask from commit 52eab5b3 of src/static.c. Regenerate with: cargo run -p xtask -- amalgamate-c */ +/* GENERATED FILE -- DO NOT EDIT. Produced by rust/xtask from commit bd05be78 of src/static.c. Regenerate with: cargo run -p xtask -- amalgamate-c */ /* ---- begin inlined: src/static.c ---- */ /* ---------------------------------------------------------------------------- @@ -25029,6 +25029,15 @@ static bool mi_page_queue_is_empty(mi_page_queue_t* queue) { } */ +/* ---- begin inlined: src/page-queue-remove.h ---- */ +/* Queue removal shared with its focused work-count test. Included after the + queue predicates and direct-cache updater in page-queue.c. */ +#ifndef MI_PAGE_QUEUE_REMOVE_H +#define MI_PAGE_QUEUE_REMOVE_H +#ifndef MI_PAGE_QUEUE_SET_IN_FULL +#define MI_PAGE_QUEUE_SET_IN_FULL mi_page_set_in_full +#endif + static void mi_page_queue_remove(mi_page_queue_t* queue, mi_page_t* page) { mi_assert_internal(page != NULL); mi_assert_expensive(mi_page_queue_contains(queue, page)); @@ -25051,10 +25060,37 @@ static void mi_page_queue_remove(mi_page_queue_t* queue, mi_page_t* page) { queue->count--; page->next = NULL; page->prev = NULL; - mi_page_set_in_full(page,false); + MI_PAGE_QUEUE_SET_IN_FULL(page,false); } +#if MI_LARGE_REPURPOSE +static void mi_page_queue_remove_retired(mi_theap_t* theap, mi_page_queue_t* queue, mi_page_t* page) { + // Selection proved a retired singleton in a normal large bin. Unpublication + // has completed before this call; only the owner can change its queue/full bit. + // The generic remover's full-bit clear is a redundant atomic RMW here. + MI_UNUSED(page); + MI_GATE_ASSERT_HELD(theap); + mi_assert_internal(mi_page_theap(page) == theap); + mi_assert_internal(queue->first == page && queue->last == page && queue->count == 1); + mi_assert_internal(page->next == NULL && page->prev == NULL); + mi_assert_internal(queue->block_size > MI_MEDIUM_MAX_OBJ_SIZE && + queue->block_size <= MI_LARGE_MAX_OBJ_SIZE); + mi_assert_internal(queue->block_size == mi_page_block_size(page)); + mi_assert_internal(page->retire_expire != 0 && page->used == 0); + mi_assert_internal(page->retired_slot == NULL && !mi_page_is_in_full(page)); + mi_assert_internal(theap->page_count > 0); + queue->first = NULL; + queue->last = NULL; + queue->count = 0; + theap->page_count--; + // Null links, the already-clear full bit, full-size accounting and the + // direct small-page cache are unchanged, exactly as for generic removal. +} +#endif +#endif +/* ---- end inlined: src/page-queue-remove.h ---- */ + static void mi_page_queue_push(mi_theap_t* theap, mi_page_queue_t* queue, mi_page_t* page) { MI_GATE_ASSERT_HELD(theap); // #366: owner-private leaf (docs/purge-all-implementation.md §5.2) mi_assert_internal(mi_page_theap(page) == theap); @@ -25782,7 +25818,7 @@ static mi_page_t* mi_page_repurpose_retired(mi_theap_t* theap, mi_page_queue_t* mi_assert_internal(mi_page_all_free(page) && mi_page_is_owned(page) && !mi_page_is_abandoned(page)); mi_assert_internal(mi_tf_block(mi_atomic_load_relaxed(&page->xthread_free)) == NULL); mi_assert_internal(mi_page_theap(page) == theap); - mi_page_queue_remove(best_pq, page); + mi_page_queue_remove_retired(theap, best_pq, page); mi_theap_stat_decrease(theap, page_bins[_mi_page_stats_bin(page)], 1); page->retire_expire = 0; page->retired_at = 0; @@ -27774,6 +27810,9 @@ static void mi_page_discard_slack(mi_page_t* page) { const size_t os_size = _mi_os_page_size(); uint8_t* const pstart = mi_page_start(page); uint8_t* hi = mi_page_slice_start(page) + page->memid.mem.arena.slice_count * MI_ARENA_SLICE_SIZE; + #if MI_SECURE>=5 + hi -= _mi_os_secure_guard_page_size(); // #618: the trailing guard page is PROT_NONE, never slack + #endif const size_t committed = mi_page_slice_committed(page); // 0: the whole page is committed if (committed > 0 && hi > mi_page_slice_start(page) + committed) { hi = mi_page_slice_start(page) + committed; } // never beyond what is committed const uintptr_t lo = _mi_align_up((uintptr_t)pstart + (size_t)page->reserved * mi_page_block_size(page), os_size); diff --git a/src/page-holes.c b/src/page-holes.c index 7b429ba0..1a58b414 100644 --- a/src/page-holes.c +++ b/src/page-holes.c @@ -551,6 +551,9 @@ static void mi_page_discard_slack(mi_page_t* page) { const size_t os_size = _mi_os_page_size(); uint8_t* const pstart = mi_page_start(page); uint8_t* hi = mi_page_slice_start(page) + page->memid.mem.arena.slice_count * MI_ARENA_SLICE_SIZE; + #if MI_SECURE>=5 + hi -= _mi_os_secure_guard_page_size(); // #618: the trailing guard page is PROT_NONE, never slack + #endif const size_t committed = mi_page_slice_committed(page); // 0: the whole page is committed if (committed > 0 && hi > mi_page_slice_start(page) + committed) { hi = mi_page_slice_start(page) + committed; } // never beyond what is committed const uintptr_t lo = _mi_align_up((uintptr_t)pstart + (size_t)page->reserved * mi_page_block_size(page), os_size); diff --git a/src/page-queue-remove.h b/src/page-queue-remove.h new file mode 100644 index 00000000..8d243df0 --- /dev/null +++ b/src/page-queue-remove.h @@ -0,0 +1,59 @@ +/* Queue removal shared with its focused work-count test. Included after the + queue predicates and direct-cache updater in page-queue.c. */ +#ifndef MI_PAGE_QUEUE_REMOVE_H +#define MI_PAGE_QUEUE_REMOVE_H +#ifndef MI_PAGE_QUEUE_SET_IN_FULL +#define MI_PAGE_QUEUE_SET_IN_FULL mi_page_set_in_full +#endif + +static void mi_page_queue_remove(mi_page_queue_t* queue, mi_page_t* page) { + mi_assert_internal(page != NULL); + mi_assert_expensive(mi_page_queue_contains(queue, page)); + mi_assert_internal(queue->count >= 1); + mi_assert_internal(mi_page_block_size(page) == queue->block_size || + (mi_page_is_huge(page) && mi_page_queue_is_huge(queue)) || + (mi_page_is_in_full(page) && mi_page_queue_is_full(queue))); + mi_theap_t* theap = mi_page_theap(page); + MI_GATE_ASSERT_HELD(theap); // #366: owner-private leaf (docs/purge-all-implementation.md §5.2) + if (page->prev != NULL) page->prev->next = page->next; + if (page->next != NULL) page->next->prev = page->prev; + if (page == queue->last) queue->last = page->prev; + if (page == queue->first) { + queue->first = page->next; + // update first + mi_assert_internal(mi_theap_contains_queue(theap, queue)); + mi_theap_queue_first_update(theap,queue); + } + theap->page_count--; + queue->count--; + page->next = NULL; + page->prev = NULL; + MI_PAGE_QUEUE_SET_IN_FULL(page,false); +} + + +#if MI_LARGE_REPURPOSE +static void mi_page_queue_remove_retired(mi_theap_t* theap, mi_page_queue_t* queue, mi_page_t* page) { + // Selection proved a retired singleton in a normal large bin. Unpublication + // has completed before this call; only the owner can change its queue/full bit. + // The generic remover's full-bit clear is a redundant atomic RMW here. + MI_UNUSED(page); + MI_GATE_ASSERT_HELD(theap); + mi_assert_internal(mi_page_theap(page) == theap); + mi_assert_internal(queue->first == page && queue->last == page && queue->count == 1); + mi_assert_internal(page->next == NULL && page->prev == NULL); + mi_assert_internal(queue->block_size > MI_MEDIUM_MAX_OBJ_SIZE && + queue->block_size <= MI_LARGE_MAX_OBJ_SIZE); + mi_assert_internal(queue->block_size == mi_page_block_size(page)); + mi_assert_internal(page->retire_expire != 0 && page->used == 0); + mi_assert_internal(page->retired_slot == NULL && !mi_page_is_in_full(page)); + mi_assert_internal(theap->page_count > 0); + queue->first = NULL; + queue->last = NULL; + queue->count = 0; + theap->page_count--; + // Null links, the already-clear full bit, full-size accounting and the + // direct small-page cache are unchanged, exactly as for generic removal. +} +#endif +#endif diff --git a/src/page-queue.c b/src/page-queue.c index f259e7e1..1e8478d2 100644 --- a/src/page-queue.c +++ b/src/page-queue.c @@ -306,31 +306,7 @@ static bool mi_page_queue_is_empty(mi_page_queue_t* queue) { } */ -static void mi_page_queue_remove(mi_page_queue_t* queue, mi_page_t* page) { - mi_assert_internal(page != NULL); - mi_assert_expensive(mi_page_queue_contains(queue, page)); - mi_assert_internal(queue->count >= 1); - mi_assert_internal(mi_page_block_size(page) == queue->block_size || - (mi_page_is_huge(page) && mi_page_queue_is_huge(queue)) || - (mi_page_is_in_full(page) && mi_page_queue_is_full(queue))); - mi_theap_t* theap = mi_page_theap(page); - MI_GATE_ASSERT_HELD(theap); // #366: owner-private leaf (docs/purge-all-implementation.md §5.2) - if (page->prev != NULL) page->prev->next = page->next; - if (page->next != NULL) page->next->prev = page->prev; - if (page == queue->last) queue->last = page->prev; - if (page == queue->first) { - queue->first = page->next; - // update first - mi_assert_internal(mi_theap_contains_queue(theap, queue)); - mi_theap_queue_first_update(theap,queue); - } - theap->page_count--; - queue->count--; - page->next = NULL; - page->prev = NULL; - mi_page_set_in_full(page,false); -} - +#include "page-queue-remove.h" static void mi_page_queue_push(mi_theap_t* theap, mi_page_queue_t* queue, mi_page_t* page) { MI_GATE_ASSERT_HELD(theap); // #366: owner-private leaf (docs/purge-all-implementation.md §5.2) diff --git a/src/page.c b/src/page.c index e688396b..92186a28 100644 --- a/src/page.c +++ b/src/page.c @@ -600,7 +600,7 @@ static mi_page_t* mi_page_repurpose_retired(mi_theap_t* theap, mi_page_queue_t* mi_assert_internal(mi_page_all_free(page) && mi_page_is_owned(page) && !mi_page_is_abandoned(page)); mi_assert_internal(mi_tf_block(mi_atomic_load_relaxed(&page->xthread_free)) == NULL); mi_assert_internal(mi_page_theap(page) == theap); - mi_page_queue_remove(best_pq, page); + mi_page_queue_remove_retired(theap, best_pq, page); mi_theap_stat_decrease(theap, page_bins[_mi_page_stats_bin(page)], 1); page->retire_expire = 0; page->retired_at = 0; diff --git a/test/retired-queue-remove.h b/test/retired-queue-remove.h new file mode 100644 index 00000000..db723653 --- /dev/null +++ b/test/retired-queue-remove.h @@ -0,0 +1,85 @@ +/* #614: run the production queue-removal body with counted flag writes. + These predicates model the synthetic queues; no allocator queue is modified. */ +#ifndef MI_TEST_RETIRED_QUEUE_REMOVE_H +#define MI_TEST_RETIRED_QUEUE_REMOVE_H +#if MI_LARGE_REPURPOSE +static size_t retired_queue_flag_writes; +static void retired_queue_set_in_full(mi_page_t* page, bool value) { + retired_queue_flag_writes++; + mi_page_set_in_full(page, value); +} +// Maybe unused: these predicates appear only in debug assertions in the shared body. +MI_DECL_MAYBE_UNUSED static bool mi_page_queue_contains(const mi_page_queue_t* q, const mi_page_t* p) { + for (const mi_page_t* it = q->first; it != NULL; it = it->next) if (it == p) return true; + return false; +} +MI_DECL_MAYBE_UNUSED static bool mi_theap_contains_queue(const mi_theap_t* t, const mi_page_queue_t* q) { + return q >= &t->pages[0] && q <= &t->pages[MI_BIN_FULL]; +} +MI_DECL_MAYBE_UNUSED static bool mi_page_queue_is_huge(const mi_page_queue_t* q) { + return q->block_size == MI_LARGE_MAX_OBJ_SIZE + sizeof(uintptr_t); +} +MI_DECL_MAYBE_UNUSED static bool mi_page_queue_is_full(const mi_page_queue_t* q) { + return q->block_size == MI_LARGE_MAX_OBJ_SIZE + 2 * sizeof(uintptr_t); +} +static void mi_theap_queue_first_update(mi_theap_t* t, const mi_page_queue_t* q) { + MI_UNUSED(t); + // The real updater returns immediately for every large queue tested here. + assert(q->block_size > MI_SMALL_SIZE_MAX); +} +#define MI_PAGE_QUEUE_SET_IN_FULL retired_queue_set_in_full +#include "../src/page-queue-remove.h" +#undef MI_PAGE_QUEUE_SET_IN_FULL + +static void case_retired_queue_remove(void) { + mi_theap_t* real = mi_theap_get_default(); + MI_GATE_ENTER(real); + for (size_t flag = 0; flag <= MI_PAGE_HAS_INTERIOR_POINTERS; flag += MI_PAGE_HAS_INTERIOR_POINTERS) { + mi_theap_t owner; + mi_page_t page; + memset(&owner, 0, sizeof(owner)); + memset(&page, 0, sizeof(page)); + owner.tld = real->tld; + mi_atomic_store_ptr_relaxed(mi_heap_t, &owner.heap, _mi_theap_heap(real)); + owner.page_count = 2; + owner.pages_full_size = SIZE_A; + const size_t bin = _mi_bin(SIZE_A); + mi_page_queue_t* q = &owner.pages[bin]; + q->first = q->last = &page; q->count = 1; q->block_size = SIZE_A; + page.theap = &owner; page.block_size = SIZE_A; + page.retire_expire = 1; + mi_atomic_store_relaxed(&page.xthread_id, _mi_thread_id() | flag); + const mi_threadid_t before = mi_atomic_load_relaxed(&page.xthread_id); + retired_queue_flag_writes = 0; + mi_page_queue_remove_retired(&owner, q, &page); + CHECK(q->first == NULL && q->last == NULL && q->count == 0 && q->block_size == SIZE_A, + "retired removal must empty only the selected queue"); + CHECK(owner.page_count == 1 && owner.pages_full_size == SIZE_A, + "retired removal must preserve full-page accounting"); + CHECK(page.next == NULL && page.prev == NULL && page.theap == &owner && + mi_atomic_load_relaxed(&page.xthread_id) == before, + "retired removal must preserve page links, owner and flags"); + for (size_t i = 0; i <= MI_BIN_FULL; i++) if (i != bin) { + CHECK(owner.pages[i].first == NULL && owner.pages[i].last == NULL && owner.pages[i].count == 0, + "retired removal must preserve other queues"); + } + for (size_t i = 0; i < MI_PAGES_DIRECT; i++) { + CHECK(owner.pages_free_direct[i] == NULL, "retired removal must preserve direct cache"); + } + CHECK(retired_queue_flag_writes == 0, "retired removal wrote full flag %zu times, expected zero", retired_queue_flag_writes); + // Keep the original production remover as a counted control: the eliminated + // operation really is present, and its observable queue result is the same. + q->first = q->last = &page; q->count = 1; owner.page_count = 2; + retired_queue_flag_writes = 0; + mi_page_queue_remove(q, &page); + CHECK(retired_queue_flag_writes == 1 && q->first == NULL && q->last == NULL && + q->count == 0 && owner.page_count == 1 && owner.pages_full_size == SIZE_A && + mi_atomic_load_relaxed(&page.xthread_id) == before, + "generic removal control must produce the same state with one flag write"); + } + MI_GATE_LEAVE(real->tld); +} +#else +static void case_retired_queue_remove(void) { } +#endif +#endif diff --git a/test/test-large-span.c b/test/test-large-span.c index c24b1604..72380171 100644 --- a/test/test-large-span.c +++ b/test/test-large-span.c @@ -562,6 +562,7 @@ static void case_off(void) { } #include "retired-search.h" +#include "retired-queue-remove.h" int main(void) { #if !MI_ENABLE_LARGE_PAGES @@ -594,6 +595,7 @@ int main(void) { case_repurpose(); case_recarve_matrix(); case_slots(); + case_retired_queue_remove(); case_retired_search(); case_retired_search_budget(); #endif diff --git a/test/test-purge-holes.c b/test/test-purge-holes.c index 75591091..bc90ce93 100644 --- a/test/test-purge-holes.c +++ b/test/test-purge-holes.c @@ -1884,57 +1884,61 @@ static bool test_owner_sweep_pacing(void) { bool ok_all = true; const long saved = mi_option_get(mi_option_purge_holes_min_interval); - // (a) baseline: an unpaced sweep, which stamps this thread's `holes_sweep_last`. - mi_option_set(mi_option_purge_holes_min_interval, 0); - if (!pace_churn(ptrs, N, SZ)) { ok_all = false; goto done; } - mi_on_thread_idle(); - const mi_msecs_t stamped_at = _mi_clock_now(); + // Scope the measurement locals so the early `goto done`s skip their initialisation as a + // whole: valid C++ too, where this file is built under MI_USE_CXX. + { + // (a) baseline: an unpaced sweep, which stamps this thread's `holes_sweep_last`. + mi_option_set(mi_option_purge_holes_min_interval, 0); + if (!pace_churn(ptrs, N, SZ)) { ok_all = false; goto done; } + mi_on_thread_idle(); + const mi_msecs_t stamped_at = _mi_clock_now(); - // (b) inside the window: a second `mi_on_thread_idle()` must not sweep at all. - mi_option_set(mi_option_purge_holes_min_interval, PACE_INTERVAL_MS); - if (!pace_churn(ptrs, N, SZ)) { ok_all = false; goto done; } - const int64_t before_in = pace_sweep_work(); - mi_on_thread_idle(); - const int64_t after_in = pace_sweep_work(); - const mi_msecs_t elapsed = _mi_clock_now() - stamped_at; - if (elapsed >= PACE_INTERVAL_MS) { - // the churn itself outran the window (a very loaded box): the negative half is not - // decidable, say so rather than fail on the machine's timing - fprintf(stderr, "\n SKIP in-window half: churn took %ldms, window is %dms\n", - (long)elapsed, PACE_INTERVAL_MS); - } - else if (after_in != before_in) { - fprintf(stderr, "\n swept %ldms into a %dms window: sweep work %lld -> %lld\n", - (long)elapsed, PACE_INTERVAL_MS, (long long)before_in, (long long)after_in); - ok_all = false; - } + // (b) inside the window: a second `mi_on_thread_idle()` must not sweep at all. + mi_option_set(mi_option_purge_holes_min_interval, PACE_INTERVAL_MS); + if (!pace_churn(ptrs, N, SZ)) { ok_all = false; goto done; } + const int64_t before_in = pace_sweep_work(); + mi_on_thread_idle(); + const int64_t after_in = pace_sweep_work(); + const mi_msecs_t elapsed = _mi_clock_now() - stamped_at; + if (elapsed >= PACE_INTERVAL_MS) { + // the churn itself outran the window (a very loaded box): the negative half is not + // decidable, say so rather than fail on the machine's timing + fprintf(stderr, "\n SKIP in-window half: churn took %ldms, window is %dms\n", + (long)elapsed, PACE_INTERVAL_MS); + } + else if (after_in != before_in) { + fprintf(stderr, "\n swept %ldms into a %dms window: sweep work %lld -> %lld\n", + (long)elapsed, PACE_INTERVAL_MS, (long long)before_in, (long long)after_in); + ok_all = false; + } - // (c) past the window: the very next `mi_on_thread_idle()` sweeps again. The deadline has - // to EXPIRE, not merely be disabled -- so wait it out rather than setting the option to 0. - #if MI_OWNER_GATE - // #366: in a gated build this thread is PARKED for the whole wait, so the scavenger sweeps it - // as soon as the window expires -- which re-stamps `holes_sweep_last`, and the owner's own - // `mi_on_thread_idle()` below then lands INSIDE a fresh window and (correctly) does nothing. - // The contract "a sweep happens past the window" still holds; count from before the wait. - const int64_t before_out = pace_sweep_work(); - pace_sleep_ms(PACE_INTERVAL_MS + (PACE_INTERVAL_MS / 2)); - if (!pace_churn(ptrs, N, SZ)) { ok_all = false; goto done; } - #else - pace_sleep_ms(PACE_INTERVAL_MS + (PACE_INTERVAL_MS / 2)); - if (!pace_churn(ptrs, N, SZ)) { ok_all = false; goto done; } - const int64_t before_out = pace_sweep_work(); - #endif - mi_on_thread_idle(); - const int64_t after_out = pace_sweep_work(); - if (purging_enabled && after_out <= before_out) { - fprintf(stderr, "\n did not sweep %dms past a %dms window: sweep work %lld -> %lld\n", - PACE_INTERVAL_MS + (PACE_INTERVAL_MS / 2), PACE_INTERVAL_MS, - (long long)before_out, (long long)after_out); - ok_all = false; + // (c) past the window: the very next `mi_on_thread_idle()` sweeps again. The deadline has + // to EXPIRE, not merely be disabled -- so wait it out rather than setting the option to 0. + #if MI_OWNER_GATE + // #366: in a gated build this thread is PARKED for the whole wait, so the scavenger sweeps it + // as soon as the window expires -- which re-stamps `holes_sweep_last`, and the owner's own + // `mi_on_thread_idle()` below then lands INSIDE a fresh window and (correctly) does nothing. + // The contract "a sweep happens past the window" still holds; count from before the wait. + const int64_t before_out = pace_sweep_work(); + pace_sleep_ms(PACE_INTERVAL_MS + (PACE_INTERVAL_MS / 2)); + if (!pace_churn(ptrs, N, SZ)) { ok_all = false; goto done; } + #else + pace_sleep_ms(PACE_INTERVAL_MS + (PACE_INTERVAL_MS / 2)); + if (!pace_churn(ptrs, N, SZ)) { ok_all = false; goto done; } + const int64_t before_out = pace_sweep_work(); + #endif + mi_on_thread_idle(); + const int64_t after_out = pace_sweep_work(); + if (purging_enabled && after_out <= before_out) { + fprintf(stderr, "\n did not sweep %dms past a %dms window: sweep work %lld -> %lld\n", + PACE_INTERVAL_MS + (PACE_INTERVAL_MS / 2), PACE_INTERVAL_MS, + (long long)before_out, (long long)after_out); + ok_all = false; + } + // with `purge_holes=0` there is no hole phase to count, so (c) has no observable -- the + // stamp still runs (see `_mi_purge_holes_of`), which is what keeps the scavenger's own + // pacing identical in the two builds. } - // with `purge_holes=0` there is no hole phase to count, so (c) has no observable -- the - // stamp still runs (see `_mi_purge_holes_of`), which is what keeps the scavenger's own - // pacing identical in the two builds. done: for (size_t i = 0; i < N; i++) { if (ptrs[i] != NULL) mi_free(ptrs[i]); } @@ -2239,8 +2243,21 @@ int main(int argc, char** argv) { CHECK("dead-thread-page-is-reused", test_dead_thread_page_is_reused()); return print_test_summary(); } + if (argc == 2 && strcmp(argv[1], "--new-thread-pacing") == 0) { + // #618: the case counts PROCESS-wide discards around thread C, so a background sweep + // of A's abandoned page during C's life was charged to C (reproduced under load on the + // frozen baseline too; 0 of 144 loaded runs failed with the scavenger off). #478 is about + // the OWNER's first tick, so measure it in its own process with no scanner started; the + // background release cases keep running with it enabled in the default invocation. + CHECK("new-thread-pacing-scavenger-disabled", + !mi_option_is_enabled(mi_option_scavenger) && !_mi_scavenger_is_running()); + if (failed != 0) return print_test_summary(); + purging_enabled = mi_option_is_enabled(mi_option_purge_holes); + CHECK("new-thread-does-not-sweep-at-once", test_new_thread_does_not_sweep_at_once()); + return print_test_summary(); + } if (argc != 1) { - fprintf(stderr, "usage: %s [--serial-reserve-reuse]\n", argv[0]); + fprintf(stderr, "usage: %s [--serial-reserve-reuse | --new-thread-pacing]\n", argv[0]); return EXIT_FAILURE; } purging_enabled = mi_option_is_enabled(mi_option_purge_holes); @@ -2310,7 +2327,6 @@ int main(int argc, char** argv) { CHECK("sweep-does-not-unpurge-on-collect", test_sweep_no_unpurge_on_collect()); CHECK("sweep-full-every-bounds-a-missed-hole", test_sweep_full_every()); CHECK("owner-sweeps-are-paced", test_owner_sweep_pacing()); - CHECK("new-thread-does-not-sweep-at-once", test_new_thread_does_not_sweep_at_once()); #if !defined(_WIN32) CHECK("idle-thread-releases-large-page", test_idle_thread_releases_large_page()); CHECK("reserved-page-is-released", test_reserved_page_is_released());