Skip to content

Commit

Permalink
Merge pull request #2039 from FractalFir/master
Browse files Browse the repository at this point in the history
Add support for Performance / Efficency cores.
  • Loading branch information
Kobzol authored Feb 13, 2025
2 parents fa1f55a + 89efd0e commit 2477025
Showing 1 changed file with 72 additions and 2 deletions.
74 changes: 72 additions & 2 deletions collector/src/compile/execute/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,67 @@ pub struct CargoProcess<'a> {
pub touch_file: Option<String>,
pub jobserver: Option<jobserver::Client>,
}
/// Returns an optional list of Performance CPU cores, if the system has P and E cores.
/// This list *should* be in a format suitable for the `taskset` command.
#[cfg(target_os = "linux")]
fn performance_cores() -> Option<&'static String> {
use std::sync::LazyLock;
static PERFORMANCE_CORES: LazyLock<Option<String>> = LazyLock::new(|| {
if std::fs::exists("/sys/devices/cpu").expect("Could not check the CPU architecture details: could not check if `/sys/devices/cpu` exists!") {
// If /sys/devices/cpu exists, then this is not a "Performance-hybrid" CPU.
None
}
else if std::fs::exists("/sys/devices/cpu_core").expect("Could not check the CPU architecture detali: could not check if `/sys/devices/cpu_core` exists!") {
// If /sys/devices/cpu_core exists, then this is a "Performance-hybrid" CPU.
eprintln!("WARNING: Performance-Hybrid CPU detected. `rustc-perf` can't run properly on Efficency cores: test suite will only use Performance cores!");
Some(std::fs::read_to_string("/sys/devices/cpu_core/cpus").unwrap().trim().to_string())
} else {
// If neither dir exists, then something is wrong - `/sys/devices/cpu` has been in Linux for over a decade.
eprintln!("WARNING: neither `/sys/devices/cpu` nor `/sys/devices/cpu_core` present, unable to determine if this CPU has a Performance-Hybrid architecture.");
None
}
});
(*PERFORMANCE_CORES).as_ref()
}

#[cfg(not(target_os = "linux"))]
// Modify this stub if you want to add support for P/E cores on more OSs
fn performance_cores() -> Option<&'static String> {
None
}

#[cfg(target_os = "linux")]
/// Makes the benchmark run only on Performance cores.
fn run_on_p_cores(path: &Path, cpu_list: &str) -> Command {
// Parse CPU list to extract the number of P cores!
// This assumes the P core id's are countinus, in format `fisrt_id-last_id`
let (core_start, core_end) = cpu_list
.split_once("-")
.unwrap_or_else(|| panic!("Unsuported P core list format: {cpu_list:?}."));
let core_start: u32 = core_start
.parse()
.expect("Expected a number when parsing the start of the P core list!");
let core_end: u32 = core_end
.parse()
.expect("Expected a number when parsing the end of the P core list!");
let core_count = core_end - core_start;
let mut cmd = Command::new("taskset");
// Set job count to P core count - this is done for 2 reasons:
// 1. The instruction count info for E core is often very incompleate - a substantial chunk of events is lost.
// 2. The performance charcteristics of E cores are less reliable, so excluding them from the benchmark makes things easier.
cmd.env("CARGO_BUILD_JOBS", format!("{core_count}"));
// pass the P core list to taskset to pin task to the P core.
cmd.arg("--cpu-list");
cmd.arg(cpu_list);
cmd.arg(path);
cmd
}

#[cfg(not(target_os = "linux"))]
// Modify this stub if you want to add support for P/E cores on more OSs
fn run_on_p_cores(_path: &Path, _cpu_list: &str) -> Command {
todo!("Can't run commands on the P cores on this platform");
}

impl<'a> CargoProcess<'a> {
pub fn incremental(mut self, incremental: bool) -> Self {
Expand All @@ -149,7 +210,12 @@ impl<'a> CargoProcess<'a> {
}

fn base_command(&self, cwd: &Path, subcommand: &str) -> Command {
let mut cmd = Command::new(Path::new(&self.toolchain.components.cargo));
// Processors with P and E cores require special handling
let mut cmd = if let Some(p_cores) = performance_cores() {
run_on_p_cores(Path::new(&self.toolchain.components.cargo), p_cores)
} else {
Command::new(Path::new(&self.toolchain.components.cargo))
};
cmd
// Not all cargo invocations (e.g. `cargo clean`) need all of these
// env vars set, but it doesn't hurt to have them.
Expand Down Expand Up @@ -550,7 +616,11 @@ fn process_stat_output(
let mut parts = line.split(';').map(|s| s.trim());
let cnt = get!(parts.next());
let _unit = get!(parts.next());
let name = get!(parts.next());
let mut name = get!(parts.next());
// Map P-core events to normal events
if name == "cpu_core/instructions:u/" {
name = "instructions:u";
}
let _time = get!(parts.next());
let pct = get!(parts.next());
if cnt == "<not supported>" || cnt == "<not counted>" || cnt.is_empty() {
Expand Down

0 comments on commit 2477025

Please sign in to comment.