summaryrefslogtreecommitdiffstats
path: root/third_party/rust/raw-cpuid/examples
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/raw-cpuid/examples
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/raw-cpuid/examples')
-rw-r--r--third_party/rust/raw-cpuid/examples/cache.rs52
-rw-r--r--third_party/rust/raw-cpuid/examples/cpu.rs27
-rw-r--r--third_party/rust/raw-cpuid/examples/topology.rs196
-rw-r--r--third_party/rust/raw-cpuid/examples/tsc_frequency.rs80
4 files changed, 355 insertions, 0 deletions
diff --git a/third_party/rust/raw-cpuid/examples/cache.rs b/third_party/rust/raw-cpuid/examples/cache.rs
new file mode 100644
index 0000000000..f71d22cdee
--- /dev/null
+++ b/third_party/rust/raw-cpuid/examples/cache.rs
@@ -0,0 +1,52 @@
+//! Example that displays information about the caches.
+extern crate raw_cpuid;
+use raw_cpuid::{CacheType, CpuId};
+
+fn main() {
+ let cpuid = CpuId::new();
+ cpuid.get_cache_parameters().map_or_else(
+ || println!("No cache parameter information available"),
+ |cparams| {
+ for cache in cparams {
+ let size = cache.associativity()
+ * cache.physical_line_partitions()
+ * cache.coherency_line_size()
+ * cache.sets();
+
+ let typ = match cache.cache_type() {
+ CacheType::Data => "Instruction-Cache",
+ CacheType::Instruction => "Data-Cache",
+ CacheType::Unified => "Unified-Cache",
+ _ => "Unknown cache type",
+ };
+
+ let associativity = if cache.is_fully_associative() {
+ format!("fully associative")
+ } else {
+ format!("{}-way associativity", cache.associativity())
+ };
+
+ let size_repr = if size > 1024 * 1024 {
+ format!("{} MiB", size / (1024 * 1024))
+ } else {
+ format!("{} KiB", size / 1024)
+ };
+
+ let mapping = if cache.has_complex_indexing() {
+ "hash-based-mapping"
+ } else {
+ "direct-mapped"
+ };
+
+ println!(
+ "L{} {}: ({}, {}, {})",
+ cache.level(),
+ typ,
+ size_repr,
+ associativity,
+ mapping
+ );
+ }
+ },
+ );
+}
diff --git a/third_party/rust/raw-cpuid/examples/cpu.rs b/third_party/rust/raw-cpuid/examples/cpu.rs
new file mode 100644
index 0000000000..d6812916b9
--- /dev/null
+++ b/third_party/rust/raw-cpuid/examples/cpu.rs
@@ -0,0 +1,27 @@
+//! An example that displays the type/features/configuration of the CPU.
+extern crate raw_cpuid;
+
+fn main() {
+ let cpuid = raw_cpuid::CpuId::new();
+
+ let vendor_string = cpuid.get_vendor_info().map_or_else(
+ || String::from("Unknown Vendor"),
+ |vf| String::from(vf.as_string()),
+ );
+
+ let brand_string: String = cpuid.get_extended_function_info().map_or_else(
+ || String::from("Unknown CPU"),
+ |extfuninfo| {
+ println!("{:?}", extfuninfo.extended_signature());
+ String::from(extfuninfo.processor_brand_string().unwrap_or("Unknown CPU"))
+ },
+ );
+
+ /*let serial_nr = cpuid.get_processor_serial().map_or_else(
+ || String::from(""),
+ |extfuninfo| String::from(extfuninfo.processor_brand_string().unwrap_or("Unknown CPU")),
+ );*/
+
+ println!("Vendor is: {}", vendor_string);
+ println!("CPU Model is: {}", brand_string);
+}
diff --git a/third_party/rust/raw-cpuid/examples/topology.rs b/third_party/rust/raw-cpuid/examples/topology.rs
new file mode 100644
index 0000000000..fe023454d5
--- /dev/null
+++ b/third_party/rust/raw-cpuid/examples/topology.rs
@@ -0,0 +1,196 @@
+//! An example that uses CPUID to determine the system topology.
+//!
+//! Intel Topology is a pretty complicated subject (unfortunately):
+//! https://software.intel.com/en-us/articles/intel-64-architecture-processor-topology-enumeration/
+extern crate core_affinity;
+extern crate raw_cpuid;
+
+use raw_cpuid::{CpuId, ExtendedTopologyLevel, TopologyType};
+use std::thread;
+
+/// Runs CPU ID on every core in the system (to gather all APIC IDs).
+///
+/// # Note
+/// This won't work on macOS, apparently there is no guarantee after setting the affinity
+/// that a thread will really execute on the pinned core.
+fn gather_all_xapic_ids() -> Vec<u8> {
+ let core_ids = core_affinity::get_core_ids().unwrap();
+
+ // Create a thread for each active CPU core.
+ core_ids
+ .into_iter()
+ .map(|id| {
+ thread::spawn(move || {
+ // Pin this thread to a single CPU core.
+ core_affinity::set_for_current(id);
+ // Do more work after this.
+ let cpuid = CpuId::new();
+ cpuid
+ .get_feature_info()
+ .map_or_else(|| 0, |finfo| finfo.initial_local_apic_id())
+ })
+ .join()
+ .unwrap_or(0)
+ })
+ .collect::<Vec<_>>()
+}
+
+/// Runs CPU ID on every core in the system (to gather all x2APIC IDs).
+///
+/// # Note
+/// This won't work on macOS, apparently there is no guarantee after setting the affinity
+/// that a thread will really execute on the pinned core.
+fn gather_all_x2apic_ids() -> Vec<u32> {
+ let core_ids = core_affinity::get_core_ids().unwrap();
+
+ // Create a thread for each active CPU core.
+ core_ids
+ .into_iter()
+ .map(|id| {
+ thread::spawn(move || {
+ // Pin this thread to a single CPU core.
+ core_affinity::set_for_current(id);
+ // Do more work after this.
+ let cpuid = CpuId::new();
+ cpuid.get_extended_topology_info().map_or_else(
+ || 0,
+ |mut topiter| topiter.next().as_ref().unwrap().x2apic_id(),
+ )
+ })
+ .join()
+ .unwrap_or(0)
+ })
+ .collect::<Vec<_>>()
+}
+
+fn enumerate_with_extended_topology_info() {
+ let cpuid = CpuId::new();
+ let mut smt_x2apic_shift: u32 = 0;
+ let mut core_x2apic_shift: u32 = 0;
+
+ cpuid.get_extended_topology_info().map_or_else(
+ || println!("No topology information available."),
+ |topoiter| {
+ let topology: Vec<ExtendedTopologyLevel> = topoiter.collect();
+ for topolevel in topology.iter() {
+ match topolevel.level_type() {
+ TopologyType::SMT => {
+ smt_x2apic_shift = topolevel.shift_right_for_next_apic_id();
+ }
+ TopologyType::Core => {
+ core_x2apic_shift = topolevel.shift_right_for_next_apic_id();
+ }
+ _ => panic!("Topology category not supported."),
+ };
+ }
+ },
+ );
+
+ println!("Enumeration of all cores in the system (with x2APIC IDs):");
+ let mut all_x2apic_ids: Vec<u32> = gather_all_x2apic_ids();
+ all_x2apic_ids.sort();
+ for x2apic_id in all_x2apic_ids {
+ let smt_select_mask = !(u32::max_value() << smt_x2apic_shift);
+ let core_select_mask = (!((u32::max_value()) << core_x2apic_shift)) ^ smt_select_mask;
+ let pkg_select_mask = u32::max_value() << core_x2apic_shift;
+
+ let smt_id = x2apic_id & smt_select_mask;
+ let core_id = (x2apic_id & core_select_mask) >> smt_x2apic_shift;
+ let pkg_id = (x2apic_id & pkg_select_mask) >> core_x2apic_shift;
+
+ println!(
+ "x2APIC#{} (pkg: {}, core: {}, smt: {})",
+ x2apic_id, pkg_id, core_id, smt_id
+ );
+ }
+}
+
+fn enumerate_with_legacy_leaf_1_4() {
+ let cpuid = CpuId::new();
+ let max_logical_processor_ids = cpuid
+ .get_feature_info()
+ .map_or_else(|| 0, |finfo| finfo.max_logical_processor_ids());
+
+ let mut smt_max_cores_for_package: u8 = 0;
+ cpuid.get_cache_parameters().map_or_else(
+ || println!("No cache parameter information available"),
+ |cparams| {
+ for (ecx, cache) in cparams.enumerate() {
+ if ecx == 0 {
+ smt_max_cores_for_package = cache.max_cores_for_package() as u8;
+ }
+ }
+ },
+ );
+
+ fn log2(o: u8) -> u8 {
+ 7 - o.leading_zeros() as u8
+ }
+
+ let smt_mask_width: u8 =
+ log2(max_logical_processor_ids.next_power_of_two() / (smt_max_cores_for_package));
+ let smt_select_mask: u8 = !(u8::max_value() << smt_mask_width);
+
+ let core_mask_width: u8 = log2(smt_max_cores_for_package);
+ let core_only_select_mask =
+ (!(u8::max_value() << (core_mask_width + smt_mask_width))) ^ smt_select_mask;
+
+ let pkg_select_mask = u8::max_value() << (core_mask_width + smt_mask_width);
+
+ println!("Enumeration of all cores in the system (with APIC IDs):");
+ let mut all_xapic_ids: Vec<u8> = gather_all_xapic_ids();
+ all_xapic_ids.sort();
+
+ for xapic_id in all_xapic_ids {
+ let smt_id = xapic_id & smt_select_mask;
+ let core_id = (xapic_id & core_only_select_mask) >> smt_mask_width;
+ let pkg_id = (xapic_id & pkg_select_mask) >> (core_mask_width + smt_mask_width);
+
+ println!(
+ "APIC#{} (pkg: {}, core: {}, smt: {})",
+ xapic_id, pkg_id, core_id, smt_id
+ );
+ }
+}
+
+fn main() {
+ let cpuid = CpuId::new();
+
+ cpuid.get_extended_function_info().map_or_else(
+ || println!("Couldn't find processor serial number."),
+ |extfuninfo| {
+ println!(
+ "CPU Model is: {}",
+ extfuninfo.processor_brand_string().unwrap_or("Unknown CPU")
+ )
+ },
+ );
+ cpuid.get_extended_topology_info().map_or_else(
+ || println!("No topology information available."),
+ |topoiter| {
+ let mut topology: Vec<ExtendedTopologyLevel> = topoiter.collect();
+ topology.reverse();
+
+ for topolevel in topology.iter() {
+ let typ = match topolevel.level_type() {
+ TopologyType::SMT => "SMT-threads",
+ TopologyType::Core => "cores",
+ _ => panic!("Topology category not supported."),
+ };
+
+ println!(
+ "At level {} the CPU has: {} {}",
+ topolevel.level_number(),
+ topolevel.processors(),
+ typ,
+ );
+ }
+ },
+ );
+
+ println!("");
+ enumerate_with_legacy_leaf_1_4();
+
+ println!("");
+ enumerate_with_extended_topology_info();
+}
diff --git a/third_party/rust/raw-cpuid/examples/tsc_frequency.rs b/third_party/rust/raw-cpuid/examples/tsc_frequency.rs
new file mode 100644
index 0000000000..8c7d671a33
--- /dev/null
+++ b/third_party/rust/raw-cpuid/examples/tsc_frequency.rs
@@ -0,0 +1,80 @@
+//! An example that determines the time stamp counter frequency (RDTSC, RDTSCP) .
+extern crate raw_cpuid;
+
+use std::time;
+
+const MHZ_TO_HZ: u64 = 1000000;
+const KHZ_TO_HZ: u64 = 1000;
+
+fn main() {
+ let cpuid = raw_cpuid::CpuId::new();
+ let has_tsc = cpuid
+ .get_feature_info()
+ .map_or(false, |finfo| finfo.has_tsc());
+
+ let has_invariant_tsc = cpuid
+ .get_extended_function_info()
+ .map_or(false, |efinfo| efinfo.has_invariant_tsc());
+
+ let tsc_frequency_hz = cpuid.get_tsc_info().map(|tinfo| {
+ if tinfo.nominal_frequency() != 0 {
+ Some(tinfo.tsc_frequency())
+ } else if tinfo.numerator() != 0 && tinfo.denominator() != 0 {
+ // Skylake and Kabylake don't report the crystal clock, approximate with base frequency:
+ cpuid
+ .get_processor_frequency_info()
+ .map(|pinfo| pinfo.processor_base_frequency() as u64 * MHZ_TO_HZ)
+ .map(|cpu_base_freq_hz| {
+ let crystal_hz =
+ cpu_base_freq_hz * tinfo.denominator() as u64 / tinfo.numerator() as u64;
+ crystal_hz * tinfo.numerator() as u64 / tinfo.denominator() as u64
+ })
+ } else {
+ None
+ }
+ });
+
+ if has_tsc {
+ // Try to figure out TSC frequency with CPUID
+ println!(
+ "TSC Frequency is: {} ({})",
+ match tsc_frequency_hz {
+ Some(x) => format!("{} Hz", x.unwrap_or(0)),
+ None => String::from("unknown"),
+ },
+ if has_invariant_tsc {
+ "invariant"
+ } else {
+ "TSC frequency varies with speed-stepping"
+ }
+ );
+
+ // Check if we run in a VM and the hypervisor can give us the TSC frequency
+ cpuid.get_hypervisor_info().map(|hv| {
+ hv.tsc_frequency().map(|tsc_khz| {
+ let virtual_tsc_frequency_hz = tsc_khz as u64 * KHZ_TO_HZ;
+ println!(
+ "Hypervisor reports TSC Frequency at: {} Hz",
+ virtual_tsc_frequency_hz
+ );
+ })
+ });
+
+ // Determine TSC frequency by measuring it (loop for a second, record ticks)
+ let one_second = time::Duration::from_secs(1);
+ let now = time::Instant::now();
+ let start = unsafe { core::arch::x86_64::_rdtsc() };
+ loop {
+ if now.elapsed() >= one_second {
+ break;
+ }
+ }
+ let end = unsafe { core::arch::x86_64::_rdtsc() };
+ println!(
+ "Empirical measurement of TSC frequency was: {} Hz",
+ (end - start)
+ );
+ } else {
+ println!("System does not have a TSC.")
+ }
+}