Track a spawned command, collecting all memory events. When `discover_system_allocators` is true, the tracker will scan for all allocators on the system (slower). When false, only `extra_allocators` are used.
(
mut command: Command,
extra_allocators: &[AllocatorLib],
discover_system_allocators: bool,
)
| 129 | /// When `discover_system_allocators` is true, the tracker will scan for all |
| 130 | /// allocators on the system (slower). When false, only `extra_allocators` are used. |
| 131 | pub fn track_command( |
| 132 | mut command: Command, |
| 133 | extra_allocators: &[AllocatorLib], |
| 134 | discover_system_allocators: bool, |
| 135 | ) -> TrackResult { |
| 136 | // IMPORTANT: Always initialize the tracker BEFORE spawning the binary, as it can take some time to |
| 137 | // attach to all the allocator libraries (especially when using NixOS). |
| 138 | let mut tracker = if discover_system_allocators { |
| 139 | memtrack::Tracker::new()? |
| 140 | } else { |
| 141 | memtrack::Tracker::new_without_allocators()? |
| 142 | }; |
| 143 | tracker.attach_allocators(extra_allocators)?; |
| 144 | |
| 145 | let child = command.spawn().context("Failed to spawn command")?; |
| 146 | let root_pid = child.id() as i32; |
| 147 | |
| 148 | tracker.enable()?; |
| 149 | let rx = tracker.track(root_pid)?; |
| 150 | |
| 151 | let mut events = Vec::new(); |
| 152 | while let Ok(event) = rx.recv_timeout(Duration::from_secs(10)) { |
| 153 | events.push(event); |
| 154 | } |
| 155 | |
| 156 | // Drop the tracker in a new thread to not block the test |
| 157 | let thread_handle = std::thread::spawn(move || core::mem::drop(tracker)); |
| 158 | |
| 159 | info!("Tracked {} events", events.len()); |
| 160 | trace!("Events: {events:#?}"); |
| 161 | |
| 162 | Ok((events, thread_handle)) |
| 163 | } |
| 164 | |
| 165 | pub fn track_binary_with_opts(binary: &Path, extra_allocators: &[AllocatorLib]) -> TrackResult { |
| 166 | track_command(Command::new(binary), extra_allocators, true) |
no test coverage detected