aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs10
-rw-r--r--src/perfcnt/intel/counters.rs8
-rw-r--r--src/perfcnt/intel/description.rs235
-rw-r--r--src/perfcnt/intel/mod.rs2
-rw-r--r--src/perfcnt/mod.rs68
-rw-r--r--src/syscall.rs14
6 files changed, 328 insertions, 9 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 0c06be5..79a60c3 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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)