Skip to content

BUG: Legacy NPY_DISABLE_CPU_FEATURES names are ignored without a visible warning #33016

Open

Description

@taktcycles

Describe the issue:

After upgrading from NumPy 2.3 to 2.4+, the following setting no longer disables the AVX-512 path used by np.log in our tests:

NPY_DISABLE_CPU_FEATURES="AVX512F AVX512CD AVX512_SKX AVX512_CLX AVX512_CNL AVX512_ICL"

On NumPy 2.5.4, using an AMD Ryzen 9 7950X3D on Linux, NumPy imports successfully and produces no visible warning under Python’s default warning filters. For identical input, the np.log output is bit-identical to the output without this environment variable.

Using the current dispatch names instead changes the output:

NPY_DISABLE_CPU_FEATURES="X86_V4 AVX512_ICL AVX512_SPR"

Running with python -W always reveals an ImportWarning explaining that the legacy names are not part of the dispatched optimizations. Since Python hides ImportWarning by default, an existing configuration can stop having its intended effect without notifying the user.

Earlier tests showed that the legacy setting worked on NumPy 2.2.6 and 2.3.5, but stopped affecting this computation on 2.4.4 and 2.5.3. We have now reproduced this behavior on 2.5.4.

The runtime dispatch documentation (https://numpy.org/doc/stable/reference/simd/build-options.html#runtime-dispatch) describes an error when a requested feature was not enabled through cpu-dispatch, whereas the observed behavior is a hidden warning.

I would expect unsupported names to produce an explicit error or a visible warning, ideally with guidance on the replacement names. This matters for workflows that control CPU dispatch when comparing floating-point outputs bit for bit: after an upgrade, the previous configuration appears to succeed while no longer producing the expected behavior.

Reproduce the code example:

Use an AVX-512-capable CPU and a Python environment with NumPy 2.5.4 installed. The following commands create repro.py and run it in four fresh processes. Each environment setting is applied before importing NumPy.

mkdir -p /tmp/numpy-dispatch-repro
cd /tmp/numpy-dispatch-repro

cat > repro.py <<'PY'
import hashlib
import os   

import numpy as np

x = 1.0 + np.random.default_rng(0).normal(0.0, 0.01, 1_000_000)
print("numpy", np.__version__)
print("disabled", repr(os.environ.get("NPY_DISABLE_CPU_FEATURES")))
print("input_sha256", hashlib.sha256(x.tobytes()).hexdigest())
print("log_sha256", hashlib.sha256(np.log(x).tobytes()).hexdigest())   
PY

# Default dispatch
env -u NPY_DISABLE_CPU_FEATURES python repro.py

# Previous AVX-512 disabling recipe
NPY_DISABLE_CPU_FEATURES="AVX512F AVX512CD AVX512_SKX AVX512_CLX AVX512_CNL AVX512_ICL" python repro.py

# Current dispatch names
NPY_DISABLE_CPU_FEATURES="X86_V4 AVX512_ICL AVX512_SPR" python repro.py

# Make the otherwise hidden warning visible
NPY_DISABLE_CPU_FEATURES="AVX512F AVX512_SKX" python -W always repro.py

Error message:

With default warning filters, the first three runs produce no stderr output. The fourth run, with -W always, produces:

<frozen importlib._bootstrap>:488: ImportWarning: During parsing environment variable: 'NPY_DISABLE_CPU_FEATURES':
You cannot disable CPU features (AVX512F AVX512_SKX), since they are not part of the dispatched optimizations
(X86_V3 X86_V4 AVX512_ICL AVX512_SPR).

Recorded stdout is shown below, with case headings added for readability:

CASE default
numpy 2.5.4
disabled None
input_sha256 e9eba03cea8f3adcf1fd60cbf13674e5f078d1034933e58650ad073f4e6e7800
log_sha256 e409a2f1be62b48569f23f645e6c4d0db33517d65cbdd7c783ed2d0549cc661a

CASE old names
numpy 2.5.4
disabled 'AVX512F AVX512CD AVX512_SKX AVX512_CLX AVX512_CNL AVX512_ICL'
input_sha256 e9eba03cea8f3adcf1fd60cbf13674e5f078d1034933e58650ad073f4e6e7800
log_sha256 e409a2f1be62b48569f23f645e6c4d0db33517d65cbdd7c783ed2d0549cc661a

CASE new names
numpy 2.5.4
disabled 'X86_V4 AVX512_ICL AVX512_SPR'
input_sha256 e9eba03cea8f3adcf1fd60cbf13674e5f078d1034933e58650ad073f4e6e7800
log_sha256 aeec32ee5668e38375e913fbeea28ff0e768a982b77382207202b88e0c76e79d

CASE old names, warnings visible
numpy 2.5.4
disabled 'AVX512F AVX512_SKX'
input_sha256 e9eba03cea8f3adcf1fd60cbf13674e5f078d1034933e58650ad073f4e6e7800
log_sha256 e409a2f1be62b48569f23f645e6c4d0db33517d65cbdd7c783ed2d0549cc661a

The input bytes are identical in all four processes. The previous disabling recipe produces the same np.log output as default dispatch; using the current dispatch names produces different output bytes.

Python and NumPy Versions:

NumPy 2.5.4
Python 3.12.15 (main, Oct  9 2026, 15:22:32) [Clang 22.1.3 ]

Runtime Environment:

Environment of the recorded reproduction:

  • Linux x86-64.
  • AMD Ryzen 9 7950X3D, with AVX-512 support.
  • Each case runs in a fresh Python process.
  • NPY_DISABLE_CPU_FEATURES is set before NumPy is imported.
  • Default Python warning filters are used except in the final case.
  • The warning reports these dispatched optimizations: X86_V3 X86_V4 AVX512_ICL AVX512_SPR.

How does this issue affect you or how did you find it:

We compare floating-point outputs bit for bit in reproducibility checks and use CPU-dispatch settings to control the computation paths being compared.

After upgrading NumPy, the previous AVX-512 disabling configuration stopped having its intended effect in this test, while import still succeeded without a visible diagnostic. This made the configuration failure difficult to detect and required investigating the changed output hashes.

Activity

  1. mattip commented on Oct 17, 2026

    @mattip
    Member
  2. seiko2plus commented on Oct 21, 2026

    @seiko2plus
    Member

    Thank you for your report. #28896 only provided compatibility at build time by providing feature redirection and ignored the runtime phase. Substituting legacy feature names seems to me the only possible fix with (DeprecationWarning). ImportWarning seems to me a reasonable choice since the process happened during the import time, treating it as an error wouldn't be a good option or forcing the warning to be exposed. Assume a certain feature that is valid but wasn't shipped in the binaries during the build time due to the compiler lacking its support or for reducing the binary size or even ceiling the default baseline.

    Build-time redirection:

    X86_REDIRECT = {
    'SSE': 'X86_V2', 'SSE2': 'X86_V2', 'SSE3': 'X86_V2', 'SSSE3': 'X86_V2',
    'SSE41': 'X86_V2', 'SSE42': 'X86_V2', 'XOP': 'X86_V2', 'FMA4': 'X86_V2',
    'FMA3': 'X86_V3', 'AVX': 'X86_V3', 'F16C': 'X86_V3',
    'AVX512F': 'X86_V3', 'AVX512CD': 'X86_V3',
    'AVX512_KNL': 'X86_V3', 'AVX512_KNM': 'X86_V3',
    'AVX512_SKX': 'X86_V4', 'AVX512_CLX': 'X86_V4', 'AVX512_CNL': 'X86_V4',
    }

    The runtime dispatch documentation (https://numpy.org/doc/stable/reference/simd/build-options.html#runtime-dispatch) describes an error when a requested feature was not enabled through cpu-dispatch, whereas the observed behavior is a hidden warning

    I agree the doc is not accurate, need to be updated.

    Since Python hides ImportWarning by default, an existing configuration can stop having its intended effect without notifying the user.

    #33027 change it to PyExc_UserWarning but I'm not sure if it's a good call due to what is explained above.

  3. seiko2plus commented on Oct 21, 2026

    @seiko2plus
    Member

    After a second look #33027 should resolve this issue and it makes sense to treat it as a user warning, but I still think we need to cover the following

    • Provide legacy substitution
    • Add a new runtime test for testing unknown features names (different from the current non dispatch-able features)
    • Updating the doc
  4. rdmitry0911 commented on Oct 29, 2026

    @rdmitry0911

    (Posting for the reporting account, same team.) Thank you both — #33027 looks like it addresses the case we reported: with the legacy NPY_DISABLE_CPU_FEATURES
    names, the runtime now either applies the substitution or warns instead of silently ignoring the setting.
    We agree with the proposal to (a) provide the legacy-name substitution and (b) add a runtime warning when a
    requested name is unknown; both would have made our regression visible immediately. We will re-run our
    reproduction against the next wheel that contains #33027 and report back here. From our side the issue can
    be closed once that PR lands.

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions