Skip to content

feat(major): [sc-23696] replace jemalloc dependency with custom malloc interposer#333

Open
supersonicbyte wants to merge 43 commits into
mainfrom
feature/sc-23696/replace-jemalloc-dependency-with-custom
Open

feat(major): [sc-23696] replace jemalloc dependency with custom malloc interposer#333
supersonicbyte wants to merge 43 commits into
mainfrom
feature/sc-23696/replace-jemalloc-dependency-with-custom

Conversation

@supersonicbyte

Copy link
Copy Markdown
Contributor

Description

This PR replaces jemalloc with a custom malloc interposer. The interposer logic is mostly inspired by the great work done by the swift-nio team.

On macOS/Darwin we ulitise the interposing feature of dydl while on Linux we use LD_PRELOAD in order to interpose.

The interposition logic is written in C and located in the MallocInterposerC package.

For actual interaction with the interposition is done through a wrapper package MallocInterposerSwift, which exposes a simple interface to hook and unhook the interposition logic and also to actually count the statistics we need.

The interposition requirers the the interposer library to be linked dynamically, since that's crucial to the nature of how the interposition works (both on Linux and Darwin). The SwiftPM Command plugin BenchmarkCommandPlugin has a dependency on Benchmark which has a dependency on the interposer libs. This causes a problem for SwiftPM and intitial tiggers of swift package benchmark command will fail.
The issue is described in more detail here.

The current workaround is to trigger the swift package benchmark command once and let it fail. Then to copy the libMallocInterposerC-tool.dylib and libMallocInterposerSwift-tool.dylib and name them without the -tool suffix.

e.g.

cp .build/arm64-apple-macosx/debug/libMallocInterposerC-tool.dylib .build/arm64-apple-macosx/debug/libMallocInterposerC.dylib
cp .build/arm64-apple-macosx/debug/libMallocInterposerSwift-tool.dylib .build/arm64-apple-macosx/debug/libMallocInterposerSwift.dylib

The same applies for Linux but the build location will be different and the dynamic library extension is .so.

Since jemalloc is removed the mallocSmall and mallocLarge metrics are removed. New metrics mallocByteCount and freeTotalCount are introducted.

How Has This Been Tested?

When running the test the executable is being linked statically to the test target. I didn't discover a way yet to dynamically link the interposer in order for it to work inside tests.

Minimal checklist:

  • I have performed a self-review of my own code
  • I have added DocC code-level documentation for any public interfaces exported by the package
  • I have added unit and/or integration tests that prove my fix is effective or that my feature works

@supersonicbyte supersonicbyte requested a review from hassila August 28, 2025 12:55

@hassila hassila left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some initial feedback, will ping you offline about the initial bootstrap problem...

Comment thread Sources/Benchmark/BenchmarkMetric.swift Outdated
Comment thread Benchmarks/Benchmarks/Basic/BenchmarkRunner+Basic.swift
Comment thread LocalPackages/MallocInterposerC/Sources/MallocInterposerC/include/interposer.h Outdated
Comment thread LocalPackages/MallocInterposerC/Package.swift Outdated
Comment thread Sources/Benchmark/BenchmarkExecutor.swift Outdated
Comment thread Sources/Benchmark/BenchmarkExecutor.swift Outdated
@hassila

hassila commented Sep 1, 2025

Copy link
Copy Markdown
Contributor

Also I see a difference in which metrics are output between main and this branch, e.g. :

Main:

Parameterized (count: 4)
╒═════════════════════════════════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╕
│ Metric                              │        p0 │       p25 │       p50 │       p75 │       p90 │       p99 │      p100 │   Samples │
╞═════════════════════════════════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╡
│ Instructions *                      │      2996 │      2997 │      2997 │      2997 │      5579 │      5579 │     39480 │     59765 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc (total) *                    │         0 │         0 │         0 │         0 │         0 │         0 │         0 │     59765 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory (resident peak) (M)          │        11 │        11 │        11 │        11 │        11 │        11 │        11 │     59765 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Throughput (# / s) (K)              │      2667 │      2185 │      2185 │      2179 │      1601 │      1500 │        46 │     59765 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Time (total CPU) (ns) *             │      1541 │      1625 │      1667 │      1708 │      1833 │      2042 │     18333 │     59765 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Time (wall clock) (ns) *            │       375 │       458 │       458 │       459 │       625 │       667 │     21708 │     59765 │
╘═════════════════════════════════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╛

this PR:

Parameterized (count: 4)
╒═════════════════════════════════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╕
│ Metric                              │        p0 │       p25 │       p50 │       p75 │       p90 │       p99 │      p100 │   Samples │
╞═════════════════════════════════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╡
│ Free (total)                        │         0 │         0 │         0 │         0 │         0 │         0 │         0 │    353057 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Instructions *                      │      2998 │      2999 │      2999 │      2999 │      5583 │      5583 │     37135 │    353057 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc (bytes total)                │         0 │         0 │         0 │         0 │         0 │         0 │         0 │    353057 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc (total) *                    │         0 │         0 │         0 │         0 │         0 │         0 │         0 │    353057 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc / free Δ *                   │         0 │         0 │         0 │         0 │         0 │         0 │         0 │    353057 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory (resident peak) (M)          │        12 │        13 │        13 │        13 │        13 │        13 │        13 │    353057 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Throughput (# / s) (K)              │      2667 │      2398 │      2185 │      2179 │      1716 │      1601 │        41 │    353057 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Time (total CPU) (ns) *             │      1375 │      1500 │      1542 │      1583 │      1667 │      1833 │     25750 │    353057 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Time (wall clock) (ns) *            │       375 │       417 │       458 │       459 │       583 │       625 │     24625 │    353057 │
╘═════════════════════════════════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╛

Got some additional malloc related metrics there, would be good to understand root cause.

@hassila

hassila commented Sep 1, 2025

Copy link
Copy Markdown
Contributor

(that was from running swift package benchmark in the Benchmarks subdirectory)

@hassila

hassila commented Sep 1, 2025

Copy link
Copy Markdown
Contributor

Also one issue when testing with package-benchmarks-samples repo with lost capture of allocation:

Main gives:

=============
Miscellaneous
=============

Memory leak 1 allocation of 1K
╒═════════════════════════════════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╕
│ Metric                              │        p0 │       p25 │       p50 │       p75 │       p90 │       p99 │      p100 │   Samples │
╞═════════════════════════════════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╡
│ (Alloc + Retain) - Release Δ *      │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc (large) *                    │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc (small) *                    │         1 │         1 │         1 │         1 │         1 │         1 │         1 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc (total) *                    │         1 │         1 │         1 │         1 │         1 │         1 │         1 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc / free Δ *                   │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory (allocated resident) (K)     │      9552 │      9552 │      9552 │      9552 │      9552 │      9552 │      9552 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory (resident peak) (K)          │      9765 │      9765 │      9765 │      9765 │      9765 │      9765 │      9765 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory (virtual peak) (G)           │       420 │       420 │       420 │       420 │       420 │       420 │       420 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory Δ (resident peak)            │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Object allocs *                     │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Releases *                          │         2 │         2 │         2 │         2 │         2 │         2 │         2 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Retains *                           │         2 │         2 │         2 │         2 │         2 │         2 │         2 │         1 │
╘═════════════════════════════════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╛

PR:

Memory leak 1 allocation of 1K
╒═════════════════════════════════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╕
│ Metric                              │        p0 │       p25 │       p50 │       p75 │       p90 │       p99 │      p100 │   Samples │
╞═════════════════════════════════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╡
│ (Alloc + Retain) - Release Δ *      │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc (bytes total)                │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc (total) *                    │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc / free Δ *                   │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory (resident peak) (M)          │        11 │        11 │        11 │        11 │        11 │        11 │        11 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory (virtual peak) (G)           │       421 │       421 │       421 │       421 │       421 │       421 │       421 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory Δ (resident peak)            │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Object allocs *                     │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Releases *                          │         2 │         2 │         2 │         2 │         2 │         2 │         2 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Retains *                           │         2 │         2 │         2 │         2 │         2 │         2 │         2 │         1 │
╘═════════════════════════════════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╛

@hassila

hassila commented Sep 1, 2025

Copy link
Copy Markdown
Contributor

(Memory (allocated resident) (K) was missing from the PR output too?)

@hassila

hassila commented Sep 1, 2025

Copy link
Copy Markdown
Contributor

This test also misses capture:
Main:

Memory leak 123 allocations of 4K - performAllocationsMutablePointer
╒═════════════════════════════════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╕
│ Metric                              │        p0 │       p25 │       p50 │       p75 │       p90 │       p99 │      p100 │   Samples │
╞═════════════════════════════════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╡
│ (Alloc + Retain) - Release Δ *      │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc (large) *                    │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc (small) *                    │       123 │       123 │       123 │       123 │       123 │       123 │       123 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc (total) *                    │       123 │       123 │       123 │       123 │       123 │       123 │       123 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc / free Δ (K) *               │      3817 │      3817 │      3817 │      3817 │      3817 │      3817 │      3817 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory (allocated resident) (M)     │        18 │        18 │        18 │        18 │        18 │        18 │        18 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory (resident peak) (K)          │      9847 │      9847 │      9847 │      9847 │      9847 │      9847 │      9847 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory (virtual peak) (G)           │       420 │       420 │       420 │       420 │       420 │       420 │       420 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory Δ (resident peak)            │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Object allocs *                     │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Releases *                          │         2 │         2 │         2 │         2 │         2 │         2 │         2 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Retains *                           │         2 │         2 │         2 │         2 │         2 │         2 │         2 │         1 │
╘═════════════════════════════════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╛

PR:

Memory leak 123 allocations of 4K - performAllocationsMutablePointer
╒═════════════════════════════════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╕
│ Metric                              │        p0 │       p25 │       p50 │       p75 │       p90 │       p99 │      p100 │   Samples │
╞═════════════════════════════════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╡
│ (Alloc + Retain) - Release Δ *      │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc (bytes total)                │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc (total) *                    │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc / free Δ *                   │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory (resident peak) (M)          │        11 │        11 │        11 │        11 │        11 │        11 │        11 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory (virtual peak) (G)           │       421 │       421 │       421 │       421 │       421 │       421 │       421 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory Δ (resident peak)            │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Object allocs *                     │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Releases *                          │         2 │         2 │         2 │         2 │         2 │         2 │         2 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Retains *                           │         2 │         2 │         2 │         2 │         2 │         2 │         2 │         1 │
╘═════════════════════════════════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╛

@hassila

hassila commented Sep 1, 2025

Copy link
Copy Markdown
Contributor

And this test should show a leak, but does not on the PR:
Main:

Memory transient allocations + 1 large leak
╒═════════════════════════════════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╕
│ Metric                              │        p0 │       p25 │       p50 │       p75 │       p90 │       p99 │      p100 │   Samples │
╞═════════════════════════════════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╡
│ (Alloc + Retain) - Release Δ *      │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc (large) *                    │         1 │         1 │         1 │         1 │         1 │         1 │         1 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc (small) *                    │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc (total) *                    │         1 │         1 │         1 │         1 │         1 │         1 │         1 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc / free Δ (K) *               │        34 │        34 │        34 │        34 │        34 │        34 │        34 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory (allocated resident) (M)     │        77 │        77 │        77 │        77 │        77 │        77 │        77 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory (resident peak) (K)          │      9847 │      9847 │      9847 │      9847 │      9847 │      9847 │      9847 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory (virtual peak) (G)           │       421 │       421 │       421 │       421 │       421 │       421 │       421 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory Δ (resident peak)            │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Object allocs *                     │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Releases *                          │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Retains *                           │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
╘═════════════════════════════════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╛

PR:

Memory transient allocations + 1 large leak
╒═════════════════════════════════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╕
│ Metric                              │        p0 │       p25 │       p50 │       p75 │       p90 │       p99 │      p100 │   Samples │
╞═════════════════════════════════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╡
│ (Alloc + Retain) - Release Δ *      │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc (bytes total) (G)            │        12 │        12 │        12 │        12 │        12 │        12 │        12 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc (total) *                    │         1 │         1 │         1 │         1 │         1 │         1 │         1 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc / free Δ *                   │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory (resident peak) (M)          │        10 │        10 │        10 │        10 │        10 │        10 │        10 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory (virtual peak) (G)           │       421 │       421 │       421 │       421 │       421 │       421 │       421 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory Δ (resident peak)            │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Object allocs *                     │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Releases *                          │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Retains *                           │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
╘═════════════════════════════════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╛

@supersonicbyte

Copy link
Copy Markdown
Contributor Author

And this test should show a leak, but does not on the PR: Main:

Memory transient allocations + 1 large leak
╒═════════════════════════════════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╕
│ Metric                              │        p0 │       p25 │       p50 │       p75 │       p90 │       p99 │      p100 │   Samples │
╞═════════════════════════════════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╡
│ (Alloc + Retain) - Release Δ *      │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc (large) *                    │         1 │         1 │         1 │         1 │         1 │         1 │         1 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc (small) *                    │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc (total) *                    │         1 │         1 │         1 │         1 │         1 │         1 │         1 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc / free Δ (K) *               │        34 │        34 │        34 │        34 │        34 │        34 │        34 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory (allocated resident) (M)     │        77 │        77 │        77 │        77 │        77 │        77 │        77 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory (resident peak) (K)          │      9847 │      9847 │      9847 │      9847 │      9847 │      9847 │      9847 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory (virtual peak) (G)           │       421 │       421 │       421 │       421 │       421 │       421 │       421 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory Δ (resident peak)            │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Object allocs *                     │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Releases *                          │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Retains *                           │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
╘═════════════════════════════════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╛

PR:

Memory transient allocations + 1 large leak
╒═════════════════════════════════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╕
│ Metric                              │        p0 │       p25 │       p50 │       p75 │       p90 │       p99 │      p100 │   Samples │
╞═════════════════════════════════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╡
│ (Alloc + Retain) - Release Δ *      │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc (bytes total) (G)            │        12 │        12 │        12 │        12 │        12 │        12 │        12 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc (total) *                    │         1 │         1 │         1 │         1 │         1 │         1 │         1 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc / free Δ *                   │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory (resident peak) (M)          │        10 │        10 │        10 │        10 │        10 │        10 │        10 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory (virtual peak) (G)           │       421 │       421 │       421 │       421 │       421 │       421 │       421 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory Δ (resident peak)            │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Object allocs *                     │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Releases *                          │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Retains *                           │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
╘═════════════════════════════════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╛

Thanks for the feedback! That's strange will look into it..

@hassila

hassila commented Sep 1, 2025

Copy link
Copy Markdown
Contributor

This one failed to find the Malloc/free delta leak on Linux:

Memory transient allocations (1K small, 1001 large, 1M leak)
╒═════════════════════════════════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╕
│ Metric                              │        p0 │       p25 │       p50 │       p75 │       p90 │       p99 │      p100 │   Samples │
╞═════════════════════════════════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╡
│ (Alloc + Retain) - Release Δ *      │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc (bytes total) (M)            │        67 │        67 │        67 │        67 │        67 │        67 │        67 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc (total) *                    │         2 │         2 │         2 │         2 │         2 │         2 │         2 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Malloc / free Δ *                   │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory (resident peak) (M)          │        24 │        24 │        24 │        24 │        24 │        24 │        24 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory (virtual peak) (M)           │       254 │       254 │       254 │       254 │       254 │       254 │       254 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Memory Δ (resident peak)            │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Object allocs *                     │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Releases *                          │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
├─────────────────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Retains *                           │         0 │         0 │         0 │         0 │         0 │         0 │         0 │         1 │
╘═════════════════════════════════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╛

@hassila

hassila commented Sep 1, 2025

Copy link
Copy Markdown
Contributor

For Linux:

cp .build/x86_64-unknown-linux-gnu/debug/libMallocInterposerC-tool.so .build/x86_64-unknown-linux-gnu/debug/libMallocInterposerC.so
cp .build/x86_64-unknown-linux-gnu/debug/libMallocInterposerSwift-tool.so .build/x86_64-unknown-linux-gnu/debug/libMallocInterposerSwift.so

(need to rebuild in between too, so build, first copy, build, second copy, ...)

@codecov

codecov Bot commented Sep 2, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 76.39485% with 55 lines in your changes missing coverage. Please review.
✅ Project coverage is 69.49%. Comparing base (595d8db) to head (35e81f3).

Files with missing lines Patch % Lines
Sources/Benchmark/BenchmarkMetric.swift 59.26% 33 Missing ⚠️
Sources/Benchmark/BenchmarkMetric+Defaults.swift 42.42% 19 Missing ⚠️
...urces/Benchmark/BenchmarkExecutor+Extensions.swift 86.36% 3 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #333      +/-   ##
==========================================
+ Coverage   68.85%   69.49%   +0.65%     
==========================================
  Files          33       34       +1     
  Lines        3152     3245      +93     
==========================================
+ Hits         2170     2255      +85     
- Misses        982      990       +8     
Files with missing lines Coverage Δ
Sources/Benchmark/BenchmarkExecutor.swift 87.67% <100.00%> (+0.34%) ⬆️
Sources/Benchmark/BenchmarkRunner.swift 59.62% <100.00%> (+0.26%) ⬆️
Tests/BenchmarkTests/BenchmarkMetricsTests.swift 98.82% <100.00%> (+0.06%) ⬆️
Tests/BenchmarkTests/MallocStatisticsTests.swift 100.00% <100.00%> (ø)
...BenchmarkTests/OperatingSystemAndMallocTests.swift 96.77% <ø> (-0.31%) ⬇️
...urces/Benchmark/BenchmarkExecutor+Extensions.swift 76.83% <86.36%> (+6.52%) ⬆️
Sources/Benchmark/BenchmarkMetric+Defaults.swift 40.74% <42.42%> (+2.21%) ⬆️
Sources/Benchmark/BenchmarkMetric.swift 62.21% <59.26%> (+0.43%) ⬆️

... and 2 files with indirect coverage changes

Files with missing lines Coverage Δ
Sources/Benchmark/BenchmarkExecutor.swift 87.67% <100.00%> (+0.34%) ⬆️
Sources/Benchmark/BenchmarkRunner.swift 59.62% <100.00%> (+0.26%) ⬆️
Tests/BenchmarkTests/BenchmarkMetricsTests.swift 98.82% <100.00%> (+0.06%) ⬆️
Tests/BenchmarkTests/MallocStatisticsTests.swift 100.00% <100.00%> (ø)
...BenchmarkTests/OperatingSystemAndMallocTests.swift 96.77% <ø> (-0.31%) ⬇️
...urces/Benchmark/BenchmarkExecutor+Extensions.swift 76.83% <86.36%> (+6.52%) ⬆️
Sources/Benchmark/BenchmarkMetric+Defaults.swift 40.74% <42.42%> (+2.21%) ⬆️
Sources/Benchmark/BenchmarkMetric.swift 62.21% <59.26%> (+0.43%) ⬆️

... and 2 files with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 595d8db...35e81f3. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@supersonicbyte

Copy link
Copy Markdown
Contributor Author

Currently blocked by this: swiftlang/swift#87696 (comment)

Comment thread LocalPackages/MallocInterposerC/Sources/MallocInterposerC/src/interposer-unix.c Outdated
@github-actions

github-actions Bot commented Mar 10, 2026

Copy link
Copy Markdown
Contributor

@supersonicbyte

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@supersonicbyte

Copy link
Copy Markdown
Contributor Author

@claude review

@supersonicbyte supersonicbyte requested a review from hassila June 16, 2026 15:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants