Skip to content

Commit f91b9c1

Browse files
feat: collect cpu flags in system info
1 parent d3731f7 commit f91b9c1

4 files changed

Lines changed: 112 additions & 4 deletions

src/system/info.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub struct SystemInfo {
3030
pub cpu_vendor_id: String,
3131
pub cpu_cores: usize,
3232
pub total_memory_gb: u64,
33+
pub cpu_flags: Vec<String>,
3334
}
3435

3536
#[cfg(test)]
@@ -46,10 +47,96 @@ impl SystemInfo {
4647
cpu_vendor_id: "GenuineIntel".to_string(),
4748
cpu_cores: 2,
4849
total_memory_gb: 8,
50+
cpu_flags: vec![
51+
"sse2".to_string(),
52+
"avx".to_string(),
53+
"avx2".to_string(),
54+
"erms".to_string(),
55+
],
4956
}
5057
}
5158
}
5259

60+
#[cfg(target_os = "linux")]
61+
fn get_glibc_relevant_cpu_flags() -> Vec<String> {
62+
use procfs::Current;
63+
64+
/// CPU flags that influence glibc's ifunc dispatch (memcpy, strlen, strcmp, etc.)
65+
///
66+
/// x86_64: selected from glibc's ifunc resolver logic:
67+
/// - sysdeps/x86_64/multiarch/ifunc-impl-list.c
68+
/// - sysdeps/x86/include/cpu-features.h
69+
///
70+
/// aarch64: selected from glibc's ifunc resolver logic:
71+
/// - sysdeps/aarch64/multiarch/ifunc-impl-list.c
72+
/// - sysdeps/unix/sysv/linux/aarch64/cpu-features.h
73+
///
74+
/// Source sources: https://sourceware.org/git/?p=glibc.git
75+
#[rustfmt::skip]
76+
const RELEVANT_X86_64_FLAGS: &[&str] = &[
77+
// SIMD
78+
"sse2", "ssse3", "sse4_1", "sse4_2",
79+
// AVX
80+
"avx", "avx2",
81+
// AVX-512
82+
"avx512f", "avx512bw", "avx512vl",
83+
// REP string optimizations
84+
"erms", "fsrm",
85+
// Other flags used in glibc dispatch decisions
86+
"rtm", "bmi1", "bmi2", "popcnt", "fma", "movbe",
87+
];
88+
89+
#[rustfmt::skip]
90+
const RELEVANT_AARCH64_FLAGS: &[&str] = &[
91+
// SVE-optimized memcpy/memmove/memset
92+
"sve",
93+
// Memory Copy/Set instructions (ARMv9, takes priority over SVE)
94+
"mops",
95+
// Memory Tagging Extension (affects memchr/strlen variant selection)
96+
"mte",
97+
// Enables MIDR_EL1 reads for CPU-specific variants (A64FX, Oryon1, etc.)
98+
"cpuid",
99+
];
100+
101+
let cpuinfo = match procfs::CpuInfo::current() {
102+
Ok(cpuinfo) => cpuinfo,
103+
Err(e) => {
104+
warn!("Failed to read /proc/cpuinfo: {e}");
105+
return Vec::new();
106+
}
107+
};
108+
109+
// /proc/cpuinfo uses "flags" on x86_64 and "Features" on aarch64
110+
let (relevant_flags, field_name) = if cfg!(target_arch = "x86_64") {
111+
(RELEVANT_X86_64_FLAGS, "flags")
112+
} else if cfg!(target_arch = "aarch64") {
113+
(RELEVANT_AARCH64_FLAGS, "Features")
114+
} else {
115+
return Vec::new();
116+
};
117+
118+
let all_flags: Vec<&str> = match cpuinfo.get_field(0, field_name) {
119+
Some(value) => value.split_whitespace().collect(),
120+
None => {
121+
warn!("No CPU flags found in /proc/cpuinfo (field: {field_name})");
122+
return Vec::new();
123+
}
124+
};
125+
126+
let mut flags: Vec<String> = all_flags
127+
.into_iter()
128+
.filter(|flag| relevant_flags.contains(flag))
129+
.map(|flag| flag.to_string())
130+
.collect();
131+
flags.sort();
132+
flags
133+
}
134+
135+
#[cfg(not(target_os = "linux"))]
136+
fn get_glibc_relevant_cpu_flags() -> Vec<String> {
137+
Vec::new()
138+
}
139+
53140
impl SystemInfo {
54141
pub fn new() -> Result<Self> {
55142
let os = System::distribution_id();
@@ -85,6 +172,8 @@ impl SystemInfo {
85172
let cpu_name = cpu.name().to_string();
86173
let cpu_vendor_id = cpu.vendor_id().to_string();
87174

175+
let cpu_flags = get_glibc_relevant_cpu_flags();
176+
88177
Ok(SystemInfo {
89178
os,
90179
os_version,
@@ -96,6 +185,7 @@ impl SystemInfo {
96185
cpu_vendor_id,
97186
cpu_cores,
98187
total_memory_gb,
188+
cpu_flags,
99189
})
100190
}
101191
}

src/upload/snapshots/codspeed_runner__upload__upload_metadata__tests__get_local_metadata_hash-2.snap

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,13 @@ expression: upload_metadata
2222
"cpuName": "cpu0",
2323
"cpuVendorId": "GenuineIntel",
2424
"cpuCores": 6,
25-
"totalMemoryGb": 16
25+
"totalMemoryGb": 16,
26+
"cpuFlags": [
27+
"sse2",
28+
"avx",
29+
"avx2",
30+
"erms"
31+
]
2632
},
2733
"runEnvironment": "LOCAL",
2834
"runPart": {

src/upload/snapshots/codspeed_runner__upload__upload_metadata__tests__get_metadata_hash-2.snap

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,13 @@ expression: upload_metadata
2424
"cpuName": "cpu0",
2525
"cpuVendorId": "GenuineIntel",
2626
"cpuCores": 2,
27-
"totalMemoryGb": 8
27+
"totalMemoryGb": 8,
28+
"cpuFlags": [
29+
"sse2",
30+
"avx",
31+
"avx2",
32+
"erms"
33+
]
2834
},
2935
"runEnvironment": "GITHUB_ACTIONS",
3036
"runPart": {

src/upload/upload_metadata.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ mod tests {
7777
hash,
7878
// Caution: when changing this value, we need to ensure that
7979
// the related backend snapshot remains the same
80-
@"b2c6175fa81d4c4c5eb215e2e77667891f33abca9f8614b45899e3ee070bdca6"
80+
@"bcf7fd0b0fcaf597a832478517599e13a0513587c98538cc9f8f8b4dc288e8d4"
8181
);
8282
assert_json_snapshot!(upload_metadata);
8383
}
@@ -106,6 +106,12 @@ mod tests {
106106
cpu_vendor_id: "GenuineIntel".to_string(),
107107
cpu_cores: 6,
108108
total_memory_gb: 16,
109+
cpu_flags: vec![
110+
"sse2".to_string(),
111+
"avx".to_string(),
112+
"avx2".to_string(),
113+
"erms".to_string(),
114+
],
109115
},
110116
},
111117
run_environment: RunEnvironment::Local,
@@ -139,7 +145,7 @@ mod tests {
139145
hash,
140146
// Caution: when changing this value, we need to ensure that
141147
// the related backend snapshot remains the same
142-
@"47b6317da2747edae177d8a99143efc6f7516beb3222b9d45331ba48d4e1c369"
148+
@"00e1df4c32a46e25479c30d5792e46d71f5cfcafb24dda7a5c81c609363aa1f4"
143149
);
144150
assert_json_snapshot!(upload_metadata);
145151
}

0 commit comments

Comments
 (0)