-
Notifications
You must be signed in to change notification settings - Fork 288
non-x86 runtime detection updates #229
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
//! Reads /proc/self/auxv on Linux systems | ||
|
||
use std::prelude::v1::*; | ||
use std::slice; | ||
use std::mem; | ||
|
||
/// Simple abstraction for the ELF Auxiliary Vector | ||
/// | ||
/// the elf.h provide the layout of the single entry as auxv_t. | ||
/// The desugared version is a usize tag followed by a union with | ||
/// the same storage size. | ||
/// | ||
/// Cache only the HWCAP and HWCAP2 entries. | ||
#[derive(Debug)] | ||
pub struct AuxVec { | ||
hwcap: Option<usize>, | ||
hwcap2: Option<usize>, | ||
} | ||
|
||
#[derive(Clone, Debug, PartialEq)] | ||
#[allow(dead_code)] | ||
/// ELF Auxiliary vector entry types | ||
/// | ||
/// The entry types are specified in [linux/auxvec.h][auxvec_h]. | ||
/// | ||
/// [auxvec_h]: https://github.com/torvalds/linux/blob/master/include/uapi/linux/auxvec.h | ||
pub enum AT { | ||
/// CPU Hardware capabilities, it is a bitfield. | ||
HWCAP = 16, | ||
/// CPU Hardware capabilities, additional bitfield. | ||
HWCAP2 = 26, | ||
} | ||
|
||
impl AuxVec { | ||
/// Reads the ELF Auxiliary Vector | ||
/// | ||
/// Try to read `/proc/self/auxv`. | ||
// TODO: Make use of getauxval once it is available in a | ||
// reliable way. | ||
pub fn new() -> Result<Self, ::std::io::Error> { | ||
use std::io::Read; | ||
let mut file = ::std::fs::File::open("/proc/self/auxv")?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Apparently it is common on Android for this file to not be readable (permissions wise), but |
||
let mut buf = [0usize; 64]; | ||
let mut raw = unsafe { | ||
slice::from_raw_parts_mut( | ||
buf.as_mut_ptr() as *mut u8, | ||
buf.len() * mem::size_of::<usize>(), | ||
) | ||
}; | ||
|
||
let _ = file.read(&mut raw)?; | ||
|
||
mem::forget(raw); | ||
|
||
let mut auxv = AuxVec { hwcap: None, hwcap2: None }; | ||
|
||
for el in buf.chunks(2) { | ||
if el[0] == AT::HWCAP as usize { | ||
auxv.hwcap = Some(el[1]); | ||
} | ||
if el[0] == AT::HWCAP2 as usize { | ||
auxv.hwcap2 = Some(el[1]); | ||
} | ||
} | ||
|
||
Ok(auxv) | ||
} | ||
|
||
/// Returns the value for the AT key | ||
pub fn lookup(&self, key: AT) -> Option<usize> { | ||
match key { | ||
AT::HWCAP => self.hwcap, | ||
AT::HWCAP2 => self.hwcap2, | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know if its easily possible but we should try to refactor this a bit so that we can test it by adding one or two dumps of auxv for arm cpus. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do not have an arm system handy right now, could somebody else do that? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah just open an issue and tag it here. Otherwise you can also try googling for dumps of auxv, maybe you get lucky :D There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually it won't work since the auxv entry size is system dependent so the synthetic 32bit tests would fail on 64bit platforms. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My idea is to avoid There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Before we go to the extent of bypassing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assume that the Apparently it would be within the 50-lines range. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @lu-zero I thought that the @marshallpierce once There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @lu-zero if you want to pursue this a good way to get initial feedback is to fill an issue with your thoughts on the matter, we are kind of mixing many different discussions in this PR, and while many are subscribed to the issues in this repo, most of them are probably not being notified about any of this. |
||
#[cfg(target_os = "linux")] | ||
#[test] | ||
fn test_auxvec_linux() { | ||
let auxvec = AuxVec::new().unwrap(); | ||
println!("{:?}", auxvec.lookup(AT::HWCAP)); | ||
println!("{:?}", auxvec); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -214,4 +214,89 @@ CPU revision : 1"; | |
assert!(cpuinfo.field("Features").has("neon")); | ||
assert!(cpuinfo.field("Features").has("asimd")); | ||
} | ||
|
||
const POWER8E_POWERKVM: &str = r"processor : 0 | ||
cpu : POWER8E (raw), altivec supported | ||
clock : 3425.000000MHz | ||
revision : 2.1 (pvr 004b 0201) | ||
|
||
processor : 1 | ||
cpu : POWER8E (raw), altivec supported | ||
clock : 3425.000000MHz | ||
revision : 2.1 (pvr 004b 0201) | ||
|
||
processor : 2 | ||
cpu : POWER8E (raw), altivec supported | ||
clock : 3425.000000MHz | ||
revision : 2.1 (pvr 004b 0201) | ||
|
||
processor : 3 | ||
cpu : POWER8E (raw), altivec supported | ||
clock : 3425.000000MHz | ||
revision : 2.1 (pvr 004b 0201) | ||
|
||
timebase : 512000000 | ||
platform : pSeries | ||
model : IBM pSeries (emulated by qemu) | ||
machine : CHRP IBM pSeries (emulated by qemu)"; | ||
|
||
#[test] | ||
fn test_cpuinfo_linux_power8_powerkvm() { | ||
let cpuinfo = CpuInfo::from_str(POWER8E_POWERKVM).unwrap(); | ||
assert_eq!(cpuinfo.field("cpu"), "POWER8E (raw), altivec supported"); | ||
|
||
assert!(cpuinfo.field("cpu").has("altivec")); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks great, thanks! Could you add a second test for a CPU without altivec, like for example this one: https://github.com/randombit/cpuinfo/blob/master/ppc/power5 ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @lu-zero it looks like the Power5 test got lost in the merge? |
||
|
||
const POWER5P: &str = r"processor : 0 | ||
cpu : POWER5+ (gs) | ||
clock : 1900.098000MHz | ||
revision : 2.1 (pvr 003b 0201) | ||
|
||
processor : 1 | ||
cpu : POWER5+ (gs) | ||
clock : 1900.098000MHz | ||
revision : 2.1 (pvr 003b 0201) | ||
|
||
processor : 2 | ||
cpu : POWER5+ (gs) | ||
clock : 1900.098000MHz | ||
revision : 2.1 (pvr 003b 0201) | ||
|
||
processor : 3 | ||
cpu : POWER5+ (gs) | ||
clock : 1900.098000MHz | ||
revision : 2.1 (pvr 003b 0201) | ||
|
||
processor : 4 | ||
cpu : POWER5+ (gs) | ||
clock : 1900.098000MHz | ||
revision : 2.1 (pvr 003b 0201) | ||
|
||
processor : 5 | ||
cpu : POWER5+ (gs) | ||
clock : 1900.098000MHz | ||
revision : 2.1 (pvr 003b 0201) | ||
|
||
processor : 6 | ||
cpu : POWER5+ (gs) | ||
clock : 1900.098000MHz | ||
revision : 2.1 (pvr 003b 0201) | ||
|
||
processor : 7 | ||
cpu : POWER5+ (gs) | ||
clock : 1900.098000MHz | ||
revision : 2.1 (pvr 003b 0201) | ||
|
||
timebase : 237331000 | ||
platform : pSeries | ||
machine : CHRP IBM,9133-55A"; | ||
|
||
#[test] | ||
fn test_cpuinfo_linux_power5p() { | ||
let cpuinfo = CpuInfo::from_str(POWER5P).unwrap(); | ||
assert_eq!(cpuinfo.field("cpu"), "POWER5+ (gs)"); | ||
|
||
assert!(!cpuinfo.field("cpu").has("altivec")); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for fixing this! The x86 run-time did not have this issue, I wish there was an easy way to unify this code. https://github.com/rust-lang-nursery/stdsimd/blob/master/coresimd/src/runtime/x86.rs#L329