diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/raw-cpuid/examples | |
parent | Initial commit. (diff) | |
download | firefox-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.rs | 52 | ||||
-rw-r--r-- | third_party/rust/raw-cpuid/examples/cpu.rs | 27 | ||||
-rw-r--r-- | third_party/rust/raw-cpuid/examples/topology.rs | 196 | ||||
-rw-r--r-- | third_party/rust/raw-cpuid/examples/tsc_frequency.rs | 80 |
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.") + } +} |