Skip to content

Commit 18e7883

Browse files
cleanup(profiling): consolidate heap-live value indices and reduce duplication
Extract ValueIndices struct, deduplicate values construction, and optimize string-ID label handling to skip resolving excluded labels. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 3f4e0cf commit 18e7883

File tree

1 file changed

+54
-68
lines changed

1 file changed

+54
-68
lines changed

libdd-profiling/src/internal/heap_live.rs

Lines changed: 54 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,37 @@ use std::hash::BuildHasherDefault;
1515
/// `reset_and_return_previous()`.
1616
type FxBuildHasher = BuildHasherDefault<rustc_hash::FxHasher>;
1717

18-
pub(crate) struct HeapLiveState {
19-
pub tracked: HashMap<u64, TrackedAlloc, FxBuildHasher>,
20-
pub max_tracked: usize,
21-
pub excluded_labels: Vec<Box<str>>,
18+
/// Indices into the sample values array for reading/writing heap-live fields.
19+
struct ValueIndices {
2220
/// Index of alloc-size in the sample values array (to read allocation size).
23-
alloc_size_idx: usize,
21+
alloc_size: usize,
2422
/// Index of heap-live-samples in the sample values array (to write 1).
25-
heap_live_samples_idx: usize,
23+
heap_live_samples: usize,
2624
/// Index of heap-live-size in the sample values array (to write the size).
27-
heap_live_size_idx: usize,
25+
heap_live_size: usize,
2826
/// Total number of values per sample.
2927
num_values: usize,
3028
}
3129

30+
impl ValueIndices {
31+
/// Build a heap-live values vector: all zeros except heap-live-samples=1
32+
/// and heap-live-size=alloc_size (read from the original sample).
33+
fn build_values(&self, sample_values: &[i64]) -> Vec<i64> {
34+
let alloc_size = sample_values.get(self.alloc_size).copied().unwrap_or(0);
35+
let mut values = vec![0i64; self.num_values];
36+
values[self.heap_live_samples] = 1;
37+
values[self.heap_live_size] = alloc_size;
38+
values
39+
}
40+
}
41+
42+
pub(crate) struct HeapLiveState {
43+
pub tracked: HashMap<u64, TrackedAlloc, FxBuildHasher>,
44+
pub max_tracked: usize,
45+
pub excluded_labels: Vec<Box<str>>,
46+
indices: ValueIndices,
47+
}
48+
3249
/// A single tracked live allocation with owned frame/label/values data.
3350
pub(crate) struct TrackedAlloc {
3451
pub frames: Vec<OwnedFrame>,
@@ -49,10 +66,12 @@ impl HeapLiveState {
4966
tracked: HashMap::with_capacity_and_hasher(max_tracked, FxBuildHasher::default()),
5067
max_tracked,
5168
excluded_labels: excluded_labels.iter().map(|s| Box::from(*s)).collect(),
52-
alloc_size_idx,
53-
heap_live_samples_idx,
54-
heap_live_size_idx,
55-
num_values,
69+
indices: ValueIndices {
70+
alloc_size: alloc_size_idx,
71+
heap_live_samples: heap_live_samples_idx,
72+
heap_live_size: heap_live_size_idx,
73+
num_values,
74+
},
5675
}
5776
}
5877

@@ -64,14 +83,7 @@ impl HeapLiveState {
6483
if self.tracked.len() >= self.max_tracked {
6584
return false;
6685
}
67-
let alloc = TrackedAlloc::from_api_sample(
68-
sample,
69-
&self.excluded_labels,
70-
self.alloc_size_idx,
71-
self.heap_live_samples_idx,
72-
self.heap_live_size_idx,
73-
self.num_values,
74-
);
86+
let alloc = TrackedAlloc::from_api_sample(sample, &self.excluded_labels, &self.indices);
7587
self.tracked.insert(ptr, alloc);
7688
true
7789
}
@@ -92,10 +104,7 @@ impl HeapLiveState {
92104
sample,
93105
storage,
94106
&self.excluded_labels,
95-
self.alloc_size_idx,
96-
self.heap_live_samples_idx,
97-
self.heap_live_size_idx,
98-
self.num_values,
107+
&self.indices,
99108
)?;
100109
self.tracked.insert(ptr, alloc);
101110
Ok(true)
@@ -107,14 +116,15 @@ impl HeapLiveState {
107116
}
108117
}
109118

119+
fn is_excluded(excluded_labels: &[Box<str>], key: &str) -> bool {
120+
excluded_labels.iter().any(|ex| ex.as_ref() == key)
121+
}
122+
110123
impl TrackedAlloc {
111124
fn from_api_sample(
112125
sample: &api::Sample,
113126
excluded_labels: &[Box<str>],
114-
alloc_size_idx: usize,
115-
heap_live_samples_idx: usize,
116-
heap_live_size_idx: usize,
117-
num_values: usize,
127+
indices: &ValueIndices,
118128
) -> Self {
119129
let frames = sample
120130
.locations
@@ -129,7 +139,7 @@ impl TrackedAlloc {
129139
let labels = sample
130140
.labels
131141
.iter()
132-
.filter(|l| !excluded_labels.iter().any(|ex| ex.as_ref() == l.key))
142+
.filter(|l| !is_excluded(excluded_labels, l.key))
133143
.map(|l| OwnedLabel {
134144
key: l.key.into(),
135145
str_value: l.str.into(),
@@ -138,29 +148,18 @@ impl TrackedAlloc {
138148
})
139149
.collect();
140150

141-
// Construct heap-live-only values: all zeros except the heap-live
142-
// fields. The allocation size is read from the original sample's
143-
// alloc-size slot.
144-
let alloc_size = sample.values.get(alloc_size_idx).copied().unwrap_or(0);
145-
let mut values = vec![0i64; num_values];
146-
values[heap_live_samples_idx] = 1;
147-
values[heap_live_size_idx] = alloc_size;
148-
149151
TrackedAlloc {
150152
frames,
151153
labels,
152-
values,
154+
values: indices.build_values(sample.values),
153155
}
154156
}
155157

156158
fn from_string_id_sample(
157159
sample: &api::StringIdSample,
158160
storage: &ManagedStringStorage,
159161
excluded_labels: &[Box<str>],
160-
alloc_size_idx: usize,
161-
heap_live_samples_idx: usize,
162-
heap_live_size_idx: usize,
163-
num_values: usize,
162+
indices: &ValueIndices,
164163
) -> anyhow::Result<Self> {
165164
let frames = sample
166165
.locations
@@ -174,37 +173,24 @@ impl TrackedAlloc {
174173
})
175174
.collect::<Result<Vec<_>, _>>()?;
176175

177-
let labels = sample
178-
.labels
179-
.iter()
180-
.map(|l| -> anyhow::Result<OwnedLabel> {
181-
Ok(OwnedLabel {
182-
key: resolve_managed_string(storage, l.key)?,
183-
str_value: resolve_managed_string(storage, l.str)?,
184-
num: l.num,
185-
num_unit: resolve_managed_string(storage, l.num_unit)?,
186-
})
187-
})
188-
.collect::<Result<Vec<_>, _>>()?;
189-
190-
let labels = labels
191-
.into_iter()
192-
.filter(|l| {
193-
!excluded_labels
194-
.iter()
195-
.any(|ex| ex.as_ref() == l.key.as_ref())
196-
})
197-
.collect();
198-
199-
let alloc_size = sample.values.get(alloc_size_idx).copied().unwrap_or(0);
200-
let mut values = vec![0i64; num_values];
201-
values[heap_live_samples_idx] = 1;
202-
values[heap_live_size_idx] = alloc_size;
176+
let mut labels = Vec::with_capacity(sample.labels.len());
177+
for l in &sample.labels {
178+
let key = resolve_managed_string(storage, l.key)?;
179+
if is_excluded(excluded_labels, &key) {
180+
continue;
181+
}
182+
labels.push(OwnedLabel {
183+
key,
184+
str_value: resolve_managed_string(storage, l.str)?,
185+
num: l.num,
186+
num_unit: resolve_managed_string(storage, l.num_unit)?,
187+
});
188+
}
203189

204190
Ok(TrackedAlloc {
205191
frames,
206192
labels,
207-
values,
193+
values: indices.build_values(sample.values),
208194
})
209195
}
210196
}

0 commit comments

Comments
 (0)