use rustc_hash::{FxHashMap, FxHashSet};
use super::clock::{ClockOffset, WallNs};
use super::spans::interval_pairing::MonoInterval;
use super::spans::span_builder::compute_span_uid;
use super::{EnclosingSpanSummary, ResolvedSample, ResolvedSpan, SOURCE_CPU_PROFILE};
struct SpanInterval {
start_wall: WallNs,
end_wall: WallNs,
span_idx: usize,
}
pub(crate) fn attribute_samples_to_spans(
samples: &mut [ResolvedSample],
resolved_spans: &mut [ResolvedSpan],
legacy_intervals: &FxHashMap<u64, Vec<MonoInterval>>,
boot_id: &str,
clock_offset: Option<ClockOffset>,
) {
let mut all_intervals: Vec<SpanInterval> = Vec::new();
let to_wall = |mono: super::clock::MonoNs| mono.to_wall_or_raw(clock_offset);
let span_idx_by_uid: FxHashMap<[u8; 16], usize> = resolved_spans
.iter()
.enumerate()
.map(|(idx, span)| (span.span_uid, idx))
.collect();
for (synthetic_instance_id, intervals) in legacy_intervals {
let target_uid = compute_span_uid(boot_id, *synthetic_instance_id);
if let Some(&span_idx) = span_idx_by_uid.get(&target_uid) {
for &(enter_ts, exit_ts) in intervals {
all_intervals.push(SpanInterval {
start_wall: to_wall(enter_ts),
end_wall: to_wall(exit_ts),
span_idx,
});
}
}
}
all_intervals.sort_unstable_by_key(|iv| iv.start_wall);
let mut sample_order: Vec<usize> = (0..samples.len()).collect();
sample_order.sort_unstable_by_key(|&i| samples[i].timestamp_ns);
let mut active: Vec<usize> = Vec::new(); let mut interval_cursor: usize = 0;
let mut seen_span_indices: FxHashSet<usize> = FxHashSet::default();
for &sample_idx in &sample_order {
let ts = WallNs(samples[sample_idx].timestamp_ns);
while interval_cursor < all_intervals.len()
&& all_intervals[interval_cursor].start_wall <= ts
{
active.push(interval_cursor);
interval_cursor += 1;
}
active.retain(|&iv_idx| all_intervals[iv_idx].end_wall > ts);
seen_span_indices.clear();
for &iv_idx in &active {
let iv = &all_intervals[iv_idx];
debug_assert!(iv.start_wall <= ts && iv.end_wall > ts);
if !seen_span_indices.insert(iv.span_idx) {
continue;
}
if samples[sample_idx].source == SOURCE_CPU_PROFILE {
resolved_spans[iv.span_idx].cpu_sample_count += 1;
} else {
resolved_spans[iv.span_idx].sched_sample_count += 1;
}
let span = &resolved_spans[iv.span_idx];
samples[sample_idx]
.enclosing_spans
.push(EnclosingSpanSummary {
span_uid: span.span_uid,
span_type_uid: span.span_type_uid,
elapsed_ns: span.elapsed_ns,
details_complete: span.details_complete,
});
}
}
}