extern crate libc;
use std::c_str::CString;
use std::mem;
mod ffi;
pub struct CpuInfo {
pub vendor: String,
pub brand: String,
pub codename: String,
pub num_cores: int,
pub num_logical_cpus: int,
pub total_logical_cpus: int,
pub l1_data_cache: Option<int>,
pub l1_instruction_cache: Option<int>,
pub l2_cache: Option<int>,
pub l3_cache: Option<int>,
flags: [u8; ffi::CPU_FLAGS_MAX],
}
#[derive(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 {
return self.flags[feature as uint] == 1u8
}
}
pub fn is_present() -> bool {
unsafe {
ffi::cpuid_present() == 1
}
}
pub fn version() -> String {
let version_string = unsafe {
let ptr = ffi::cpuid_lib_version();
CString::new(ptr, false)
};
version_string.as_str().unwrap().to_string()
}
pub fn error() -> String {
let error_string = unsafe {
let ptr = ffi::cpuid_error();
CString::new(ptr, false)
};
error_string.as_str().unwrap().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 as int,
num_logical_cpus: data.num_logical_cpus as int,
total_logical_cpus: data.total_logical_cpus as int,
l1_data_cache: if data.l1_data_cache != -1 { Some(data.l1_data_cache as int) } else { None },
l1_instruction_cache: if data.l1_instruction_cache != -1 { Some(data.l1_instruction_cache as int) } else { None },
l2_cache: if data.l2_cache != -1 { Some(data.l2_cache as int) } else { None },
l3_cache: if data.l3_cache != -1 { Some(data.l3_cache as int) } else { None },
flags: data.flags,
})
}
}
pub fn clock_frequency() -> Option<int> {
let frequency = unsafe {
ffi::cpu_clock()
};
if frequency != -1 {
Some(frequency as int)
} else {
None
}
}
#[test]
fn test_is_present() {
assert!(is_present());
}