diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib.rs | 10 | ||||
-rw-r--r-- | src/perfcnt/intel/counters.rs | 8 | ||||
-rw-r--r-- | src/perfcnt/intel/description.rs | 235 | ||||
-rw-r--r-- | src/perfcnt/intel/mod.rs | 2 | ||||
-rw-r--r-- | src/perfcnt/mod.rs | 68 | ||||
-rw-r--r-- | src/syscall.rs | 14 |
6 files changed, 328 insertions, 9 deletions
@@ -5,17 +5,22 @@ #![crate_name = "x86"] #![crate_type = "lib"] +#[cfg(test)] +#[macro_use] +extern crate std; + #[macro_use] extern crate bitflags; #[macro_use] extern crate raw_cpuid; -#[cfg(test)] -extern crate std; +#[macro_use] +extern crate phf; #[cfg(not(test))] mod std { + pub use core::fmt; pub use core::ops; pub use core::option; } @@ -31,6 +36,7 @@ pub mod segmentation; pub mod task; pub mod dtables; pub mod syscall; +pub mod perfcnt; pub mod cpuid { pub use raw_cpuid::*; }
\ No newline at end of file diff --git a/src/perfcnt/intel/counters.rs b/src/perfcnt/intel/counters.rs new file mode 100644 index 0000000..d05fd5c --- /dev/null +++ b/src/perfcnt/intel/counters.rs @@ -0,0 +1,8 @@ +use phf; +use super::description::IntelPerformanceCounterDescription; +use super::description::Counter; +use super::description::PebsType; +use super::description::Tuple; +use super::description::MSRIndex; + +include!(concat!(env!("OUT_DIR"), "/counters.rs"));
\ No newline at end of file diff --git a/src/perfcnt/intel/description.rs b/src/perfcnt/intel/description.rs new file mode 100644 index 0000000..3093c60 --- /dev/null +++ b/src/perfcnt/intel/description.rs @@ -0,0 +1,235 @@ +use std::fmt; + +pub enum PebsType { + Regular, + PebsOrRegular, + PebsOnly +} + +impl fmt::Debug for PebsType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let name = match *self { + PebsType::Regular => "Regular", + PebsType::PebsOrRegular => "PebsOrRegular", + PebsType::PebsOnly => "PebsOnly", + }; + write!(f, "PebsType::{}", name) + } +} + +pub enum Tuple { + One(u8), + Two(u8,u8) +} + +impl fmt::Debug for Tuple { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Tuple::One(a) => write!(f, "Tuple::One({})", a), + Tuple::Two(a, b) => write!(f, "Tuple::Two({}, {})", a, b), + } + } +} + +pub enum MSRIndex { + None, + One(u8), + Two(u8, u8) +} + +impl fmt::Debug for MSRIndex { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + MSRIndex::None => write!(f, "MSRIndex::None"), + MSRIndex::One(a) => write!(f, "MSRIndex::One({})", a), + MSRIndex::Two(a, b) => write!(f, "MSRIndex::Two({}, {})", a, b), + } + } +} + +pub enum Counter { + /// Bit-mask containing the fixed counters + /// usable with the corresponding performance event. + Fixed(u8), + + /// Bit-mask containing the programmable counters + /// usable with the corresponding performance event. + Programmable(u8), +} + +impl fmt::Debug for Counter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Counter::Fixed(a) => write!(f, "Counter::Fixed({})", a), + Counter::Programmable(a) => write!(f, "Counter::Programmable({})", a), + } + } +} + +#[derive(Debug)] +pub struct IntelPerformanceCounterDescription { + + /// This field maps to the Event Select field in the IA32_PERFEVTSELx[7:0]MSRs. + /// + /// The set of values for this field is defined architecturally. + /// Each value corresponds to an event logic unit and should be used with a unit + /// mask value to obtain an architectural performance event. + pub event_code: Tuple, + + /// This field maps to the Unit Mask filed in the IA32_PERFEVTSELx[15:8] MSRs. + /// + /// It further qualifies the event logic unit selected in the event select + /// field to detect a specific micro-architectural condition. + pub umask: Tuple, + + /// It is a string of characters to identify the programming of an event. + pub event_name: &'static str, + + /// This field contains a description of what is being counted by a particular event. + pub brief_description: &'static str, + + /// In some cases, this field will contain a more detailed description of what is counted by an event. + pub public_description: Option<&'static str>, + + /// This field lists the fixed (PERF_FIXED_CTRX) or programmable (IA32_PMCX) + /// counters that can be used to count the event. + pub counter: Counter, + + /// This field lists the counters where this event can be sampled + /// when Intel® Hyper-Threading Technology (Intel® HT Technology) is + /// disabled. + /// + /// When Intel® HT Technology is disabled, some processor cores gain access to + /// the programmable counters of the second thread, making a total of eight + /// programmable counters available. The additional counters will be + /// numbered 4,5,6,7. Fixed counter behavior remains unaffected. + pub counter_ht_off: Counter, + + /// This field is only relevant to PEBS events. + /// + /// It lists the counters where the event can be sampled when it is programmed as a PEBS event. + pub pebs_counters: Option<Counter>, + + /// Sample After Value (SAV) is the value that can be preloaded + /// into the counter registers to set the point at which they will overflow. + /// + /// To make the counter overflow after N occurrences of the event, + /// it should be loaded with (0xFF..FF – N) or –(N-1). On overflow a + /// hardware interrupt is generated through the Local APIC and additional + /// architectural state can be collected in the interrupt handler. + /// This is useful in event-based sampling. This field gives a recommended + /// default overflow value, which may be adjusted based on workload or tool preference. + pub sample_after_value: u64, + + /// Additional MSRs may be required for programming certain events. + /// This field gives the address of such MSRS. + pub msr_index: MSRIndex, + + /// When an MSRIndex is used (indicated by the MSRIndex column), this field will + /// contain the value that needs to be loaded into the + /// register whose address is given in MSRIndex column. + /// + /// For example, in the case of the load latency events, MSRValue defines the + /// latency threshold value to write into the MSR defined in MSRIndex (0x3F6). + pub msr_value: u64, + + /// This field is set for an event which can only be sampled or counted by itself, + /// meaning that when this event is being collected, + /// the remaining programmable counters are not available to count any other events. + pub taken_alone: bool, + + /// This field maps to the Counter Mask (CMASK) field in IA32_PERFEVTSELx[31:24] MSR. + pub counter_mask: u8, + + /// This field corresponds to the Invert Counter Mask (INV) field in IA32_PERFEVTSELx[23] MSR. + pub invert: bool, + + /// This field corresponds to the Any Thread (ANY) bit of IA32_PERFEVTSELx[21] MSR. + pub any_thread: bool, + + /// This field corresponds to the Edge Detect (E) bit of IA32_PERFEVTSELx[18] MSR. + pub edge_detect: bool, + + /// A '0' in this field means that the event cannot be programmed as a PEBS event. + /// A '1' in this field means that the event is a precise event and can be programmed + /// in one of two ways – as a regular event or as a PEBS event. + /// And a '2' in this field means that the event can only be programmed as a PEBS event. + pub pebs: PebsType, + + /// A '1' in this field means the event uses the Precise Store feature and Bit 3 and + /// bit 63 in IA32_PEBS_ENABLE MSR must be set to enable IA32_PMC3 as a PEBS counter + /// and enable the precise store facility respectively. + /// + /// Processors based on SandyBridge and IvyBridge micro-architecture offer a + /// precise store capability that provides a means to profile store memory + /// references in the system. + pub precise_store: bool, + + /// A '1' in this field means that when the event is configured as a PEBS event, + /// the Data Linear Address facility is supported. + /// + /// The Data Linear Address facility is a new feature added to Haswell as a + /// replacement or extension of the precise store facility in SNB. + pub data_la: bool, + + /// A '1' in this field means that when the event is configured as a PEBS event, + /// the DCU hit field of the PEBS record is set to 1 when the store hits in the + /// L1 cache and 0 when it misses. + pub l1_hit_indication: bool, + + /// This field lists the known bugs that apply to the events. + /// + /// For the latest, up to date errata refer to the following links: + //// + /// * Haswell: + /// http://www.intel.com/content/dam/www/public/us/en/documents/specification-updates/4th-gen-core-family-mobile-specification-update.pdf + /// + /// * IvyBridge: + /// https://www-ssl.intel.com/content/dam/www/public/us/en/documents/specification-updates/3rd-gen-core-desktop-specification-update.pdf + /// + /// * SandyBridge: + /// https://www-ssl.intel.com/content/dam/www/public/us/en/documents/specification-updates/2nd-gen-core-family-mobile-specification-update.pdf + pub errata: Option<&'static str>, + + /// There is only 1 file for core and offcore events in this format. + /// This field is set to 1 for offcore events and 0 for core events. + pub offcore: bool, +} + +impl IntelPerformanceCounterDescription { + + #[allow(dead_code)] + fn new(event_code: Tuple, umask: Tuple, event_name: &'static str, + brief_description: &'static str, public_description: Option<&'static str>, + counter: Counter, counter_ht_off: Counter, pebs_counters: Option<Counter>, + sample_after_value: u64, msr_index: MSRIndex, msr_value: u64, taken_alone: bool, + counter_mask: u8, invert: bool, any_thread: bool, edge_detect: bool, pebs: + PebsType, precise_store: bool, data_la: bool, l1_hit_indication: bool, + errata: Option<&'static str>, offcore: bool) -> IntelPerformanceCounterDescription { + + IntelPerformanceCounterDescription { + event_code: event_code, + umask: umask, + event_name: event_name, + brief_description: brief_description, + public_description: public_description, + counter: counter, + counter_ht_off: counter_ht_off, + pebs_counters: pebs_counters, + sample_after_value: sample_after_value, + msr_index: msr_index, + msr_value: msr_value, + taken_alone: taken_alone, + counter_mask: counter_mask, + invert: invert, + any_thread: any_thread, + edge_detect: edge_detect, + pebs: pebs, + precise_store: precise_store, + data_la: data_la, + l1_hit_indication: l1_hit_indication, + errata: errata, + offcore: offcore + } + } +} diff --git a/src/perfcnt/intel/mod.rs b/src/perfcnt/intel/mod.rs new file mode 100644 index 0000000..25b22dc --- /dev/null +++ b/src/perfcnt/intel/mod.rs @@ -0,0 +1,2 @@ +pub mod counters; +pub mod description;
\ No newline at end of file diff --git a/src/perfcnt/mod.rs b/src/perfcnt/mod.rs new file mode 100644 index 0000000..95edf9d --- /dev/null +++ b/src/perfcnt/mod.rs @@ -0,0 +1,68 @@ +use super::cpuid; +use phf; + +pub mod intel; + +use core::fmt::{Write, Result}; +use core::str; + +/* +pub trait Write { + + fn write_char(&mut self, c: char) -> Result { ... } + fn write_fmt(&mut self, args: Arguments) -> Result { ... } +}*/ + +#[derive(Default)] +struct ModelWriter { + buffer: [u8; 20], + index: usize +} + +impl ModelWriter { + fn as_str(&self) -> &str { + str::from_utf8(&self.buffer).unwrap() + } +} + +impl Write for ModelWriter { + fn write_str(&mut self, s: &str) -> Result { + for c in s.chars() { + self.buffer[self.index] = c as u8; + self.index += 1; + } + Ok(()) + } +} + +/// Return performance counter description for the running micro-architecture. +pub fn available_counters() -> Option<&'static phf::Map<&'static str, intel::description::IntelPerformanceCounterDescription>> { + + let cpuid = cpuid::CpuId::new(); + + cpuid.get_vendor_info().map(|vf| { + cpuid.get_feature_info().map(|fi| { + let vendor = vf.as_string(); + let (family, extended_model, model) = (fi.family_id(), fi.extended_model_id(), fi.model_id()); + + let mut writer: ModelWriter = Default::default(); + let res = write!(writer, "{}-{}-{:X}{:X}", vendor, family, extended_model, model); + let key = writer.as_str(); + + match intel::counters::COUNTER_MAP.contains_key(key) { + true => return Some(intel::counters::COUNTER_MAP[key]), + false => return None + }; + }); + }); + + None +} + +#[cfg(test)] +#[test] +fn list_mine() { + for counter in available_counters() { + println!("{:?}", counter); + } +}
\ No newline at end of file diff --git a/src/syscall.rs b/src/syscall.rs index a1fa036..61e9ee7 100644 --- a/src/syscall.rs +++ b/src/syscall.rs @@ -42,14 +42,14 @@ macro_rules! syscall { #[inline(always)] pub unsafe fn syscall0(arg0: u64) -> u64 { - let mut ret: u64; + let ret: u64; asm!("syscall" : "={rax}" (ret) : "{rax}" (arg0) : "rcx", "r11", "memory" : "volatile"); ret } #[inline(always)] pub unsafe fn syscall1(arg0: u64, arg1: u64) -> u64 { - let mut ret: u64; + let ret: u64; asm!("syscall" : "={rax}" (ret) : "{rax}" (arg0), "{rdi}" (arg1) : "rcx", "r11", "memory" : "volatile"); ret @@ -57,7 +57,7 @@ pub unsafe fn syscall1(arg0: u64, arg1: u64) -> u64 { #[inline(always)] pub unsafe fn syscall2(arg0: u64, arg1: u64, arg2: u64) -> u64 { - let mut ret: u64; + let ret: u64; asm!("syscall" : "={rax}" (ret) : "{rax}" (arg0), "{rdi}" (arg1), "{rsi}" (arg2) : "rcx", "r11", "memory" : "volatile"); ret @@ -65,7 +65,7 @@ pub unsafe fn syscall2(arg0: u64, arg1: u64, arg2: u64) -> u64 { #[inline(always)] pub unsafe fn syscall3(arg0: u64, arg1: u64, arg2: u64, arg3: u64) -> u64 { - let mut ret: u64; + let ret: u64; asm!("syscall" : "={rax}" (ret) : "{rax}" (arg0), "{rdi}" (arg1), "{rsi}" (arg2), "{rdx}" (arg3) : "rcx", "r11", "memory" : "volatile"); ret @@ -73,7 +73,7 @@ pub unsafe fn syscall3(arg0: u64, arg1: u64, arg2: u64, arg3: u64) -> u64 { #[inline(always)] pub unsafe fn syscall4(arg0: u64, arg1: u64, arg2: u64, arg3: u64, arg4: u64) -> u64 { - let mut ret: u64; + let ret: u64; asm!("syscall" : "={rax}" (ret) : "{rax}" (arg0), "{rdi}" (arg1), "{rsi}" (arg2), "{rdx}" (arg3), "{r10}" (arg4) : "rcx", "r11", "memory" : "volatile"); @@ -82,7 +82,7 @@ pub unsafe fn syscall4(arg0: u64, arg1: u64, arg2: u64, arg3: u64, arg4: u64) -> #[inline(always)] pub unsafe fn syscall5(arg0: u64, arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 { - let mut ret: u64; + let ret: u64; asm!("syscall" : "={rax}" (ret) : "{rax}" (arg0), "{rdi}" (arg1), "{rsi}" (arg2), "{rdx}" (arg3), "{r10}" (arg4), "{r8}" (arg5) : "rcx", "r11", "memory" @@ -92,7 +92,7 @@ pub unsafe fn syscall5(arg0: u64, arg1: u64, arg2: u64, arg3: u64, arg4: u64, ar #[inline(always)] pub unsafe fn syscall6(arg0: u64, arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64, arg6: u64) -> u64 { - let mut ret: u64; + let ret: u64; asm!("syscall" : "={rax}" (ret) : "{rax}" (arg0), "{rdi}" (arg1), "{rsi}" (arg2), "{rdx}" (arg3), "{r10}" (arg4), "{r8}" (arg5), "{r9}" (arg6) |