extern crate libc;
use std::ffi::CStr;
use std::mem;
use std::str;
mod ffi;
pub struct CpuInfo {
pub vendor: String,
pub brand: String,
pub codename: String,
pub num_cores: i32,
pub num_logical_cpus: i32,
pub total_logical_cpus: i32,
pub l1_data_cache: Option<i32>,
pub l1_instruction_cache: Option<i32>,
pub l2_cache: Option<i32>,
pub l3_cache: Option<i32>,
flags: [u8; ffi::CPU_FLAGS_MAX],
}
#[derive(Clone, Copy)]
pub enum CpuFeature {
FloatingPointUnit = 0,
VirtualModeExtension,
DebugingExtension,
PageSizeExtension,
TimestampCounter,
ModelSpecificRegisters,
PhysicalAddressExtension,
MachineCheckException,
CMPXCHG8B,
APIC,
MemoryTypeRangeRegisters,
SysenterSysexit,
PageGlobalEnable,
MachineCheckArchitecture,
CMOV,
PageAttributeTable,
PageAddressExtension36bit,
ProcessorSerialNumber,
CLFLUSH,
DebugStore,
ACPI,
MMX,
FXSAVE,
SSE,
SSE2,
SelfSnoop,
HyperThreading,
ThermalMonitor,
IA64,
PendingBreakEnable,
SSE3,
PCLMULQDQ,
DebugStore64,
MONITOR,
CplQualifiedDebugStore,
VirtualisationTechnology,
SaferModeExceptions,
EnhancedSpeedStep,
ThermalMonitor2,
SSSE3,
ContextId,
CMPXCHG16B,
SendTaskPriorityMessages,
PerformanceCapabilitiesMSR,
DirectCacheAccess,
SSE41,
SSE42,
SyscallSysret,
ExecuteDisableBit,
MOVBE,
POPCNT,
AES,
XSAVE,
OSXSAVE,
AdvancedVectorExtensions,
MMXExtensions,
AMD3DNow,
AMD3DNowExtended,
NoExecuteBit,
FXSAVEOptimizations,
RDTSCP,
LongMode,
LAHFLongMode,
CoreMultiProcessingLegacyMode,
AMDSecureVirtualMachine,
LZCNT,
MisalignedSSE,
SSE4a,
PREFETCH,
OsVisibleWorkaround,
InstructionBasedSampling,
SSE5,
SKINIT,
WatchdogTimer,
TemperatureSensor,
FrequencyIDControl,
VoltageIDControl,
THERMTRIP,
AMDThermalControl,
SoftwareThermalControl,
Multiplier100Mhz,
HardwarePstateControl,
ConstantTSCTicks,
XOP,
FMA3,
FMA4,
TrailingBitManipulation,
FPConvert16Bit,
RDRAND,
X2APIC,
CorePerformanceBoost,
MPERF,
ProcessorFeedbackInterface,
ProcessorAccumulator,
NumCpuFeatures,
}
impl CpuInfo {
pub fn has_feature(&self, feature: CpuFeature) -> bool {
self.flags[feature as usize] == 1u8
}
}
pub fn is_present() -> bool {
unsafe { ffi::cpuid_present() == 1 }
}
pub fn version() -> String {
unsafe {
let ptr = ffi::cpuid_lib_version();
let bytes = CStr::from_ptr(ptr).to_bytes();
str::from_utf8(bytes).ok().expect("Invalid UTF8 string").to_string()
}
}
pub fn error() -> String {
unsafe {
let ptr = ffi::cpuid_error();
let bytes = CStr::from_ptr(ptr).to_bytes();
str::from_utf8(bytes).ok().expect("Invalid UTF8 string").to_string()
}
}
pub fn identify() -> Result<CpuInfo, String> {
let mut raw: ffi::cpu_raw_data_t = unsafe { mem::uninitialized() };
let raw_result = unsafe { ffi::cpuid_get_raw_data(&mut raw) };
if raw_result != 0 {
return Err(error());
}
let mut data: ffi::cpu_id_t = unsafe { mem::uninitialized() };
let identify_result = unsafe { ffi::cpu_identify(&mut raw, &mut data) };
if identify_result != 0 {
Err(error())
} else {
Ok(CpuInfo {
vendor: String::from_utf8(data.vendor_str.iter().map(|&x| x as u8).collect())
.ok()
.expect("Invalid vendor string"),
brand: String::from_utf8(data.brand_str.iter().map(|&x| x as u8).collect())
.ok()
.expect("Invalid brand string"),
codename: String::from_utf8(data.cpu_codename.iter().map(|&x| x as u8).collect())
.ok()
.expect("Invalid codename string"),
num_cores: data.num_cores,
num_logical_cpus: data.num_logical_cpus,
total_logical_cpus: data.total_logical_cpus,
l1_data_cache: if data.l1_data_cache != -1 {
Some(data.l1_data_cache)
} else {
None
},
l1_instruction_cache: if data.l1_instruction_cache != -1 {
Some(data.l1_instruction_cache)
} else {
None
},
l2_cache: if data.l2_cache != -1 {
Some(data.l2_cache)
} else {
None
},
l3_cache: if data.l3_cache != -1 {
Some(data.l3_cache)
} else {
None
},
flags: data.flags,
})
}
}
pub fn clock_frequency() -> Option<i32> {
let frequency = unsafe { ffi::cpu_clock() };
if frequency != -1 {
Some(frequency)
} else {
None
}
}
#[test]
fn test_is_present() {
assert!(is_present());
}