Skip to content

"Illegal instruction" when running simple array additions #10330

Closed

Description

@ulido

Numpy crashes with an "illegal instruction" when running a simple array addition (past a certain array size) when running inside a VM under Xen. It is probably somehow related to #9534. I narrowed it down the commit 37740eb, which introduced AVX2 simd code:

Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy
>>> numpy.__version__
'1.12.0.dev0+37740eb'
>>> a = numpy.arange(15)
>>> a[1:] + a[:-1]
Illegal instruction (core dumped)

I also tried the current master, which shows the same error.

It is working fine up to the preceding commit eeb4e17:

Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy
>>> numpy.__version__
'1.12.0.dev0+eeb4e17'
>>> a = numpy.arange(15)
>>> a[1:] + a[:-1]
array([ 1,  3,  5,  7,  9, 11, 13, 15, 17, 19, 21, 23, 25, 27])`

Note that /proc/cpuinfo doesn't list AVX2:

processor	: 0
vendor_id	: GenuineIntel
cpu family	: 6
model		: 63
model name	: Intel(R) Xeon(R) CPU E5-2680 v3 @ 2.50GHz
stepping	: 2
microcode	: 0x31
cpu MHz		: 2494.282
cache size	: 30720 KB
physical id	: 0
siblings	: 4
core id		: 0
cpu cores	: 4
apicid		: 0
initial apicid	: 0
fpu		: yes
fpu_exception	: yes
cpuid level	: 13
wp		: yes
flags		: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx rdtscp lm constant_tsc rep_good nopl pni pclmulqdq ssse3 cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes rdrand hypervisor lahf_lm abm fsgsbase tsc_adjust bmi1 smep bmi2 erms invpcid
bugs		:
bogomips	: 4988.56
clflush size	: 64
cache_alignment	: 64
address sizes	: 46 bits physical, 48 bits virtual
power management:

processor	: 1
vendor_id	: GenuineIntel
cpu family	: 6
model		: 63
model name	: Intel(R) Xeon(R) CPU E5-2680 v3 @ 2.50GHz
stepping	: 2
microcode	: 0x31
cpu MHz		: 2494.282
cache size	: 30720 KB
physical id	: 0
siblings	: 4
core id		: 2
cpu cores	: 4
apicid		: 2
initial apicid	: 2
fpu		: yes
fpu_exception	: yes
cpuid level	: 13
wp		: yes
flags		: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx rdtscp lm constant_tsc rep_good nopl pni pclmulqdq ssse3 cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes rdrand hypervisor lahf_lm abm fsgsbase tsc_adjust bmi1 smep bmi2 erms invpcid
bugs		:
bogomips	: 4988.56
clflush size	: 64
cache_alignment	: 64
address sizes	: 46 bits physical, 48 bits virtual
power management:

processor	: 2
vendor_id	: GenuineIntel
cpu family	: 6
model		: 63
model name	: Intel(R) Xeon(R) CPU E5-2680 v3 @ 2.50GHz
stepping	: 2
microcode	: 0x31
cpu MHz		: 2494.282
cache size	: 30720 KB
physical id	: 0
siblings	: 4
core id		: 4
cpu cores	: 4
apicid		: 4
initial apicid	: 4
fpu		: yes
fpu_exception	: yes
cpuid level	: 13
wp		: yes
flags		: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx rdtscp lm constant_tsc rep_good nopl pni pclmulqdq ssse3 cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes rdrand hypervisor lahf_lm abm fsgsbase tsc_adjust bmi1 smep bmi2 erms invpcid
bugs		:
bogomips	: 4988.56
clflush size	: 64
cache_alignment	: 64
address sizes	: 46 bits physical, 48 bits virtual
power management:

processor	: 3
vendor_id	: GenuineIntel
cpu family	: 6
model		: 63
model name	: Intel(R) Xeon(R) CPU E5-2680 v3 @ 2.50GHz
stepping	: 2
microcode	: 0x31
cpu MHz		: 2494.282
cache size	: 30720 KB
physical id	: 0
siblings	: 4
core id		: 6
cpu cores	: 4
apicid		: 6
initial apicid	: 6
fpu		: yes
fpu_exception	: yes
cpuid level	: 13
wp		: yes
flags		: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx rdtscp lm constant_tsc rep_good nopl pni pclmulqdq ssse3 cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes rdrand hypervisor lahf_lm abm fsgsbase tsc_adjust bmi1 smep bmi2 erms invpcid
bugs		:
bogomips	: 4988.56
clflush size	: 64
cache_alignment	: 64
address sizes	: 46 bits physical, 48 bits virtual
power management:

I tried to understand how numpy decides when to use the avx2 simd codepaths but failed miserably.

Activity

  1. ulido commented on Jan 5, 2018

    @ulido
    Author

    I just tried that, but it crashed again:

    (master) user@host:~/tmp/numpy$ CFLAGS='-march=x86-64' pip3 install -U .
    Processing /home/ud214/tmp/numpy
    Installing collected packages: numpy
      Found existing installation: numpy 1.15.0.dev0+10ccfe7
        Uninstalling numpy-1.15.0.dev0+10ccfe7:
          Successfully uninstalled numpy-1.15.0.dev0+10ccfe7
      Running setup.py install for numpy ... done
    Successfully installed numpy-1.15.0.dev0+10ccfe7
    You are using pip version 8.1.1, however version 9.0.1 is available.
    You should consider upgrading via the 'pip install --upgrade pip' command.
    (master) user@host:~/tmp$ python3
    Python 3.5.2 (default, Nov 23 2017, 16:37:01)
    [GCC 5.4.0 20160609] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import numpy
    >>> numpy.__version__
    '1.15.0.dev0+10ccfe7'
    >>> a = numpy.arange(15)
    >>> a[1:] + a[:-1]
    Illegal instruction (core dumped)

    I should've mentioned that the problem also arises if I use the regular numpy version from pip:

    (pip) user@host:~/tmp$ pip3 install numpy
    Collecting numpy
      Using cached numpy-1.13.3-cp35-cp35m-manylinux1_x86_64.whl
    Installing collected packages: numpy
    Successfully installed numpy-1.13.3
    You are using pip version 8.1.1, however version 9.0.1 is available.
    You should consider upgrading via the 'pip install --upgrade pip' command.
    (pip) user@host:~/tmp$ python3
    Python 3.5.2 (default, Nov 23 2017, 16:37:01)
    [GCC 5.4.0 20160609] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import numpy
    >>> numpy.__version__
    '1.13.3'
    >>> a = numpy.arange(15)
    >>> a[1:] + a[:-1]
    Illegal instruction (core dumped)

    I guess the pip-supplied manylinux wheel should work regardless of the presence of AVX2, correct?

  2. seberg commented on Jan 7, 2018

    @seberg
    Member

    Numpy has runtime detection here. Now that works with gcc __builtin_cpu_supports, either there is something done wrong there in numpy, or the VM is doing something weird? If you have a clue about it, git grep for NPY_CPU_SUPPORTS. GCC docs mention some cpu_init stuff, but dunno, seems weird if that was it?

  3. seberg commented on Jan 7, 2018

    @seberg
    Member

    I am sure you can remove the avx/avx2 target from the setup code (or pass through flags to disable it maybe). (e.g. check/modify numpy/core/setup_common.py)

  4. ulido commented on Jan 7, 2018

    @ulido
    Author

    Thanks @seberg ! I'm pretty sure that the problem is that the Xen hypervisor my VM is running on is configure to mask the AVX capabilities of the host cpu (I don't know why, I don't control the hypervisor.). My guess is that __builtin_cpu_supports uses heuristics based on the cpu name or so to find which features it supports. However, that leads to trouble in this case when capabilities are masked/forbidden by the host. Here is some code to prove that (AVX is detected but not working):

    user@host:~/tmp$ cat avx_test.c
    #include <stdio.h>
    
    int main()
    {
      if (__builtin_cpu_supports("avx")) {
        printf("AVX supported!\n");
    
        printf("Testing if it's really working (should crash with SIGILL if not)\n");
        // Simplest AVX instruction I could find:
        __builtin_ia32_vzeroall();
        printf("If you see this, it worked!\n");
      } else {
        printf("AVX not supported!\n");
      }
    }
    user@host:~/tmp$ gcc -mavx avx_test.c
    user@host:~/tmp$ ./a.out
    AVX supported!
    Testing if it's really working (should crash with SIGILL if not)
    
    Illegal instruction (core dumped)
    

    Do you think it would be possible to use a custom function to set NPY_CPU_SUPPORTS_AVX / NPY_CPU_SUPPORTS_AVX2 that tries to run a corresponding instruction and catches SIGILL instead of __builtin_cpu_supports?

  5. seberg commented on Jan 7, 2018

    @seberg
    Member

    As far as I understand AVX, etc. have to be enabled explicitly when compiling? So I think you can simply remove those lines that have something to do with AVX in that setup file I mentioned and recompile? That should just lead to disabling the whole stuff.

    For a more general solution, I do not know.... I am sure we could have a flag or so to disable it explicitly at least during compile time, maybe even more fancy stuff. I do not really know build stuff, etc. Doing more fancy stuff during run-time seems odd to me, but thats just gut feeling.

  6. ulido commented on Jan 7, 2018

    @ulido
    Author
  7. seberg commented on Jan 7, 2018

    @seberg
    Member

    Tend to agree, it seems more like a bug in either gcc or probably the VM to me as well. I don't mind making working around it easier, but doing weird things when the gcc function seems like smarter people who know this stuff wrote it….
    We can make working around it easier maybe. I also wonder if (at least for manylinux numpy) the openblas won't blow up as well as soon as you use it? And I am sure adding that __builtin_cpu_init() call does not matter?

  8. ulido commented on Jan 8, 2018

    @ulido
    Author

    Ok, @seberg, I followed your suggestion and removed the entries for AVX in setup_common.py, which fixed the problem for now, but I guess it would be good to at least have a compile time option to disable AVX/AVX2.

    I did some testing and found that it is not a gcc bug. The cpu itself reports AVX/AVX2 capabilities via the cpuid instruction (which is used by __builtin_cpu_supports). Rather, Xen fails to mask the features in the response to calling cpuid (but I don't know anything about Xen, and have no control over the host system I'm running my VM on). /proc/cpuinfo correctly reports them as absent, so it should be possible to query that as a last check after __builtin_cpu_supports reports true.

    Closing the issue for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions