Skip to content

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

Merged
merged 3 commits into from
Dec 12, 2017
Merged

non-x86 runtime detection updates #229

merged 3 commits into from
Dec 12, 2017

Conversation

lu-zero
Copy link
Contributor

@lu-zero lu-zero commented Dec 10, 2017

The arm32 variant is not tested due a small hardware failure.

@alexcrichton
Copy link
Member

This looks great to me, thanks!

Mind adding some more documentation as well? For example for a newbie like me, I'm not even sure what auxv is :(. It'd be great if that file explained a little bit about the purpose of the file, the format, and then maybe provided a link to more info?

Additionally for the bits defined in powerpc64, could documentation be referenced for where the values come from?

{
let mut enable_feature = |f| {
if x.has_feature(&f) {
bit::set(value, f as u32);
value = bit::set(value, f as u32);
Copy link
Contributor

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

// TODO: make it less ugly if possible
pub fn new() -> Result<Self, ::std::io::Error> {
use std::io::Read;
let mut file = ::std::fs::File::open("/proc/self/auxv")?;
Copy link
Contributor

@gnzlbg gnzlbg Dec 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good first step, but we should only do this if libc's getauxval does not exist. I think we can add getauxval as an extern C weak_symbol, and check whether the value of a function pointer to it is null or not at run-time. If it is not null we should just call that, but if it is null then the binary does not have a linked extern C getauxval function, and we can proceed to read proc/self/auxv as a fallback.

I wish someone (@alexcrichton , @BurntSushi ) would review #211 since that would allow us to add some more ARM targets for testing and use qemu-system instead of qemu-user to test this on linux and android targets.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I avoided getauxval since it is nonstandard, I wouldn't rely on weak_symbol to check for its presence (static linking and non-gnu libcs aren't uncommon:))

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typically we don't use weak symbols as they're not very portable, but a solution is to do what libstd does which is dlsym at runtime.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC the problem was that /proc/self/auxv is not guaranteed to exist on all Android targets, but libc::getauxval is (and also, libc::getauxval is always faster than reading /proc/self/auxv on all platforms that have it).

Anyways, we don't need to add libc::getauxval on this PR, that was more me thinking out loud. This PR is a good step forward as it is. Good job!

@@ -45,6 +45,23 @@ pub fn detect_features<T: linux::FeatureQuery>(mut x: T) -> usize {
value
}

/// Probe the ELF Auxiliary vector for hardware capabilities
///
/// The values are part of the platform-specific `asm/hwcap.h`
Copy link
Contributor

@gnzlbg gnzlbg Dec 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you maybe add a link to the linux header where hwcap is defined? That is, here: https://github.com/torvalds/linux/blob/master/arch/arm64/include/uapi/asm/hwcap.h

(and do the same for arm?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

/// The desugared version is a usize tag followed by a union with
/// the same storage size.
pub struct AuxVec {
raw: Vec<usize>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should avoid the Vec here. Can't we just use a [usize; 64] + a length?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could just copy the hwcaps when present maybe?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that would be better.

I know we are already doing a lot of syscals by reading the file, and that allocating the vector should not matter much, but I was hoping that if we managed to add support for libc::getauxval in the future we could reuse at least some of this for that.

}

/// Detects ARM features:
pub fn detect_features() -> usize {
// FIXME: use libc::getauxval, and if that fails /proc/auxv
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should keep this fixme because we are still not calling libc::getauxval. We should try to do that first, and if that fails, then read /proc/self/auxv, and if that fails, then try to read /proc/cpuinfo.


#[cfg(test)]
mod tests {
#[test]
Copy link
Contributor

@gnzlbg gnzlbg Dec 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a test that parses one or two dumps of /proc/cpuinfo for powerpc CPUs?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, since the cpuinfo is w/out information at least for now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check this out: https://github.com/randombit/cpuinfo/tree/master/ppc

That's a collection of cpuinfo files for a lot of powerpc cpus. Maybe one could c&p one of those files here and add it as a test?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm afraid the comment is not clear in the function: /proc/cpuinfo on powerpc does not provide useful information, I left that code there since I plan to ask the linux kernel developers to provide the same information as arm does. I can change the function with a simple return false so it is less misleading for not.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment is clear, I just skimmed too fast through it.

What is the value of adding the cpuinfo implementation? We can always add it later once a kernel is released that "supports" it right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just prefer to leave the placeholder since it is sort of future proof.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the linux mod require this implementation to exist? If that is the case I think we should fix that instead.

I can do that later if you prefer, but I think that leaving it with the expectation that a future Linux kernel version implements this is a long shot.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The linux mod requires the implementation and I wouldn't spend more time on that. I updated it so it leverages the small bit of information to get to know if at least 1 feature is enabled.

Copy link
Contributor

@gnzlbg gnzlbg Dec 11, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that the examples of cpuinfo for powerpc are there everything has become clear (sorry that it took so long). Just to check that I understand correctly, the only thing that can be checked from /proc/cpuinfo for PowerPC is whether altivec is supported or not, is that right?

#[cfg(test)]
mod tests {
use super::*;

Copy link
Contributor

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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?

Copy link
Contributor

Choose a reason for hiding this comment

The 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

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could use #[cfg(target_pointer_width = "32")] to enable the tests on 32-bit platforms or to add different tests for 32 and 64 bit platforms.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My idea is to avoid getauxval completely and just walk from argv in imp::init() and save a GLOBAL_AUXV_PTR there. then wrap the whole thing as it is done for args.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before we go to the extent of bypassing getauxval() and doing our own unsafe version, I think it would make sense to evaluate whether or not there is actually a problem with getauxval() availability in practice. Are people going to be writing Rust code that uses SIMD that gets deployed on very old Android devices? I suspect that that is likely to be a marginal use case at most.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume that the getauxval() support is sorted out already and I looked at how hard would be avoiding it to support the fringe cases I mentioned.

Apparently it would be within the 50-lines range.

Copy link
Contributor

@gnzlbg gnzlbg Dec 15, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lu-zero I thought that the init call was only available in std, is it also usable from core?


@marshallpierce once getauxval lands things will be in my opinion very good for Linux users and my time is better spent on improving things for macos users (macos x86 users are fine already, but iOS users on ARM chips are not). Having said this, if someone wants to spearhead support for libc's without getauxval on coresimd I'd completely support that (for steed users it might be better to just implement getauxval on steed though). Then there is also arm-thumb users which are currently left a bit in the dark; we might be able to help them in coresimd but it is unclear to me what the best way to do that is (probably offer something like what we offer for x86).

Copy link
Contributor

Choose a reason for hiding this comment

The 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.

@gnzlbg
Copy link
Contributor

gnzlbg commented Dec 10, 2017

Looks very good, thanks! I've left some comments in the code, but they are all minor issues.

@lu-zero lu-zero force-pushed the master branch 3 times, most recently from 02254b9 to d303269 Compare December 11, 2017 11:32
assert_eq!(cpuinfo.field("cpu"), "POWER8E (raw), altivec supported");

assert!(cpuinfo.field("cpu").has("altivec"));
}
Copy link
Contributor

Choose a reason for hiding this comment

The 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 ?

Copy link
Contributor

Choose a reason for hiding this comment

The 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?

@gnzlbg
Copy link
Contributor

gnzlbg commented Dec 12, 2017

I've opened #234 to track testing auxv. Modulo the Power5 tests that got lost in the merge this LGTM.

Rely mainly on parsing auxv since the cpuinfo information is incomplete.
@lu-zero
Copy link
Contributor Author

lu-zero commented Dec 12, 2017

I updated patch to add it, I hope it doesn't cause additional disruption

@gnzlbg gnzlbg merged commit 098787d into rust-lang:master Dec 12, 2017
@gnzlbg
Copy link
Contributor

gnzlbg commented Dec 12, 2017

@lu-zero thank you for working on this! great job!

// reliable way.
pub fn new() -> Result<Self, ::std::io::Error> {
use std::io::Read;
let mut file = ::std::fs::File::open("/proc/self/auxv")?;

Choose a reason for hiding this comment

The 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 getauxval() is widely available because bionic (their libc) has implemented it for some years now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants