Skip to content

Commit 533d19f

Browse files
authored
Don't reset the perf counter after reading (#467)
This reduces the accumulated error and avoid triggering a kernel bug.
1 parent 5b875dc commit 533d19f

File tree

8 files changed

+113
-38
lines changed

8 files changed

+113
-38
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ atomic-traits = "0.2.0"
3333
atomic = "0.4.6"
3434
spin = "0.5.2"
3535
env_logger = "0.8.2"
36-
pfm = {version = "0.0.8", optional = true}
36+
pfm = {version = "0.0.9", optional = true}
3737

3838
[dev-dependencies]
3939
crossbeam = "0.7.3"

src/memory_manager.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ pub fn gc_init<VM: VMBinding>(mmtk: &'static mut MMTK<VM>, heap_size: usize) {
6161
if split[0] == "Threads:" {
6262
let threads = split[1].parse::<i32>().unwrap();
6363
if threads != 1 {
64-
warn!("Current process has {} threads, process-wide perf event measurement will only include child threads spawned from this threadas", threads);
64+
warn!("Current process has {} threads, process-wide perf event measurement will only include child threads spawned from this thread", threads);
6565
}
6666
}
6767
}

src/scheduler/work_counter.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -189,16 +189,16 @@ mod perf_event {
189189
impl WorkCounter for WorkPerfEvent {
190190
fn start(&mut self) {
191191
self.running = true;
192-
self.pe.reset();
193-
self.pe.enable();
192+
self.pe.reset().expect("Failed to reset perf event");
193+
self.pe.enable().expect("Failed to enable perf event");
194194
}
195195
fn stop(&mut self) {
196196
self.running = true;
197197
let perf_event_value = self.pe.read().unwrap();
198198
self.base.merge_val(perf_event_value.value as f64);
199199
// assert not multiplexing
200200
assert_eq!(perf_event_value.time_enabled, perf_event_value.time_running);
201-
self.pe.disable();
201+
self.pe.disable().expect("Failed to disable perf event");
202202
}
203203
fn name(&self) -> String {
204204
self.event_name.to_owned()

src/util/statistics/counter/event_counter.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,6 @@ impl Counter for EventCounter {
8080
self.running = false;
8181
}
8282

83-
/**
84-
* The phase has changed (from GC to mutator or mutator to GC).
85-
* Take action with respect to the last phase if necessary.
86-
*/
8783
fn phase_change(&mut self, old_phase: usize) {
8884
if self.running {
8985
self.count[old_phase] = self.current_count;
@@ -100,14 +96,14 @@ impl Counter for EventCounter {
10096
}
10197
}
10298

103-
fn print_total(&self, mutator: Option<bool>) {
104-
match mutator {
99+
fn get_total(&self, other: Option<bool>) -> u64 {
100+
match other {
105101
None => {
106102
let mut total = 0;
107103
for p in 0..=self.stats.get_phase() {
108104
total += self.count[p];
109105
}
110-
self.print_value(total);
106+
total
111107
}
112108
Some(m) => {
113109
let mut total = 0;
@@ -116,13 +112,17 @@ impl Counter for EventCounter {
116112
total += self.count[p];
117113
p += 2;
118114
}
119-
self.print_value(total);
115+
total
120116
}
121-
};
117+
}
118+
}
119+
120+
fn print_total(&self, other: Option<bool>) {
121+
self.print_value(self.get_total(other));
122122
}
123123

124-
fn print_min(&self, mutator: bool) {
125-
let mut p = if mutator { 0 } else { 1 };
124+
fn print_min(&self, other: bool) {
125+
let mut p = if other { 0 } else { 1 };
126126
let mut min = self.count[p];
127127
while p < self.stats.get_phase() {
128128
if self.count[p] < min {
@@ -133,8 +133,8 @@ impl Counter for EventCounter {
133133
self.print_value(min);
134134
}
135135

136-
fn print_max(&self, mutator: bool) {
137-
let mut p = if mutator { 0 } else { 1 };
136+
fn print_max(&self, other: bool) {
137+
let mut p = if other { 0 } else { 1 };
138138
let mut max = self.count[p];
139139
while p < self.stats.get_phase() {
140140
if self.count[p] > max {

src/util/statistics/counter/long_counter.rs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ impl<T: Diffable> Counter for LongCounter<T> {
2828
}
2929
debug_assert!(!self.running);
3030
self.running = true;
31+
self.diffable.start();
3132
self.start_value = Some(self.diffable.current_value());
3233
}
3334

@@ -37,6 +38,7 @@ impl<T: Diffable> Counter for LongCounter<T> {
3738
}
3839
debug_assert!(self.running);
3940
self.running = false;
41+
self.diffable.stop();
4042
let current_value = self.diffable.current_value();
4143
let delta = T::diff(&current_value, self.start_value.as_ref().unwrap());
4244
self.count[self.stats.get_phase()] += delta;
@@ -62,23 +64,27 @@ impl<T: Diffable> Counter for LongCounter<T> {
6264
}
6365
}
6466

65-
fn print_total(&self, mutator: Option<bool>) {
66-
match mutator {
67-
None => self.print_value(self.total_count),
67+
fn get_total(&self, other: Option<bool>) -> u64 {
68+
match other {
69+
None => self.total_count,
6870
Some(m) => {
6971
let mut total = 0;
7072
let mut p = if m { 0 } else { 1 };
7173
while p <= self.stats.get_phase() {
7274
total += self.count[p];
7375
p += 2;
7476
}
75-
self.print_value(total);
77+
total
7678
}
77-
};
79+
}
80+
}
81+
82+
fn print_total(&self, other: Option<bool>) {
83+
self.print_value(self.get_total(other));
7884
}
7985

80-
fn print_min(&self, mutator: bool) {
81-
let mut p = if mutator { 0 } else { 1 };
86+
fn print_min(&self, other: bool) {
87+
let mut p = if other { 0 } else { 1 };
8288
let mut min = self.count[p];
8389
while p < self.stats.get_phase() {
8490
if self.count[p] < min {
@@ -89,8 +95,8 @@ impl<T: Diffable> Counter for LongCounter<T> {
8995
self.print_value(min);
9096
}
9197

92-
fn print_max(&self, mutator: bool) {
93-
let mut p = if mutator { 0 } else { 1 };
98+
fn print_max(&self, other: bool) {
99+
let mut p = if other { 0 } else { 1 };
94100
let mut max = self.count[p];
95101
while p < self.stats.get_phase() {
96102
if self.count[p] > max {

src/util/statistics/counter/mod.rs

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,73 @@ pub use self::long_counter::{LongCounter, Timer};
1212
pub use self::perf_event::PerfEventDiffable;
1313
pub use self::size_counter::SizeCounter;
1414

15+
/// An abstraction over how a specific Diffable value is counted
16+
///
17+
/// For example, we can just collect the values, and store the cummulative sum,
18+
/// or we can derive some kind of histogram, etc.
1519
pub trait Counter {
20+
/// Start the counter
1621
fn start(&mut self);
22+
/// Stop the counter
1723
fn stop(&mut self);
24+
/// Signal a change in GC phase.
25+
///
26+
/// The phase number starts from 0 and is strictly increasing.
27+
/// Even numbers mean mutators are running (`other`) while odd numbers mean
28+
/// stop-the-world pauses (`stw`).
29+
/// Take action with respect to the last phase if necessary.
1830
fn phase_change(&mut self, old_phase: usize);
31+
/// Print the counter value for a particular phase
32+
///
33+
/// If the counter merges the phases, the printing value will include
34+
/// the specified phase and the next phase
1935
fn print_count(&self, phase: usize);
20-
fn print_total(&self, mutator: Option<bool>);
21-
fn print_min(&self, mutator: bool);
22-
fn print_max(&self, mutator: bool);
36+
/// Get the total count over past phases
37+
///
38+
/// If the argument is None, count all phases.
39+
/// Otherwise, count only `other` phases if true, or `stw` phases if false
40+
fn get_total(&self, other: Option<bool>) -> u64;
41+
/// Print the total count over past phases
42+
///
43+
/// If the argument is None, count all phases.
44+
/// Otherwise, count only `other` phases if true, or `stw` phases if false
45+
fn print_total(&self, other: Option<bool>);
46+
/// Print the minimum count of the past phases
47+
///
48+
/// Consider only `other` phases if true, or `stw` phases if false
49+
fn print_min(&self, other: bool);
50+
/// Print the maximum count of the past phases
51+
///
52+
/// Consider only `other` phases if true, or `stw` phases if false
53+
fn print_max(&self, other: bool);
54+
/// Print the count of the last phases
2355
fn print_last(&self);
56+
/// Whether the counter merges other and stw phases.
2457
fn merge_phases(&self) -> bool;
58+
/// Whether the counter starts implicitly after creation
59+
///
60+
/// FIXME currently unused
2561
fn implicitly_start(&self) -> bool;
62+
/// Get the name of the counter
2663
fn name(&self) -> &String;
2764
}
2865

66+
/// An abstraction over some changing values that we want to measure.
67+
///
2968
/// A Diffable object could be stateless (e.g. a timer that reads the wall
3069
/// clock), or stateful (e.g. holds reference to a perf event fd)
3170
pub trait Diffable {
71+
/// The type of each reading
3272
type Val;
73+
/// Start the Diffable
74+
fn start(&mut self);
75+
/// Stop the Diffable
76+
fn stop(&mut self);
77+
/// Read the current value
3378
fn current_value(&mut self) -> Self::Val;
79+
/// Compute the difference between two readings
3480
fn diff(current: &Self::Val, earlier: &Self::Val) -> u64;
81+
/// Print the difference in a specific format
3582
fn print_diff(val: u64);
3683
}
3784

@@ -40,6 +87,12 @@ pub struct MonotoneNanoTime;
4087
impl Diffable for MonotoneNanoTime {
4188
type Val = Instant;
4289

90+
/// nop for the wall-clock time
91+
fn start(&mut self) {}
92+
93+
/// nop for the wall-clock time
94+
fn stop(&mut self) {}
95+
4396
fn current_value(&mut self) -> Instant {
4497
Instant::now()
4598
}

src/util/statistics/counter/perf_event.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,24 @@ impl PerfEventDiffable {
2222
impl Diffable for PerfEventDiffable {
2323
type Val = PerfEventValue;
2424

25+
fn start(&mut self) {
26+
self.pe.reset().expect("Failed to reset perf evet");
27+
self.pe.enable().expect("Failed to enable perf evet");
28+
}
29+
30+
fn stop(&mut self) {
31+
self.pe.disable().expect("Failed to disable perf evet");
32+
}
33+
2534
fn current_value(&mut self) -> Self::Val {
26-
let val = self.pe.read().unwrap();
27-
self.pe.enable();
28-
self.pe.reset();
35+
let val = self.pe.read().expect("Failed to read perf evet");
36+
assert_eq!(val.time_enabled, val.time_running, "perf event multiplexed");
2937
val
3038
}
3139

32-
fn diff(current: &Self::Val, _earlier: &Self::Val) -> u64 {
33-
// earlier value is not used as the counter is reset after each use
34-
assert_eq!(current.time_enabled, current.time_running);
35-
current.value as u64
40+
fn diff(current: &Self::Val, earlier: &Self::Val) -> u64 {
41+
assert!(current.value >= earlier.value, "perf event overflowed");
42+
current.value as u64 - earlier.value as u64
3643
}
3744

3845
fn print_diff(val: u64) {

src/util/statistics/stats.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use std::sync::Mutex;
1414
pub const MAX_PHASES: usize = 1 << 12;
1515
pub const MAX_COUNTERS: usize = 100;
1616

17-
// Shared with each counter
17+
/// GC stats shared among counters
1818
pub struct SharedStats {
1919
phase: AtomicUsize,
2020
gathering_stats: AtomicBool,
@@ -38,6 +38,10 @@ impl SharedStats {
3838
}
3939
}
4040

41+
/// GC statistics
42+
///
43+
/// The struct holds basic GC statistics, like the GC count,
44+
/// and an array of counters.
4145
pub struct Stats {
4246
gc_count: AtomicUsize,
4347
total_time: Arc<Mutex<Timer>>,
@@ -54,6 +58,8 @@ pub struct Stats {
5458
impl Stats {
5559
#[allow(unused)]
5660
pub fn new(options: &Options) -> Self {
61+
// Create a perfmon instance and initialize it
62+
// we use perfmon to parse perf event names
5763
#[cfg(feature = "perf_counter")]
5864
let perfmon = {
5965
let mut perfmon: Perfmon = Default::default();
@@ -65,6 +71,7 @@ impl Stats {
6571
gathering_stats: AtomicBool::new(false),
6672
});
6773
let mut counters: Vec<Arc<Mutex<dyn Counter + Send>>> = vec![];
74+
// We always have a time counter enabled
6875
let t = Arc::new(Mutex::new(LongCounter::new(
6976
"time".to_string(),
7077
shared.clone(),
@@ -73,6 +80,8 @@ impl Stats {
7380
MonotoneNanoTime {},
7481
)));
7582
counters.push(t.clone());
83+
// Read from the MMTK option for a list of perf events we want to
84+
// measure, and create corresponding counters
7685
#[cfg(feature = "perf_counter")]
7786
for e in &options.phase_perf_events.events {
7887
counters.push(Arc::new(Mutex::new(LongCounter::new(

0 commit comments

Comments
 (0)