6

I have some code that depends on CPU and OS support for various CPU features.

In particular I need to check for various SIMD instruction set support. Namely sse2, avx, avx2, fma4, and neon. (neon being the ARM SIMD feature. I'm less interested in that; given less ARM end-users.)

What I am doing right now is:

function cpu_flags()
    if is_linux()
        cpuinfo = readstring(`cat /proc/cpuinfo`);
        cpu_flag_string = match(r"flags\t\t: (.*)", cpuinfo).captures[1]
    elseif is_apple()
        sysinfo = readstring(`sysctl -a`);
        cpu_flag_string = match(r"machdep.cpu.features: (.*)", cpuinfo).captures[1]
    else
        @assert is_windows()
        warn("CPU Feature detection does not work on windows.")
        cpu_flag_string = ""
    end
    split(lowercase(cpu_flag_string))
end

This has two downsides:

  1. It doesn't work on windows
  2. I'm just not sure it is correct; it it? Or does it screw up, if for example the OS has a feature disabled, but physically the CPU supports it?

So my questions is:

  1. How can I make this work on windows.
  2. Is this correct, or even a OK way to go about getting this information?

This is part of a build script (with BinDeps.jl); so I need a solution that doesn't involve opening a GUI. And ideally one that doesn't add a 3rd party dependency. Extracting the information from GCC somehow would work, since I already require GCC to compile some shared libraries. (choosing which libraries, is what this code to detect the instruction set is for)

Frames Catherine White
  • 27,368
  • 21
  • 87
  • 137
  • 1
    Julia includes a [`ccall`-able CPUID.](https://github.com/JuliaLang/julia/blob/d95fe923b44008ddecb6f39828af38d082bfd97e/src/sys.c#L453) Then you can just use the [suitable flags and bit masks](https://en.wikipedia.org/wiki/CPUID) eg as in this [C-code](http://llvm.org/docs/doxygen/html/Host_8cpp_source.html) – Frames Catherine White Aug 29 '16 at 03:21
  • If you need more firepower, try [Hwloc.jl](https://github.com/JuliaParallel/Hwloc.jl) which provides extended information (especially useful for HPC environments). – Isaiah Norton Aug 29 '16 at 13:38
  • @Isaiah I am still trying to work out a way to do this *at all* in a portable way. I don't really want to write the code I mentioned in the comment. If there is a way with Hwloc.jl I am keen to see it, how about posting an answer? – Frames Catherine White Aug 29 '16 at 13:41
  • Actually, it appears that Hwloc doesn't support CPU features yet, my mistake. LLVM provides a `getHostCPUFeatures`, but unfortunately it doesn't work reliably before LLVM 3.8, and Julia 0.5 will at least initially be released with LLVM 3.7. – Isaiah Norton Aug 29 '16 at 15:54
  • If the right windows .dll is bound to, there is: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724482(v=vs.85).aspx, But it doesn't seem to have on that matches to FMA3 or AVX2 or several others I am interested in – Frames Catherine White Aug 29 '16 at 17:34
  • @Isaiah I'ld be interested in seeing an answer on `getHostCPUFeatures`. If it exists and kinda works (even if unreliably) on windows, that is not too bad. I can throw up a warning saying "We attempted to determine your CPU features, and got back X. But it might not be correct due to Bug #123. You can override it by setting ENVVAR...". Which is similar to what i currently, except I simply throw an error requiring windows users to set the ENVVAR – Frames Catherine White Aug 29 '16 at 17:38

1 Answers1

2

I'm just not sure it is correct; it it? Or does it screw up, if for example the OS has a feature disabled, but physically the CPU supports it?

I don't think that the OS has any say in disabling vector instructions; I've seen the BIOS being able to disable stuff (in particular, the virtualization extensions), but in that case you won't find them even in /proc/cpuinfo - that's kind of its point :-) .

Extracting the information from GCC somehow would work, since I already require GCC to compile some shared libraries

If you always have gcc (MinGW on Windows) you can use __builtin_cpu_supports:

#include <stdio.h>

int main()
{
    if (__builtin_cpu_supports("mmx")) {
        printf("\nI got MMX !\n");
    } else
        printf("\nWhat ? MMX ? What is that ?\n");
    return (0);
}

and apparently this built-in functions work under mingw-w64 too.

AFAIK it uses the CPUID instruction to extract the relevant information (so it should reflect quite well the environment your code will run in).

(from https://stackoverflow.com/a/17759098/214671)

Community
  • 1
  • 1
Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
  • That will, sadly, only tell me about: cmov mmx popcnt sse sse2 sse3 ssse3 sse4.1 sse4.2 avx avx2. https://gcc.gnu.org/onlinedocs/gcc-4.8.4/gcc/X86-Built-in-Functions.html Which means it won't tell me about `fma4` or `neon` on ARM (though I didn't mention neon in my question. I'll fix that now) – Frames Catherine White Aug 29 '16 at 05:00
  • Well that's because that documentation is about gcc 4.8 and FMA probably didn't even exist then, I suppose more recent versions have updated this builtin. OTOH, probably the most future proof way should be to build an extension that just spits out the data provided by the CPUID instruction, and examine it yourself in your Julia code. Not sure about ARM and Neon, however, I'll have to look it up. – Matteo Italia Aug 29 '16 at 05:42
  • Ah I see now your comment above, then yes, you should definitely use it. Add it as an answer and accept it! – Matteo Italia Aug 29 '16 at 05:44
  • 1
    Its really annoying to implement. If I do, I'll probably release it as a julia package. Re: the documentation. The GCC6 documentation for it is about the same. Still no FMA4. https://gcc.gnu.org/onlinedocs/gcc-6.2.0/gcc/x86-Built-in-Functions.html#x86-Built-in-Functions – Frames Catherine White Aug 29 '16 at 07:00