Skip to content

Commit cfe3819

Browse files
ghaithclaude
andcommitted
refactor: review nits — lazy PhaseTimer labels and typed UnitId source accessor
Two small follow-ups from review feedback: - `PhaseTimer::new_with(|| format!(...))` defers the label allocation until `PLC_TIMING` is enabled. The pipeline driver previously paid one `format!` per participant per stage even when timing was off, perturbing the measurements that the instrumentation was meant to observe. - `UnitId::source_index() -> Option<usize>` replaces the `unit_id.is_source()` + `unit_id.raw() as usize` pair at the bookkeeper's closure-build site. The conversion is now encapsulated and non-source ids can't slip through. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 2670c7c commit cfe3819

4 files changed

Lines changed: 52 additions & 20 deletions

File tree

compiler/plc_driver/src/pipelines.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -489,23 +489,23 @@ impl<T: SourceContainer> Pipeline for BuildPipeline<T> {
489489
let project = {
490490
let _t = PhaseTimer::new("pre_index (participants)");
491491
self.participants.iter_mut().for_each(|p| {
492-
let _t = PhaseTimer::new(format!("pre_index/{}", p.name()));
492+
let _t = PhaseTimer::new_with(|| format!("pre_index/{}", p.name()));
493493
p.pre_index(&project);
494494
});
495495
self.mutable_participants.iter_mut().fold(project, |project, p| {
496-
let _t = PhaseTimer::new(format!("pre_index/{}", p.name()));
496+
let _t = PhaseTimer::new_with(|| format!("pre_index/{}", p.name()));
497497
p.pre_index(project)
498498
})
499499
};
500500
let indexed_project = project.index(self.context.provider());
501501
let project = {
502502
let _t = PhaseTimer::new("post_index (participants)");
503503
self.participants.iter().for_each(|p| {
504-
let _t = PhaseTimer::new(format!("post_index/{}", p.name()));
504+
let _t = PhaseTimer::new_with(|| format!("post_index/{}", p.name()));
505505
p.post_index(&indexed_project);
506506
});
507507
self.mutable_participants.iter_mut().fold(indexed_project, |project, p| {
508-
let _t = PhaseTimer::new(format!("post_index/{}", p.name()));
508+
let _t = PhaseTimer::new_with(|| format!("post_index/{}", p.name()));
509509
p.post_index(project)
510510
})
511511
};
@@ -518,23 +518,23 @@ impl<T: SourceContainer> Pipeline for BuildPipeline<T> {
518518
let project = {
519519
let _t = PhaseTimer::new("pre_annotate (participants)");
520520
self.participants.iter().for_each(|p| {
521-
let _t = PhaseTimer::new(format!("pre_annotate/{}", p.name()));
521+
let _t = PhaseTimer::new_with(|| format!("pre_annotate/{}", p.name()));
522522
p.pre_annotate(&project);
523523
});
524524
self.mutable_participants.iter_mut().fold(project, |project, p| {
525-
let _t = PhaseTimer::new(format!("pre_annotate/{}", p.name()));
525+
let _t = PhaseTimer::new_with(|| format!("pre_annotate/{}", p.name()));
526526
p.pre_annotate(project)
527527
})
528528
};
529529
let annotated_project = project.annotate(self.context.provider());
530530
let mut annotated_project = {
531531
let _t = PhaseTimer::new("post_annotate (participants)");
532532
self.participants.iter().for_each(|p| {
533-
let _t = PhaseTimer::new(format!("post_annotate/{}", p.name()));
533+
let _t = PhaseTimer::new_with(|| format!("post_annotate/{}", p.name()));
534534
p.post_annotate(&annotated_project);
535535
});
536536
self.mutable_participants.iter_mut().fold(annotated_project, |project, p| {
537-
let _t = PhaseTimer::new(format!("post_annotate/{}", p.name()));
537+
let _t = PhaseTimer::new_with(|| format!("post_annotate/{}", p.name()));
538538
p.post_annotate(project)
539539
})
540540
};

compiler/plc_driver/src/pipelines/bookkeeping.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ impl LoweringBookkeeper {
125125
for sig in &self.changed_signatures {
126126
if let Some(dependents) = reverse_deps_pre.dependents(sig) {
127127
for unit_id in dependents {
128-
if unit_id.is_source() {
129-
closure.insert(unit_id.raw() as usize);
128+
if let Some(idx) = unit_id.source_index() {
129+
closure.insert(idx);
130130
}
131131
}
132132
}

compiler/plc_driver/src/pipelines/timing.rs

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,41 @@ pub struct PhaseTimer {
3535
}
3636

3737
impl PhaseTimer {
38-
pub fn new(label: impl Into<String>) -> Self {
38+
/// Constructs a timer with a label known at compile time. When timing is
39+
/// disabled, the only work done is reading the `ENABLED` flag.
40+
pub fn new(label: &'static str) -> Self {
41+
Self::new_inner(active_depth(), label, enabled())
42+
}
43+
44+
/// Constructs a timer whose label requires runtime formatting. The closure
45+
/// is only invoked when timing is enabled — `format!`/allocation is
46+
/// skipped on the hot path when `PLC_TIMING` is unset.
47+
pub fn new_with<F>(label_fn: F) -> Self
48+
where
49+
F: FnOnce() -> String,
50+
{
3951
let active = enabled();
40-
let depth = if active {
41-
DEPTH.with(|d| {
42-
let cur = d.get();
43-
d.set(cur + 1);
44-
cur
45-
})
46-
} else {
47-
0
48-
};
52+
let label: String = if active { label_fn() } else { String::new() };
53+
Self::new_inner(active_depth(), label, active)
54+
}
55+
56+
fn new_inner(depth: usize, label: impl Into<String>, active: bool) -> Self {
4957
Self { label: label.into(), start: Instant::now(), depth, active }
5058
}
5159
}
5260

61+
fn active_depth() -> usize {
62+
if enabled() {
63+
DEPTH.with(|d| {
64+
let cur = d.get();
65+
d.set(cur + 1);
66+
cur
67+
})
68+
} else {
69+
0
70+
}
71+
}
72+
5373
impl Drop for PhaseTimer {
5474
fn drop(&mut self) {
5575
if !self.active {

src/index/unit_id.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,18 @@ impl UnitId {
5252
self.0 < Self::UNTAGGED.0
5353
}
5454

55+
/// Returns the source-list index if this is a source unit, or `None`
56+
/// for built-in, synthetic, or untagged ids. Prefer this over
57+
/// `is_source()` + `raw() as usize`: the conversion is encapsulated and
58+
/// non-source ids can't slip through silently.
59+
pub fn source_index(self) -> Option<usize> {
60+
if self.is_source() {
61+
Some(self.0 as usize)
62+
} else {
63+
None
64+
}
65+
}
66+
5567
pub fn is_builtin(self) -> bool {
5668
self == Self::BUILTIN
5769
}

0 commit comments

Comments
 (0)