Skip to content

Commit 9ffc05c

Browse files
stepanchegfacebook-github-bot
authored andcommitted
AggregateHeapProfileInfo::merge
Summary: Utility to merge multiple `AggregateHeapProfileInfo`. Reviewed By: bobyangyf Differential Revision: D38518064 fbshipit-source-id: dca83ccedf08029f461da6b1a812cb5a7cd04ba7
1 parent faae7c4 commit 9ffc05c

File tree

4 files changed

+103
-2
lines changed

4 files changed

+103
-2
lines changed

starlark/src/eval/runtime/small_duration.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,12 @@ impl<'a> Sum<&'a SmallDuration> for SmallDuration {
9292
iter.fold(SmallDuration::default(), |acc, x| acc + *x)
9393
}
9494
}
95+
96+
impl Sum<SmallDuration> for SmallDuration {
97+
fn sum<I>(iter: I) -> SmallDuration
98+
where
99+
I: Iterator<Item = SmallDuration>,
100+
{
101+
iter.fold(SmallDuration::default(), |acc, x| acc + x)
102+
}
103+
}

starlark/src/values/layout/heap/profile/aggregated.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,47 @@ pub(crate) struct StackFrame {
209209
pub(crate) calls_x2: u32,
210210
}
211211

212+
impl StackFrame {
213+
fn merge_callees<'a>(
214+
frames: &'a [StackFrameWithContext<'a>],
215+
strings: &mut StringIndex,
216+
) -> SmallMap<StringId, StackFrame> {
217+
let mut group_by_callee: SmallMap<&str, Vec<StackFrameWithContext>> = SmallMap::new();
218+
for frame in frames {
219+
for (name, callee) in frame.callees() {
220+
group_by_callee
221+
.entry(name)
222+
.or_insert_with(Vec::new)
223+
.push(callee);
224+
}
225+
}
226+
group_by_callee
227+
.into_iter()
228+
.map(|(name, frames)| {
229+
let name = strings.index(name);
230+
(name, StackFrame::merge(frames, strings))
231+
})
232+
.collect()
233+
}
234+
235+
fn merge<'a>(
236+
frames: impl IntoIterator<Item = StackFrameWithContext<'a>>,
237+
strings: &mut StringIndex,
238+
) -> StackFrame {
239+
let frames = Vec::from_iter(frames);
240+
let callees = StackFrame::merge_callees(&frames, strings);
241+
let allocs = HeapSummary::merge(frames.iter().map(|f| &f.frame.allocs));
242+
let time_x2 = frames.iter().map(|f| f.frame.time_x2).sum();
243+
let calls_x2 = frames.iter().map(|f| f.frame.calls_x2).sum();
244+
StackFrame {
245+
callees,
246+
allocs,
247+
time_x2,
248+
calls_x2,
249+
}
250+
}
251+
}
252+
212253
struct StackFrameWithContext<'c> {
213254
frame: &'c StackFrame,
214255
strings: &'c StringIndex,
@@ -292,6 +333,25 @@ impl AggregateHeapProfileInfo {
292333
}
293334
}
294335

336+
#[allow(dead_code)] // TODO: used later.
337+
fn merge<'a>(
338+
profiles: impl IntoIterator<Item = &'a AggregateHeapProfileInfo>,
339+
) -> AggregateHeapProfileInfo {
340+
let mut strings = StringIndex::default();
341+
let totals_id = strings.index(Self::TOTALS_STR);
342+
let root_id = strings.index(Self::ROOT_STR);
343+
let blank_id = strings.index(Self::BLANK_STR);
344+
let roots = profiles.into_iter().map(|p| p.root());
345+
let root = StackFrame::merge(roots, &mut strings);
346+
AggregateHeapProfileInfo {
347+
strings,
348+
root,
349+
totals_id,
350+
root_id,
351+
blank_id,
352+
}
353+
}
354+
295355
/// Write this out recursively to a file.
296356
pub(crate) fn gen_flame_graph(&self) -> String {
297357
let mut writer = FlameGraphWriter::new();
@@ -312,6 +372,7 @@ mod tests {
312372
use crate::values::layout::heap::heap_type::HeapKind;
313373
use crate::values::layout::heap::profile::aggregated::AggregateHeapProfileInfo;
314374
use crate::values::layout::heap::profile::aggregated::StackFrame;
375+
use crate::values::layout::heap::profile::summary::HeapSummaryByFunction;
315376
use crate::values::Freezer;
316377
use crate::values::FrozenHeap;
317378
use crate::values::Heap;
@@ -372,4 +433,25 @@ mod tests {
372433
);
373434
assert_eq!(2, total_alloc_count(&stacks.root));
374435
}
436+
437+
#[test]
438+
fn test_merge() {
439+
fn make() -> AggregateHeapProfileInfo {
440+
let heap = Heap::new();
441+
heap.record_call_enter(const_frozen_string!("xx").to_value());
442+
let s = heap.alloc_str("abc");
443+
heap.record_call_exit();
444+
let freezer = Freezer::new(FrozenHeap::new());
445+
freezer.freeze(s.to_value()).unwrap();
446+
447+
AggregateHeapProfileInfo::collect(&heap, Some(HeapKind::Frozen))
448+
}
449+
450+
let merge = AggregateHeapProfileInfo::merge([&make(), &make(), &make()]);
451+
let summary = HeapSummaryByFunction::init(&merge);
452+
assert_eq!(1, summary.info().len());
453+
let (xx_id, xx_info) = summary.info()[0];
454+
assert_eq!("xx", merge.strings.get(xx_id));
455+
assert_eq!(3, xx_info.alloc.get("string").unwrap().count);
456+
}
375457
}

starlark/src/values/layout/heap/profile/by_type.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,14 @@ impl HeapSummary {
5353
pub(crate) fn add(&mut self, t: &'static str, s: AllocCounts) {
5454
*self.summary.entry(t).or_default() += s;
5555
}
56+
57+
pub(crate) fn merge<'a>(heaps: impl IntoIterator<Item = &'a HeapSummary>) -> HeapSummary {
58+
let mut summary = SmallMap::new();
59+
for heap in heaps {
60+
for (k, v) in heap.summary.iter() {
61+
*summary.entry(*k).or_default() += *v;
62+
}
63+
}
64+
HeapSummary { summary }
65+
}
5666
}

starlark/src/values/layout/heap/profile/summary.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use crate::values::layout::heap::profile::string_index::StringIndexMap;
2929

3030
/// Information relating to a function.
3131
#[derive(Default, Debug, Clone)]
32-
struct FuncInfo {
32+
pub(crate) struct FuncInfo {
3333
/// Number of times this function was called
3434
pub calls: usize,
3535
/// Who called this function (and how many times each)
@@ -108,7 +108,7 @@ impl HeapSummaryByFunction {
108108
FuncInfo::merge(self.info.values())
109109
}
110110

111-
fn info(&self) -> Vec<(StringId, &FuncInfo)> {
111+
pub(crate) fn info(&self) -> Vec<(StringId, &FuncInfo)> {
112112
self.info.iter().collect::<Vec<_>>()
113113
}
114114

0 commit comments

Comments
 (0)