Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add perf event support #315

Merged
merged 32 commits into from
Jun 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
ce0c3f9
Add perfmon to Stats
caizixian May 18, 2021
5f1fca9
Refactor worker stat type
caizixian May 18, 2021
86ae080
Revert "Add perfmon to Stats"
caizixian May 18, 2021
863af8f
Implement as trait object
caizixian May 18, 2021
712b3b0
Fix test
caizixian May 18, 2021
b00d7a4
Fix clippy
caizixian May 18, 2021
69c0342
Refactor out work counters
caizixian May 18, 2021
b19368d
Add perfmon initialization
caizixian May 18, 2021
046988a
Make counter name a String
caizixian May 18, 2021
dbc1893
Implement perf event work counter
caizixian May 18, 2021
488391f
Don't insert counters when stat is disabled
caizixian May 19, 2021
bb9a51e
Implement Debug for WorkPerfEvent
caizixian May 19, 2021
00f38d0
Assert perf events are not multiplexing
caizixian May 19, 2021
8564b90
Merge branch 'master' into perf-event
caizixian May 28, 2021
7cbf3b5
Fix build error
caizixian May 28, 2021
40efc51
Merge branch 'master' into perf-event
caizixian Jun 11, 2021
792397d
Configure perf events with MMTk options
caizixian Jun 11, 2021
ad77838
Use new MMTk option and conditional compilation
caizixian Jun 13, 2021
32e8561
Fix scope issue
caizixian Jun 13, 2021
397aa20
Documentation
caizixian Jun 13, 2021
29fd7a7
Fix test error when compiled without perf feature
caizixian Jun 13, 2021
26b7600
Clippy fixes
caizixian Jun 13, 2021
ff9a636
cargo fmt
caizixian Jun 13, 2021
6fd31d5
Get rid of duplicated code
caizixian Jun 25, 2021
0101978
Fix initialization of Perfmon
caizixian Jun 25, 2021
bda23d2
Fix typo
caizixian Jun 25, 2021
1cfc308
Refactor the perf event option into a struct
caizixian Jun 25, 2021
7a1e3b3
Include perf_counter feature in CI
caizixian Jun 25, 2021
2edb2a5
Suppress warning due to conditional compilation
caizixian Jun 25, 2021
8163837
Fix unit tests
caizixian Jun 25, 2021
44446ac
Merge branch 'master' into perf-event
caizixian Jun 25, 2021
2b57d72
Merge branch 'master' into perf-event
caizixian Jun 26, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/scripts/ci-build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ if [[ $arch == "x86_64" && $os == "linux" ]]; then
cargo build --target i686-unknown-linux-gnu
for_all_features "cargo build --target i686-unknown-linux-gnu"
for_all_features "cargo build --release --target i686-unknown-linux-gnu"
cargo build --features perf_counter
fi
2 changes: 1 addition & 1 deletion .github/scripts/ci-common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ init_non_exclusive_features() {

while IFS= read -r line; do
# Only parse non mutally exclusive features
if [[ $line == *"-- Non mutally exclusive features --"* ]]; then
if [[ $line == *"-- Non mutually exclusive features --"* ]]; then
parse_features=true
continue
fi
Expand Down
3 changes: 3 additions & 0 deletions .github/scripts/ci-style.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ cargo clippy --manifest-path=vmbindings/dummyvm/Cargo.toml
if [[ $arch == "x86_64" && $os == "linux" ]]; then
for_all_features "cargo clippy --target i686-unknown-linux-gnu"
for_all_features "cargo clippy --release --target i686-unknown-linux-gnu"
cargo clippy --features perf_counter
cargo clippy --release --features perf_counter
cargo clippy --tests --features perf_counter
fi

# check format
Expand Down
1 change: 1 addition & 0 deletions .github/scripts/ci-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ for_all_features "cargo test"
# For x86_64-linux, also check for i686
if [[ $arch == "x86_64" && $os == "linux" ]]; then
for_all_features "cargo test --target i686-unknown-linux-gnu"
cargo test --features perf_counter
fi

python examples/build.py
Expand Down
7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ atomic-traits = "0.2.0"
atomic = "0.4.6"
spin = "0.5.2"
env_logger = "0.8.2"
pfm = {version = "0.0.7", optional = true}

[dev-dependencies]
crossbeam = "0.7.3"
Expand All @@ -41,11 +42,15 @@ rand = "0.7.3"
[features]
default = []

# This feature is only supported on x86-64 for now
# It's manually added to CI scripts
perf_counter = ["pfm"]

# .github/scripts/ci-common.sh extracts features from the following part (including from comments).
# So be careful when editing or adding stuff to the section below.

# Do not modify the following line - ci-common.sh matches it
# -- Non mutally exclusive features --
# -- Non mutually exclusive features --

# spaces
vm_space = []
Expand Down
2 changes: 1 addition & 1 deletion src/scheduler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub(crate) use scheduler::MMTkScheduler;
pub(self) use scheduler::Scheduler;

mod stat;
mod work_counter;
pub(self) mod work_counter;

mod work;
pub use work::CoordinatorWork;
Expand Down
1 change: 1 addition & 0 deletions src/scheduler/scheduler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ mod tests {
// println!("Original: {:?}", data);

SCHEDULER.initialize(NUM_WORKERS, &(), VMThread::UNINITIALIZED);
SCHEDULER.enable_stat();
SCHEDULER.work_buckets[WorkBucketStage::Unconstrained]
.add(Sort(unsafe { &mut *(data as *mut _) }));
SCHEDULER.wait_for_completion();
Expand Down
61 changes: 52 additions & 9 deletions src/scheduler/stat.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
//! Statistics for work packets
use super::work_counter::{WorkCounter, WorkCounterBase, WorkDuration};
#[cfg(feature = "perf_counter")]
use crate::scheduler::work_counter::WorkPerfEvent;
use crate::scheduler::Context;
use crate::vm::VMBinding;
use crate::MMTK;
use std::any::TypeId;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::sync::atomic::{AtomicBool, Ordering};

/// Merge and print the work-packet level statistics from all worker threads
Expand Down Expand Up @@ -99,7 +105,7 @@ impl SchedulerStat {
stat
}
/// Merge work counters from different worker threads
pub fn merge(&mut self, stat: &WorkerLocalStat) {
pub fn merge<C>(&mut self, stat: &WorkerLocalStat<C>) {
// Merge work packet type ID to work packet name mapping
for (id, name) in &stat.work_id_name_map {
self.work_id_name_map.insert(*id, *name);
Expand Down Expand Up @@ -144,7 +150,7 @@ impl WorkStat {
/// Stop all work counters for the work packet type of the just executed
/// work packet
#[inline(always)]
pub fn end_of_work(&self, worker_stat: &mut WorkerLocalStat) {
pub fn end_of_work<C: Context>(&self, worker_stat: &mut WorkerLocalStat<C>) {
if !worker_stat.is_enabled() {
return;
};
Expand All @@ -165,15 +171,27 @@ impl WorkStat {
}

/// Worker thread local counterpart of [`SchedulerStat`]
#[derive(Default)]
pub struct WorkerLocalStat {
pub struct WorkerLocalStat<C> {
work_id_name_map: HashMap<TypeId, &'static str>,
work_counts: HashMap<TypeId, usize>,
work_counters: HashMap<TypeId, Vec<Box<dyn WorkCounter>>>,
enabled: AtomicBool,
_phantom: PhantomData<C>,
}

impl<C> Default for WorkerLocalStat<C> {
fn default() -> Self {
WorkerLocalStat {
work_id_name_map: Default::default(),
work_counts: Default::default(),
work_counters: Default::default(),
enabled: AtomicBool::new(false),
_phantom: Default::default(),
}
}
}

impl WorkerLocalStat {
impl<C: Context> WorkerLocalStat<C> {
#[inline]
pub fn is_enabled(&self) -> bool {
self.enabled.load(Ordering::SeqCst)
Expand All @@ -185,23 +203,48 @@ impl WorkerLocalStat {
/// Measure the execution of a work packet by starting all counters for that
/// type
#[inline]
pub fn measure_work(&mut self, work_id: TypeId, work_name: &'static str) -> WorkStat {
pub fn measure_work(
&mut self,
work_id: TypeId,
work_name: &'static str,
context: &'static C,
) -> WorkStat {
let stat = WorkStat {
type_id: work_id,
type_name: work_name,
};
if self.is_enabled() {
self.work_counters
.entry(work_id)
.or_insert_with(WorkerLocalStat::counter_set)
.or_insert_with(|| C::counter_set(context))
.iter_mut()
.for_each(|c| c.start());
}
stat
}
}

// The set of work counters for all work packet types
fn counter_set() -> Vec<Box<dyn WorkCounter>> {
/// Private trait to let different contexts supply different sets of default
/// counters
trait HasCounterSet {
fn counter_set(context: &'static Self) -> Vec<Box<dyn WorkCounter>>;
}

impl<C> HasCounterSet for C {
default fn counter_set(_context: &'static Self) -> Vec<Box<dyn WorkCounter>> {
vec![Box::new(WorkDuration::new())]
}
}

/// Specialization for MMTk to read the options
#[allow(unused_variables, unused_mut)]
impl<VM: VMBinding> HasCounterSet for MMTK<VM> {
fn counter_set(mmtk: &'static Self) -> Vec<Box<dyn WorkCounter>> {
let mut counters: Vec<Box<dyn WorkCounter>> = vec![Box::new(WorkDuration::new())];
#[cfg(feature = "perf_counter")]
for e in &mmtk.options.perf_events.events {
counters.push(box WorkPerfEvent::new(&e.0, e.1, e.2));
}
counters
}
}
2 changes: 1 addition & 1 deletion src/scheduler/work.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub trait Work<C: Context>: 'static + Send {
fn do_work_with_stat(&mut self, worker: &mut Worker<C>, context: &'static C) {
let stat = worker
.stat
.measure_work(TypeId::of::<Self>(), type_name::<Self>());
.measure_work(TypeId::of::<Self>(), type_name::<Self>(), context);
self.do_work(worker, context);
stat.end_of_work(&mut worker.stat);
}
Expand Down
81 changes: 81 additions & 0 deletions src/scheduler/work_counter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,84 @@ impl WorkCounter for WorkDuration {
&mut self.base
}
}

#[cfg(feature = "perf_counter")]
mod perf_event {
//! Measure the perf events of work packets
//!
//! This is built on top of libpfm4.
//! The events to measure are parsed from MMTk option `perf_events`
use super::*;
use libc::{c_int, pid_t};
use pfm::PerfEvent;
use std::fmt;

/// Work counter for perf events
#[derive(Clone)]
pub struct WorkPerfEvent {
base: WorkCounterBase,
running: bool,
event_name: String,
pe: PerfEvent,
}

impl WorkPerfEvent {
/// Create a work counter
///
/// See `perf_event_open` for more details on `pid` and `cpu`
/// Examples:
/// 0, -1 measures the calling thread on all CPUs
/// -1, 0 measures all threads on CPU 0
/// -1, -1 is invalid
pub fn new(name: &str, pid: pid_t, cpu: c_int) -> WorkPerfEvent {
let mut pe = PerfEvent::new(name)
.unwrap_or_else(|_| panic!("Failed to create perf event {}", name));
pe.open(pid, cpu)
.unwrap_or_else(|_| panic!("Failed to open perf event {}", name));
WorkPerfEvent {
base: Default::default(),
running: false,
event_name: name.to_string(),
pe,
}
}
}

impl fmt::Debug for WorkPerfEvent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("WorkPerfEvent")
.field("base", &self.base)
.field("running", &self.running)
.field("event_name", &self.event_name)
.finish()
}
}

impl WorkCounter for WorkPerfEvent {
fn start(&mut self) {
self.running = true;
self.pe.reset();
self.pe.enable();
}
fn stop(&mut self) {
self.running = true;
let perf_event_value = self.pe.read().unwrap();
self.base.merge_val(perf_event_value.value as f64);
// assert not multiplexing
assert_eq!(perf_event_value.time_enabled, perf_event_value.time_running);
self.pe.disable();
}
fn name(&self) -> String {
self.event_name.to_owned()
}
fn get_base(&self) -> &WorkCounterBase {
&self.base
}
fn get_base_mut(&mut self) -> &mut WorkCounterBase {
&mut self.base
}
}
}

#[cfg(feature = "perf_counter")]
pub(super) use perf_event::WorkPerfEvent;
2 changes: 1 addition & 1 deletion src/scheduler/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub struct Worker<C: Context> {
local: WorkerLocalPtr,
pub local_work_bucket: WorkBucket<C>,
pub sender: Sender<CoordinatorMessage<C>>,
pub stat: WorkerLocalStat,
pub stat: WorkerLocalStat<C>,
context: Option<&'static C>,
is_coordinator: bool,
local_work_buffer: Vec<(WorkBucketStage, Box<dyn Work<C>>)>,
Expand Down
Loading