Page MenuHomeFreeBSD

hwpmc: fix leak of IBS per-CPU array on unload
ClosedPublic

Authored by paulo_nlink.com.br on Tue, Sep 22, 1:34 AM.
Tags
None
Referenced Files
F173789237: D59881.id187367.diff
Mon, Sep 28, 10:41 AM
F173782994: D59881.id187403.diff
Mon, Sep 28, 9:19 AM
F173745333: D59881.diff
Mon, Sep 28, 2:23 AM
F173697586: D59881.id187367.diff
Sun, Sep 27, 7:33 PM
Unknown Object (File)
Sun, Sep 27, 12:44 AM
Unknown Object (File)
Sat, Sep 26, 6:52 PM
Unknown Object (File)
Sat, Sep 26, 9:39 AM
Unknown Object (File)
Thu, Sep 24, 12:55 PM
Subscribers

Details

Summary

pmc_ibs_initialize() allocates the ibs_pcpu[] pointer array, and
pmc_ibs_finalize() exists to free it, but pmc_ibs_finalize() is
never called. Every hwpmc unload on a CPU with IBS therefore leaks
one pmc_cpu_max()-sized pointer array.

Call pmc_ibs_finalize() from pmc_amd_finalize(), alongside the RAPL,
TSC and perf classes. IBS is only initialized on CPUs that support
it, so make pmc_ibs_finalize() return early when ibs_pcpu is NULL,
making it safe to call when the class was skipped at initialize
time, as pmc_rapl_finalize() already is.

Tested on an AMD Ryzen 5 5600X (Zen 3, 12 threads) with INVARIANTS.
Before the change, each kldload/kldunload cycle leaked one 96-byte
M_PMC allocation, and DTrace showed the ibs_pcpu[] allocation from
pmc_ibs_initialize() as the only one never freed. After the change,
50 load/unload cycles leave M_PMC InUse and MemUse unchanged, and
every allocation made at load is freed at unload.

Sponsored by: NLINK (https://nlink.com.br), Recife, Brazil
Fixes: e51ef8ae490f ("hwpmc: Initial support for AMD IBS")

Test Plan

Hardware: AMD Ryzen 5 5600X (Zen 3, Family 19h, 12 threads),
FreeBSD 16.0-CURRENT GENERIC (INVARIANTS enabled).

  1. Memory accounting over 50 kldunload/kldload cycles:

    Before: vmstat -m "pmc" InUse +50, MemUse +6400 bytes (one 96-byte allocation, 128-byte bucket, per cycle) After: InUse and MemUse unchanged

    The leak reproduces identically with and without 8a0cab240f21, so it predates the recent pmcdesc allocation change.
  1. DTrace, tracking every 65-128 byte M_PMC allocation across load / unload / load and matching each pointer to its free():

    Before: 7 allocations at first load, 6 freed at unload; the unfreed one comes from pmc_ibs_initialize+0x25 After: 7 allocations, 7 freed
  1. No KASSERT fired across the 50 unloads, so per-CPU teardown runs before pmc_ibs_finalize() as expected.

Not tested: the early-return path on AMD CPUs without IBS. It is
correct by inspection (ibs_pcpu stays NULL when IBS is not
initialized) and mirrors pmc_rapl_finalize().

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Not Applicable
Unit
Tests Not Applicable