Skip to content

Commit dc2de19

Browse files
committed
feat(memtrack): support tcmalloc
1 parent c8e51e0 commit dc2de19

4 files changed

Lines changed: 66 additions & 11 deletions

File tree

crates/memtrack/src/allocators/dynamic.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,25 @@ fn get_allocator_paths(lib: &AllocatorKind) -> &'static [&'static str] {
4646
// NixOS
4747
"/nix/store/*mimalloc*/lib/libmimalloc.so*",
4848
],
49+
AllocatorKind::Tcmalloc => &[
50+
// gperftools tcmalloc variants
51+
// Debian, Ubuntu: Standard Linux multiarch paths
52+
"/lib/*-linux-gnu/libtcmalloc.so*",
53+
"/lib/*-linux-gnu/libtcmalloc_minimal.so*",
54+
"/lib/*-linux-gnu/libtcmalloc_debug.so*",
55+
"/lib/*-linux-gnu/libtcmalloc_and_profiler.so*",
56+
"/usr/lib/*-linux-gnu/libtcmalloc.so*",
57+
"/usr/lib/*-linux-gnu/libtcmalloc_minimal.so*",
58+
"/usr/lib/*-linux-gnu/libtcmalloc_debug.so*",
59+
"/usr/lib/*-linux-gnu/libtcmalloc_and_profiler.so*",
60+
// RHEL, Fedora, CentOS, Arch
61+
"/lib*/libtcmalloc*.so*",
62+
"/usr/lib*/libtcmalloc*.so*",
63+
"/usr/local/lib*/libtcmalloc*.so*",
64+
// NixOS
65+
"/nix/store/*tcmalloc*/lib/libtcmalloc*.so*",
66+
"/nix/store/*gperftools*/lib/libtcmalloc*.so*",
67+
],
4968
}
5069
}
5170

crates/memtrack/src/allocators/mod.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,18 @@ pub enum AllocatorKind {
1919
Jemalloc,
2020
/// mimalloc - Microsoft's allocator
2121
Mimalloc,
22+
/// TCMalloc - Google's thread-caching malloc
23+
///
24+
/// Two variants exist:
25+
/// - **gperftools** (github.com/gperftools/gperftools): Original ~2005 release.
26+
/// Exports both standard symbols (malloc/free) AND tc_* prefixed symbols.
27+
/// - **google/tcmalloc** (github.com/google/tcmalloc): Modern ~2020 rewrite.
28+
/// Exports ONLY standard symbols (malloc/free/etc.) - no tc_* prefix.
29+
///
30+
/// We'll always try to attach to both the standard and `tc_*` API. If the newer rewrite is
31+
/// used, we'll only attach to the standard API.
32+
Tcmalloc,
2233
// Future allocators:
23-
// Tcmalloc,
2434
// Hoard,
2535
// Rpmalloc,
2636
}
@@ -33,6 +43,7 @@ impl AllocatorKind {
3343
&[
3444
AllocatorKind::Jemalloc,
3545
AllocatorKind::Mimalloc,
46+
AllocatorKind::Tcmalloc,
3647
AllocatorKind::LibCpp,
3748
AllocatorKind::Libc,
3849
]
@@ -45,23 +56,14 @@ impl AllocatorKind {
4556
AllocatorKind::LibCpp => "libc++",
4657
AllocatorKind::Jemalloc => "jemalloc",
4758
AllocatorKind::Mimalloc => "mimalloc",
59+
AllocatorKind::Tcmalloc => "tcmalloc",
4860
}
4961
}
5062

5163
/// Returns true if this allocator is required (must be found).
5264
pub fn is_required(&self) -> bool {
5365
matches!(self, AllocatorKind::Libc)
5466
}
55-
56-
/// Returns the symbol names used to detect this allocator in binaries.
57-
pub fn symbols(&self) -> &'static [&'static str] {
58-
match self {
59-
AllocatorKind::Libc => &["malloc", "free"],
60-
AllocatorKind::LibCpp => &["_Znwm", "_Znam", "_ZdlPv", "_ZdaPv"],
61-
AllocatorKind::Jemalloc => &["_rjem_malloc", "je_malloc", "je_malloc_default"],
62-
AllocatorKind::Mimalloc => &["mi_malloc_aligned", "mi_malloc", "mi_free"],
63-
}
64-
}
6567
}
6668

6769
/// Discovered allocator library with its kind and path.

crates/memtrack/src/allocators/static_linked.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,19 @@ use std::path::{Path, PathBuf};
44

55
use crate::allocators::{AllocatorKind, AllocatorLib};
66

7+
impl AllocatorKind {
8+
/// Returns the symbol names used to detect this allocator in binaries.
9+
pub fn symbols(&self) -> &'static [&'static str] {
10+
match self {
11+
AllocatorKind::Libc => &["malloc", "free"],
12+
AllocatorKind::LibCpp => &["_Znwm", "_Znam", "_ZdlPv", "_ZdaPv"],
13+
AllocatorKind::Jemalloc => &["_rjem_malloc", "je_malloc", "je_malloc_default"],
14+
AllocatorKind::Mimalloc => &["mi_malloc_aligned", "mi_malloc", "mi_free"],
15+
AllocatorKind::Tcmalloc => &["tc_malloc", "tc_free", "tc_version"],
16+
}
17+
}
18+
}
19+
720
/// Walk upward and downward from current directory to find build directories.
821
/// Returns all found build directories in order of preference.
922
fn find_build_dirs() -> Vec<PathBuf> {

crates/memtrack/src/ebpf/memtrack.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,11 @@ impl MemtrackBpf {
291291
let _ = self.attach_libcpp_probes(lib_path);
292292
self.attach_mimalloc_probes(lib_path)
293293
}
294+
AllocatorKind::Tcmalloc => {
295+
// Try C++ operators (tcmalloc exports these for C++ programs)
296+
let _ = self.attach_libcpp_probes(lib_path);
297+
self.attach_tcmalloc_probes(lib_path)
298+
}
294299
}
295300
}
296301

@@ -405,6 +410,22 @@ impl MemtrackBpf {
405410

406411
Ok(())
407412
}
413+
414+
/// Attach TCMalloc probes ( tc_* API).
415+
///
416+
/// See:
417+
/// - https://github.com/google/tcmalloc/blob/master/docs/reference.md
418+
/// - https://github.com/gperftools/gperftools/blob/a47243150ec41097602730ff8779fafcc172d1fb/src/tcmalloc.cc#L178-L190
419+
420+
fn attach_tcmalloc_probes(&mut self, lib_path: &Path) -> Result<()> {
421+
self.attach_standard_probes(lib_path, &["tc_"], &[])?;
422+
423+
self.try_attach_free(lib_path, "free_sized");
424+
self.try_attach_free(lib_path, "free_aligned_sized");
425+
self.try_attach_free(lib_path, "sdallocx");
426+
427+
Ok(())
428+
}
408429
attach_tracepoint!(sched_fork);
409430

410431
pub fn attach_tracepoints(&mut self) -> Result<()> {

0 commit comments

Comments
 (0)