mirror of
https://github.com/rui314/mold.git
synced 2026-11-09 04:49:33 -10:00
Skip timer recording when profiling is disabled
Avoid clock reads, getrusage calls and shared record locks during ordinary links. Explicit --perf keeps the existing timing output. Cover nested timers, background handles and repeated stops in a unit test.
This commit is contained in:
1 parent
f359d51458
commit
7a7d03d186
2 files changed
+71
-8
No files matched your search
+6
-1
@@ -248,6 +248,11 @@ impl<E: Arch> Context<E> {
|
||||
..SyntheticSymbols::default()
|
||||
};
|
||||
let page_size = args.page_size;
|
||||
let timers = if args.perf {
|
||||
Timers::new()
|
||||
} else {
|
||||
Timers::disabled()
|
||||
};
|
||||
|
||||
Context {
|
||||
reldyn: RelDynSection::<E>::new(&args),
|
||||
@@ -269,7 +274,7 @@ impl<E: Arch> Context<E> {
|
||||
note_package: NotePackageSection::new(),
|
||||
args,
|
||||
cmdline_args,
|
||||
timers: Timers::new(),
|
||||
timers,
|
||||
symbols,
|
||||
symbol_chunks: Vec::new(),
|
||||
symbol_bins: OnceLock::new(),
|
||||
|
||||
+65
-7
@@ -74,9 +74,9 @@ struct Record {
|
||||
|
||||
/// Collects wall-clock and CPU timing records for the passes of a link.
|
||||
/// Cloning shares the underlying records.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Timers {
|
||||
records: Arc<Mutex<Vec<Record>>>,
|
||||
records: Option<Arc<Mutex<Vec<Record>>>>,
|
||||
}
|
||||
|
||||
/// A running timer, stopped when dropped.
|
||||
@@ -146,22 +146,49 @@ fn rusage() -> (f64, f64) {
|
||||
(to_secs(user), to_secs(kernel))
|
||||
}
|
||||
|
||||
impl Default for Timers {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Timers {
|
||||
pub fn new() -> Self {
|
||||
Timers::default()
|
||||
Timers {
|
||||
records: Some(Arc::new(Mutex::new(Vec::new()))),
|
||||
}
|
||||
}
|
||||
|
||||
/// Skips clock reads, system calls and shared recording when --perf is off.
|
||||
pub fn disabled() -> Self {
|
||||
Timers { records: None }
|
||||
}
|
||||
|
||||
fn inactive(&self) -> Timer {
|
||||
Timer {
|
||||
timers: self.clone(),
|
||||
index: 0,
|
||||
stopped: true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Starts a timer, nested in the timer still running that started last.
|
||||
pub fn start(&self, name: &str) -> Timer {
|
||||
let records = self.records.lock().unwrap();
|
||||
let Some(records) = &self.records else {
|
||||
return self.inactive();
|
||||
};
|
||||
let records = records.lock().unwrap();
|
||||
let parent = records.iter().rposition(|r| r.end.is_none());
|
||||
drop(records);
|
||||
self.start_child(name, parent)
|
||||
}
|
||||
|
||||
fn start_child(&self, name: &str, parent: Option<usize>) -> Timer {
|
||||
let Some(records) = &self.records else {
|
||||
return self.inactive();
|
||||
};
|
||||
let (user, sys) = rusage();
|
||||
let mut records = self.records.lock().unwrap();
|
||||
let mut records = records.lock().unwrap();
|
||||
let index = records.len();
|
||||
records.push(Record {
|
||||
name: name.to_string(),
|
||||
@@ -186,7 +213,7 @@ impl Timers {
|
||||
|
||||
fn stop(&self, index: usize) {
|
||||
let (user, sys) = rusage();
|
||||
let mut records = self.records.lock().unwrap();
|
||||
let mut records = self.records.as_ref().unwrap().lock().unwrap();
|
||||
let record = &mut records[index];
|
||||
if record.end.is_none() {
|
||||
record.end = Some(Instant::now());
|
||||
@@ -196,7 +223,10 @@ impl Timers {
|
||||
}
|
||||
|
||||
pub fn print(&self) {
|
||||
let mut records = self.records.lock().unwrap();
|
||||
let Some(records) = &self.records else {
|
||||
return;
|
||||
};
|
||||
let mut records = records.lock().unwrap();
|
||||
let now = Instant::now();
|
||||
for r in records.iter_mut() {
|
||||
if r.end.is_none() {
|
||||
@@ -265,3 +295,31 @@ impl Drop for Timer {
|
||||
self.stop();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn optional_recording_includes_nested_and_background_timers() {
|
||||
for timers in [Timers::new(), Timers::disabled()] {
|
||||
let mut root = timers.start("root");
|
||||
let child = root.child("child");
|
||||
let handle = root.handle();
|
||||
std::thread::spawn(move || drop(handle.child("background")))
|
||||
.join()
|
||||
.unwrap();
|
||||
drop(child);
|
||||
root.stop();
|
||||
root.stop();
|
||||
if let Some(records) = &timers.records {
|
||||
let records = records.lock().unwrap();
|
||||
assert_eq!(records.len(), 3);
|
||||
assert!(records.iter().all(|record| record.end.is_some()));
|
||||
assert_eq!(records[0].children, [1, 2]);
|
||||
} else {
|
||||
assert!(root.timers.records.is_none());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user