├── mkl ├── _version.py ├── _init_helper.py ├── __init__.py ├── _mkl_service.pxd ├── _mklinitmodule.c ├── tests │ └── test_mkl_service.py └── _mkl_service.pyx ├── .github ├── CODEOWNERS ├── dependabot.yml └── workflows │ ├── pre-commit.yml │ ├── build-with-clang.yml │ ├── openssf-scorecard.yml │ └── conda-package.yml ├── .git-blame-ignore-revs ├── conda-recipe ├── conda_build_config.yaml ├── bld.bat ├── build.sh └── meta.yaml ├── .flake8 ├── .travis.yml ├── LICENSE.txt ├── README.md ├── .gitignore ├── examples └── example.py ├── .pre-commit-config.yaml ├── pyproject.toml ├── CODE_OF_CONDUCT.md ├── setup.py └── CHANGELOG.md /mkl/_version.py: -------------------------------------------------------------------------------- 1 | __version__ = "2.7.0dev0" 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @ndgrigorian @antonwolfy @xaleryb @jharlow-intel 2 | -------------------------------------------------------------------------------- /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # $ git config blame.ignoreRevsFile .git-blame-ignore-revs 2 | 3 | # Add pre-commit hooks 4 | 9c1fb5bd9b946c2eaaf1ea882e789efcccf66b53 5 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | day: "saturday" 8 | rebase-strategy: "disabled" 9 | -------------------------------------------------------------------------------- /conda-recipe/conda_build_config.yaml: -------------------------------------------------------------------------------- 1 | c_compiler: # [linux] 2 | - gcc # [linux] 3 | cxx_compiler: # [linux] 4 | - gxx # [linux] 5 | cxx_compiler_version: # [linux] 6 | - '14' # [linux] 7 | c_stdlib: # [linux] 8 | - sysroot # [linux] 9 | c_stdlib_version: # [linux] 10 | - '2.28' # [linux] 11 | c_stdlib: # [win] 12 | - vs # [win] 13 | cxx_compiler: # [win] 14 | - vs2022 # [win] 15 | c_compiler: # [win] 16 | - vs2022 # [win] 17 | -------------------------------------------------------------------------------- /conda-recipe/bld.bat: -------------------------------------------------------------------------------- 1 | echo on 2 | rem set CFLAGS=-I%PREFIX%\Library\include %CFLAGS% 3 | rem set LDFLAGS=/LIBPATH:%PREFIX% %LDFLAGS% 4 | 5 | set MKLROOT=%CONDA_PREFIX% 6 | 7 | "%PYTHON%" setup.py clean --all 8 | 9 | :: Make CMake verbose 10 | set "VERBOSE=1" 11 | 12 | :: -wnx flags mean: --wheel --no-isolation --skip-dependency-check 13 | %PYTHON% -m build -w -n -x 14 | if %ERRORLEVEL% neq 0 exit 1 15 | 16 | :: wheel file was renamed 17 | for /f %%f in ('dir /b /S .\dist') do ( 18 | %PYTHON% -m pip install %%f ^ 19 | --no-build-isolation ^ 20 | --no-deps ^ 21 | --only-binary :all: ^ 22 | --no-index ^ 23 | --prefix %PREFIX% ^ 24 | -vv 25 | if %ERRORLEVEL% neq 0 exit 1 26 | ) 27 | 28 | :: Copy wheel package 29 | if NOT "%WHEELS_OUTPUT_FOLDER%"=="" ( 30 | copy dist\mkl_service*.whl %WHEELS_OUTPUT_FOLDER% 31 | if %ERRORLEVEL% neq 0 exit 1 32 | ) 33 | -------------------------------------------------------------------------------- /conda-recipe/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -ex 3 | 4 | export MKLROOT=$CONDA_PREFIX 5 | 6 | read -r GLIBC_MAJOR GLIBC_MINOR <<<"$(conda list '^sysroot_linux-64$' \ 7 | | tail -n 1 | awk '{print $2}' | grep -oP '\d+' | head -n 2 | tr '\n' ' ')" 8 | 9 | ${PYTHON} setup.py clean --all 10 | 11 | # Make CMake verbose 12 | export VERBOSE=1 13 | 14 | # -wnx flags mean: --wheel --no-isolation --skip-dependency-check 15 | ${PYTHON} -m build -w -n -x 16 | 17 | ${PYTHON} -m wheel tags --remove \ 18 | --platform-tag "manylinux_${GLIBC_MAJOR}_${GLIBC_MINOR}_x86_64" \ 19 | dist/mkl_service*.whl 20 | 21 | ${PYTHON} -m pip install dist/mkl_service*.whl \ 22 | --no-build-isolation \ 23 | --no-deps \ 24 | --only-binary :all: \ 25 | --no-index \ 26 | --prefix "${PREFIX}" \ 27 | -vv 28 | 29 | # Copy wheel package 30 | if [[ -d "${WHEELS_OUTPUT_FOLDER}" ]]; then 31 | cp dist/mkl_service*.whl "${WHEELS_OUTPUT_FOLDER[@]}" 32 | fi 33 | -------------------------------------------------------------------------------- /.github/workflows/pre-commit.yml: -------------------------------------------------------------------------------- 1 | name: pre-commit 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: [master] 7 | 8 | permissions: read-all 9 | 10 | jobs: 11 | pre-commit: 12 | runs-on: ubuntu-latest 13 | timeout-minutes: 30 14 | steps: 15 | - name: Checkout repo 16 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 17 | 18 | - name: Set up python 19 | uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 20 | with: 21 | python-version: '3.12' 22 | 23 | - name: Set up pip packages 24 | uses: BSFishy/pip-action@8f2d471d809dc20b6ada98c91910b6ae6243f318 # v1 25 | with: 26 | packages: | 27 | codespell 28 | pylint 29 | 30 | - name: Set up clang-format 31 | run: | 32 | sudo apt-get install -y clang-format-14 33 | sudo unlink /usr/bin/clang-format 34 | sudo ln -s /usr/bin/clang-format-14 /usr/bin/clang-format 35 | clang-format --version 36 | 37 | - name: Run pre-commit checks 38 | uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 39 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | extend-ignore = 3 | # whitespace before ':' (currently conflicts with black formatting): 4 | E203, 5 | # line too long (in docstrings): 6 | E501, 7 | # ‘from module import *’ used; unable to detect undefined names: 8 | F403, 9 | # doc line too long (105 > 80 characters): 10 | W505, 11 | # missing docstring in public module: 12 | D100, 13 | # missing docstring in public class: 14 | D101, 15 | # missing docstring in public method: 16 | D102, 17 | # missing docstring in public function: 18 | D103, 19 | # missing docstring in public package: 20 | D104, 21 | # missing docstring in magic method: 22 | D105, 23 | # missing docstring in __init__: 24 | D107, 25 | # no blank lines allowed after function docstring: 26 | D202, 27 | # 1 blank line required between summary line and description: 28 | D205, 29 | # first line should end with a period: 30 | D400, 31 | # first line should be in imperative mood: 32 | D401, 33 | # first line should not be the function's "signature": 34 | D402, 35 | 36 | per-file-ignores = 37 | mkl/__init__.py: E402, F401, F405 38 | 39 | filename = *.py, *.pyx, *.pxi, *.pxd 40 | max_line_length = 80 41 | max-doc-length = 80 42 | show-source = True 43 | 44 | # Print detailed statistic if any issue detected 45 | count = True 46 | statistics = True 47 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | matrix: 2 | include: 3 | - name: "Linux-Py2" 4 | os: linux 5 | dist: xenial 6 | env: 7 | - MINICONDA=Miniconda2-latest-Linux-x86_64.sh 8 | - PYVER="--python=27" 9 | - name: "Linux-Py3" 10 | os: linux 11 | dist: xenial 12 | env: 13 | - MINICONDA=Miniconda3-latest-Linux-x86_64.sh 14 | - PYVER="" 15 | - name: "OsX-Py2" 16 | os: osx 17 | osx_image: xcode8 18 | env: 19 | - MATRIX_EVAL="brew install gcc && CC=gcc-7 && CXX=g++-7" 20 | - MINICONDA=Miniconda3-latest-MacOSX-x86_64.sh 21 | - MACOSX_DEPLOYMENT_TARGET="10.9" 22 | - PYVER="--python=27" 23 | - name: "OsX-Py3" 24 | os: osx 25 | osx_image: xcode8 26 | env: 27 | - MATRIX_EVAL="brew install gcc && CC=gcc-7 && CXX=g++-7" 28 | - MINICONDA=Miniconda3-latest-MacOSX-x86_64.sh 29 | - MACOSX_DEPLOYMENT_TARGET="10.9" 30 | - PYVER="" 31 | 32 | install: 33 | - wget https://repo.continuum.io/miniconda/$MINICONDA -O miniconda.sh; 34 | - bash miniconda.sh -b -p $HOME/miniconda 35 | - export PATH="$HOME/miniconda/bin:$PATH" 36 | - hash -r 37 | - conda update --yes -q conda 38 | - conda install --yes conda-build 39 | # Useful for debugging any issues with conda 40 | - conda info -a 41 | - gcc -v 42 | - g++ -v 43 | 44 | script: 45 | - conda build -c conda-forge $PYVER --override-channels conda-recipe 46 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018, Intel Corporation 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | * Redistributions of source code must retain the above copyright notice, 7 | this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of Intel Corporation nor the names of its contributors 12 | may be used to endorse or promote products derived from this software 13 | without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `mkl-service` - Python package for run-time control of Intel® oneAPI Math Kernel Library (oneMKL). 2 | [![Conda package](https://github.com/IntelPython/mkl-service/actions/workflows/conda-package.yml/badge.svg)](https://github.com/IntelPython/mkl-service/actions/workflows/conda-package.yml) 3 | [![Build mkl-service with clang](https://github.com/IntelPython/mkl-service/actions/workflows/build-with-clang.yml/badge.svg)](https://github.com/IntelPython/mkl-service/actions/workflows/build-with-clang.yml) 4 | [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/IntelPython/mkl-service/badge)](https://securityscorecards.dev/viewer/?uri=github.com/IntelPython/mkl-service) 5 | 6 | 7 | --- 8 | 9 | To install conda package, use `conda install -c https://software.repos.intel.com/python/conda/ mkl-service`, or `conda install -c conda-forge mkl-service`. 10 | 11 | To install PyPI package, use `python -m pip install mkl-service`. 12 | 13 | --- 14 | 15 | Intel® oneAPI Math Kernel Library (oneMKL) supports functions are subdivided into the following groups according to their purpose: 16 | - Version Information 17 | - Threading Control 18 | - Timing 19 | - Memory Management 20 | - Conditional Numerical Reproducibility Control 21 | - Miscellaneous 22 | 23 | A short example, illustrating its use: 24 | 25 | ```python 26 | >>> import mkl 27 | >>> mkl.domain_set_num_threads(1, domain="fft") # oneMKL FFT functions to run sequentially 28 | # 'success' 29 | ``` 30 | 31 | For more information about the usage of support functions see [Developer Reference for Intel® oneAPI Math Kernel Library for C](https://www.intel.com/content/www/us/en/docs/onemkl/developer-reference-c/2025-2/support-functions.html). 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Cython 2 | mkl/_mkl_service.c 3 | 4 | # Byte-compiled / optimized / DLL files 5 | __pycache__/ 6 | *.py[cod] 7 | *$py.class 8 | 9 | # C extensions 10 | *.so 11 | 12 | # Distribution / packaging 13 | .Python 14 | env/ 15 | build/ 16 | develop-eggs/ 17 | dist/ 18 | downloads/ 19 | eggs/ 20 | .eggs/ 21 | lib/ 22 | lib64/ 23 | parts/ 24 | sdist/ 25 | var/ 26 | wheels/ 27 | *.egg-info/ 28 | .installed.cfg 29 | *.egg 30 | 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | *.spec 36 | 37 | # Installer logs 38 | pip-log.txt 39 | pip-delete-this-directory.txt 40 | 41 | # Unit test / coverage reports 42 | htmlcov/ 43 | .tox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | .hypothesis/ 51 | 52 | # Translations 53 | *.mo 54 | *.pot 55 | 56 | # Django stuff: 57 | *.log 58 | local_settings.py 59 | 60 | # Flask stuff: 61 | instance/ 62 | .webassets-cache 63 | 64 | # Scrapy stuff: 65 | .scrapy 66 | 67 | # Sphinx documentation 68 | docs/_build/ 69 | 70 | # PyBuilder 71 | target/ 72 | 73 | # Jupyter Notebook 74 | .ipynb_checkpoints 75 | 76 | # pyenv 77 | .python-version 78 | 79 | # celery beat schedule file 80 | celerybeat-schedule 81 | 82 | # SageMath parsed files 83 | *.sage.py 84 | 85 | # dotenv 86 | .env 87 | 88 | # virtualenv 89 | .venv 90 | venv/ 91 | ENV/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /conda-recipe/meta.yaml: -------------------------------------------------------------------------------- 1 | package: 2 | name: mkl-service 3 | version: {{ GIT_DESCRIBE_TAG }} 4 | 5 | source: 6 | path: .. 7 | 8 | build: 9 | number: {{ GIT_DESCRIBE_NUMBER }} 10 | script_env: 11 | - WHEELS_OUTPUT_FOLDER 12 | ignore_run_exports: 13 | - blas 14 | - mkl-service 15 | 16 | requirements: 17 | build: 18 | - {{ compiler('c') }} 19 | - {{ stdlib('c') }} 20 | host: 21 | - python 22 | - python-gil # [py>=314] 23 | - pip >=25.0 24 | - setuptools >=77 25 | - mkl-devel 26 | - cython 27 | - wheel >=0.45.1 28 | - python-build >=1.2.2 29 | run: 30 | - python 31 | - python-gil # [py>=314] 32 | - {{ pin_compatible('mkl') }} 33 | 34 | test: 35 | requires: 36 | - pytest 37 | imports: 38 | - mkl 39 | commands: 40 | - pytest -vv --pyargs mkl 41 | 42 | about: 43 | home: http://github.com/IntelPython/mkl-service 44 | license: BSD-3-Clause 45 | license_file: LICENSE.txt 46 | summary: Python hooks for Intel® oneAPI Math Kernel Library (oneMKL) runtime control settings 47 | description: | 48 | LEGAL NOTICE: Use of this software package is subject to the 49 | software license agreement (as set forth above, in the license section of 50 | the installed Conda package and/or the README file) and all notices, 51 | disclaimers or license terms for third party or open source software 52 | included in or with the software. 53 |

54 | EULA: BSD-3-Clause 55 |

56 | 57 | extra: 58 | recipe-maintainers: 59 | - ekomarova 60 | - vtavana 61 | - xaleryb 62 | -------------------------------------------------------------------------------- /mkl/_init_helper.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, Intel Corporation 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions are met: 5 | # 6 | # * Redistributions of source code must retain the above copyright notice, 7 | # this list of conditions and the following disclaimer. 8 | # * Redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution. 11 | # * Neither the name of Intel Corporation nor the names of its contributors 12 | # may be used to endorse or promote products derived from this software 13 | # without specific prior written permission. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 19 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | import os 27 | import os.path 28 | import sys 29 | 30 | is_venv_win32 = ( 31 | sys.platform == "win32" 32 | and sys.base_exec_prefix != sys.exec_prefix 33 | and os.path.isfile(os.path.join(sys.exec_prefix, "pyvenv.cfg")) 34 | ) 35 | 36 | if is_venv_win32: 37 | # In Windows venv: add Library/bin to PATH for proper DLL loading 38 | dll_dir = os.path.join(sys.exec_prefix, "Library", "bin") 39 | if os.path.isdir(dll_dir): 40 | os.add_dll_directory(dll_dir) 41 | 42 | del is_venv_win32 43 | -------------------------------------------------------------------------------- /.github/workflows/build-with-clang.yml: -------------------------------------------------------------------------------- 1 | name: Build project with IntelLLVM clang compiler 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | permissions: read-all 10 | 11 | jobs: 12 | build-with-clang: 13 | runs-on: ubuntu-latest 14 | 15 | strategy: 16 | matrix: 17 | python: ["3.10", "3.11", "3.12", "3.13"] 18 | 19 | env: 20 | ONEAPI_ROOT: /opt/intel/oneapi 21 | 22 | defaults: 23 | run: 24 | shell: bash -el {0} 25 | 26 | steps: 27 | - name: Cancel Previous Runs 28 | uses: styfle/cancel-workflow-action@85880fa0301c86cca9da44039ee3bb12d3bedbfa # 0.12.1 29 | with: 30 | access_token: ${{ github.token }} 31 | 32 | - name: Add Intel repository 33 | run: | 34 | wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB 35 | sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB 36 | rm GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB 37 | sudo add-apt-repository "deb https://apt.repos.intel.com/oneapi all main" 38 | sudo apt-get update 39 | 40 | - name: Install Intel OneAPI 41 | run: | 42 | sudo apt-get install intel-oneapi-compiler-dpcpp-cpp 43 | sudo apt-get install intel-oneapi-tbb 44 | sudo apt-get install intel-oneapi-mkl-devel 45 | 46 | - name: Setup Python 47 | uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 48 | with: 49 | python-version: ${{ matrix.python }} 50 | architecture: x64 51 | 52 | - name: Checkout repo 53 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 54 | with: 55 | fetch-depth: 0 56 | 57 | - name: Install mkl-service dependencies 58 | uses: BSFishy/pip-action@8f2d471d809dc20b6ada98c91910b6ae6243f318 # v1 59 | with: 60 | packages: | 61 | cython 62 | setuptools>=77 63 | pytest 64 | 65 | - name: List oneAPI folder content 66 | run: ls ${{ env.ONEAPI_ROOT }}/compiler 67 | 68 | - name: Build mkl-service 69 | run: | 70 | source ${{ env.ONEAPI_ROOT }}/setvars.sh 71 | echo $CMPLR_ROOT 72 | export CC=$CMPLR_ROOT/bin/icx 73 | export CFLAGS="${CFLAGS} -fno-fast-math" 74 | python setup.py develop 75 | 76 | - name: Run mkl-service tests 77 | run: | 78 | source ${{ env.ONEAPI_ROOT }}/setvars.sh 79 | pytest -s -v --pyargs mkl 80 | -------------------------------------------------------------------------------- /mkl/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018, Intel Corporation 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions are met: 5 | # 6 | # * Redistributions of source code must retain the above copyright notice, 7 | # this list of conditions and the following disclaimer. 8 | # * Redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution. 11 | # * Neither the name of Intel Corporation nor the names of its contributors 12 | # may be used to endorse or promote products derived from this software 13 | # without specific prior written permission. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 19 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | import sys 27 | 28 | from . import _init_helper 29 | 30 | 31 | class RTLD_for_MKL: 32 | def __init__(self): 33 | self.saved_rtld = None 34 | 35 | def __enter__(self): 36 | import ctypes 37 | 38 | try: 39 | self.saved_rtld = sys.getdlopenflags() 40 | # python loads libraries with RTLD_LOCAL, but MKL requires 41 | # RTLD_GLOBAL pre-load MKL with RTLD_GLOBAL before loading 42 | # the native extension 43 | sys.setdlopenflags(self.saved_rtld | ctypes.RTLD_GLOBAL) 44 | except AttributeError: 45 | pass 46 | del ctypes 47 | 48 | def __exit__(self, *args): 49 | if self.saved_rtld: 50 | sys.setdlopenflags(self.saved_rtld) 51 | self.saved_rtld = None 52 | 53 | 54 | with RTLD_for_MKL(): 55 | from . import _mklinit 56 | 57 | del RTLD_for_MKL 58 | del sys 59 | 60 | from ._py_mkl_service import * 61 | from ._version import __version__ 62 | 63 | del _init_helper 64 | -------------------------------------------------------------------------------- /examples/example.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018, Intel Corporation 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions are met: 5 | # 6 | # * Redistributions of source code must retain the above copyright notice, 7 | # this list of conditions and the following disclaimer. 8 | # * Redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution. 11 | # * Neither the name of Intel Corporation nor the names of its contributors 12 | # may be used to endorse or promote products derived from this software 13 | # without specific prior written permission. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 19 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | # pylint: disable=no-member 27 | 28 | import re 29 | 30 | import mkl 31 | 32 | 33 | def enable_best_instructions_set(): 34 | for instructions_set in ["avx512", "avx2", "avx", "sse4_2"]: 35 | if mkl.enable_instructions(instructions_set) == "success": 36 | result = instructions_set 37 | break 38 | else: 39 | result = "error" 40 | 41 | return result 42 | 43 | 44 | def is_max_supported_instructions_set(instructions_set): 45 | result = False 46 | if re.search( 47 | instructions_set.replace("4_2", "4.2"), 48 | mkl.get_version()["Processor"].decode(), 49 | re.IGNORECASE, 50 | ): 51 | result = True 52 | 53 | return result 54 | 55 | 56 | if __name__ == "__main__": 57 | time_begin = mkl.dsecnd() 58 | print(mkl.get_version_string()) 59 | 60 | instructions_set = enable_best_instructions_set() 61 | print("Enable snstructions set: " + str(instructions_set)) 62 | 63 | is_max = is_max_supported_instructions_set(instructions_set) 64 | print("Is the best supported instructions set: " + str(is_max)) 65 | 66 | time_end = mkl.dsecnd() 67 | print("Execution time: " + str(time_end - time_begin)) 68 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v6.0.0 4 | hooks: 5 | - id: check-ast 6 | - id: check-builtin-literals 7 | - id: check-case-conflict 8 | - id: check-executables-have-shebangs 9 | - id: check-merge-conflict 10 | - id: check-toml 11 | - id: debug-statements 12 | - id: destroyed-symlinks 13 | - id: end-of-file-fixer 14 | - id: fix-byte-order-marker 15 | - id: mixed-line-ending 16 | - id: trailing-whitespace 17 | 18 | - repo: https://github.com/pre-commit/pygrep-hooks 19 | rev: v1.10.0 20 | hooks: 21 | - id: python-check-blanket-noqa 22 | - id: python-check-blanket-type-ignore 23 | - id: python-check-mock-methods 24 | - id: python-no-eval 25 | - id: python-no-log-warn 26 | - id: python-use-type-annotations 27 | - id: rst-backticks 28 | - id: rst-directive-colons 29 | - id: rst-inline-touching-normal 30 | - id: text-unicode-replacement-char 31 | 32 | - repo: https://github.com/codespell-project/codespell 33 | rev: v2.4.1 34 | hooks: 35 | - id: codespell 36 | additional_dependencies: 37 | - tomli 38 | 39 | - repo: https://github.com/psf/black 40 | rev: 25.9.0 41 | hooks: 42 | - id: black 43 | exclude: "_vendored/conv_template.py" 44 | 45 | - repo: https://github.com/pocc/pre-commit-hooks 46 | rev: v1.3.5 47 | hooks: 48 | - id: clang-format 49 | args: ["-i"] 50 | 51 | - repo: https://github.com/MarcoGorelli/cython-lint 52 | rev: v0.17.0 53 | hooks: 54 | - id: cython-lint 55 | - id: double-quote-cython-strings 56 | 57 | - repo: https://github.com/pycqa/flake8 58 | rev: 7.3.0 59 | hooks: 60 | - id: flake8 61 | args: ["--config=.flake8"] 62 | additional_dependencies: 63 | - flake8-docstrings==1.7.0 64 | - flake8-bugbear==24.4.26 65 | 66 | - repo: https://github.com/pycqa/isort 67 | rev: 6.1.0 68 | hooks: 69 | - id: isort 70 | name: isort (python) 71 | - id: isort 72 | name: isort (cython) 73 | types: [cython] 74 | - id: isort 75 | name: isort (pyi) 76 | types: [pyi] 77 | 78 | - repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks 79 | rev: v2.15.0 80 | hooks: 81 | - id: pretty-format-toml 82 | args: [--autofix] 83 | 84 | - repo: local 85 | hooks: 86 | - id: pylint 87 | name: pylint 88 | entry: pylint 89 | language: system 90 | types: [python] 91 | require_serial: true 92 | args: 93 | [ 94 | "-rn", # Only display messages 95 | "-sn", # Don't display the score 96 | "--errors-only", 97 | "--disable=import-error", 98 | ] 99 | 100 | - repo: https://github.com/jumanjihouse/pre-commit-hooks 101 | rev: 3.0.0 102 | hooks: 103 | - id: shellcheck 104 | -------------------------------------------------------------------------------- /.github/workflows/openssf-scorecard.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. They are provided 2 | # by a third-party and are governed by separate terms of service, privacy 3 | # policy, and support documentation. 4 | 5 | name: Scorecard supply-chain security 6 | on: 7 | # For Branch-Protection check. Only the default branch is supported. See 8 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection 9 | branch_protection_rule: 10 | # To guarantee Maintained check is occasionally updated. See 11 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained 12 | schedule: 13 | - cron: '28 2 * * 1' 14 | - cron: '28 2 * * 4' 15 | push: 16 | branches: [ "master" ] 17 | 18 | # Declare default permissions as read only. 19 | permissions: read-all 20 | 21 | jobs: 22 | analysis: 23 | name: Scorecard analysis 24 | runs-on: ubuntu-latest 25 | timeout-minutes: 30 26 | permissions: 27 | # Needed to upload the results to code-scanning dashboard. 28 | security-events: write 29 | # Needed to publish results and get a badge (see publish_results below). 30 | id-token: write 31 | # Uncomment the permissions below if installing in a private repository. 32 | # contents: read 33 | # actions: read 34 | 35 | steps: 36 | - name: "Checkout code" 37 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 38 | with: 39 | persist-credentials: false 40 | 41 | - name: "Run analysis" 42 | uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 43 | with: 44 | results_file: results.sarif 45 | results_format: sarif 46 | # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: 47 | # - you want to enable the Branch-Protection check on a *public* repository, or 48 | # - you are installing Scorecard on a *private* repository 49 | # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat. 50 | # repo_token: ${{ secrets.SCORECARD_TOKEN }} 51 | 52 | # Public repositories: 53 | # - Publish results to OpenSSF REST API for easy access by consumers 54 | # - Allows the repository to include the Scorecard badge. 55 | # - See https://github.com/ossf/scorecard-action#publishing-results. 56 | # For private repositories: 57 | # - `publish_results` will always be set to `false`, regardless 58 | # of the value entered here. 59 | publish_results: true 60 | 61 | # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF 62 | # format to the repository Actions tab. 63 | - name: "Upload artifact" 64 | uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 65 | with: 66 | name: SARIF file 67 | path: results.sarif 68 | retention-days: 14 69 | 70 | # Upload the results to GitHub's code scanning dashboard. 71 | - name: "Upload to code-scanning" 72 | uses: github/codeql-action/upload-sarif@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5 73 | with: 74 | sarif_file: results.sarif 75 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, Intel Corporation 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions are met: 5 | # 6 | # * Redistributions of source code must retain the above copyright notice, 7 | # this list of conditions and the following disclaimer. 8 | # * Redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution. 11 | # * Neither the name of Intel Corporation nor the names of its contributors 12 | # may be used to endorse or promote products derived from this software 13 | # without specific prior written permission. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 19 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | [build-system] 27 | build-backend = "setuptools.build_meta" 28 | requires = ["setuptools>=77", "Cython", "wheel>=0.45.1", "build>=1.2.2"] 29 | 30 | [project] 31 | authors = [ 32 | {name = "Intel Corporation", email = "scripting@intel.com"} 33 | ] 34 | classifiers = [ 35 | "Development Status :: 5 - Production/Stable", 36 | "Intended Audience :: Science/Research", 37 | "Intended Audience :: Developers", 38 | "Programming Language :: C", 39 | "Programming Language :: Python", 40 | "Programming Language :: Python :: 3", 41 | "Programming Language :: Python :: 3.10", 42 | "Programming Language :: Python :: 3.11", 43 | "Programming Language :: Python :: 3.12", 44 | "Programming Language :: Python :: 3.13", 45 | "Programming Language :: Python :: 3.14", 46 | "Programming Language :: Python :: Implementation :: CPython", 47 | "Topic :: Software Development", 48 | "Topic :: Utilities", 49 | "Operating System :: Microsoft :: Windows", 50 | "Operating System :: POSIX", 51 | "Operating System :: Unix" 52 | ] 53 | dependencies = [] 54 | description = "Python hooks for Intel® oneAPI Math Kernel Library (oneMKL) runtime control settings" 55 | dynamic = ["version"] 56 | keywords = ["MKL"] 57 | license = "BSD-3-Clause" 58 | name = "mkl-service" 59 | readme = {file = "README.md", content-type = "text/markdown"} 60 | requires-python = ">=3.10,<3.15" 61 | 62 | [project.optional-dependencies] 63 | test = ["pytest"] 64 | 65 | [project.urls] 66 | Download = "http://github.com/IntelPython/mkl-service" 67 | Homepage = "http://github.com/IntelPython/mkl-service" 68 | 69 | [tool.setuptools] 70 | include-package-data = true 71 | packages = ["mkl"] 72 | 73 | [tool.setuptools.dynamic] 74 | version = {attr = "mkl._version.__version__"} 75 | 76 | [tool.setuptools.package-data] 77 | "mkl" = ["tests/*.py"] 78 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at scripting@intel.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018, Intel Corporation 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions are met: 5 | # 6 | # * Redistributions of source code must retain the above copyright notice, 7 | # this list of conditions and the following disclaimer. 8 | # * Redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution. 11 | # * Neither the name of Intel Corporation nor the names of its contributors 12 | # may be used to endorse or promote products derived from this software 13 | # without specific prior written permission. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 19 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | 27 | import os 28 | import sys 29 | from os.path import join 30 | 31 | import Cython.Build 32 | from setuptools import Extension, setup 33 | 34 | 35 | def extensions(): 36 | mkl_root = os.environ.get("MKLROOT", None) 37 | if mkl_root: 38 | mkl_info = { 39 | "include_dirs": [join(mkl_root, "include")], 40 | "library_dirs": [join(mkl_root, "lib"), join(mkl_root, "lib", "intel64")], 41 | "libraries": ["mkl_rt"], 42 | } 43 | else: 44 | raise ValueError("MKLROOT environment variable not set.") 45 | 46 | if sys.platform != "win32": 47 | mkl_info["rpaths"] = ["$ORIGIN/../..", "$ORIGIN/../../.."] 48 | 49 | mkl_include_dirs = mkl_info.get("include_dirs", []) 50 | mkl_library_dirs = mkl_info.get("library_dirs", []) 51 | mkl_libraries = mkl_info.get("libraries", ["mkl_rt"]) 52 | mkl_rpaths = mkl_info.get("rpaths", []) 53 | 54 | defs = [] 55 | if any(["mkl_rt" in li for li in mkl_libraries]): 56 | # libs += ["dl"] - by default on Linux 57 | defs += [("USING_MKL_RT", None)] 58 | 59 | extensions = [] 60 | extensions.append( 61 | Extension( 62 | "mkl._mklinit", 63 | sources=[join("mkl", "_mklinitmodule.c")], 64 | include_dirs=mkl_include_dirs, 65 | libraries=mkl_libraries + (["pthread"] if os.name == "posix" else []), 66 | library_dirs=mkl_library_dirs, 67 | runtime_library_dirs=mkl_rpaths, 68 | extra_compile_args=[ 69 | "-DNDEBUG" 70 | # "-g", "-O2", "-Wall", 71 | ], 72 | define_macros=defs, 73 | ) 74 | ) 75 | 76 | extensions.append( 77 | Extension( 78 | "mkl._py_mkl_service", 79 | sources=[join("mkl", "_mkl_service.pyx")], 80 | include_dirs=mkl_include_dirs, 81 | library_dirs=mkl_library_dirs, 82 | libraries=mkl_libraries, 83 | runtime_library_dirs=mkl_rpaths, 84 | extra_compile_args=[ 85 | "-DNDEBUG" 86 | # "-g", "-O2", "-Wall", 87 | ], 88 | ) 89 | ) 90 | 91 | return extensions 92 | 93 | 94 | setup( 95 | cmdclass={"build_ext": Cython.Build.build_ext}, 96 | ext_modules=extensions(), 97 | zip_safe=False, 98 | ) 99 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [dev] (MM/DD/YYYY) 8 | 9 | ### Removed 10 | * Dropped support for Python 3.9 [gh-118](https://github.com/IntelPython/mkl-service/pull/118) 11 | 12 | ## [2.6.1] (11/25/2025) 13 | 14 | ### Fixed 15 | * Fixed the run-time dependencies of `mkl-service` package to explicitly depend on a non–free-threaded (GIL-enabled) Python [gh-111](github.com/IntelPython/mkl-service/pull/111) 16 | 17 | ## [2.6.0] (10/06/2025) 18 | 19 | ### Added 20 | * Enabled support of Python 3.14 [gh-100](https://github.com/IntelPython/mkl-service/pull/100) 21 | 22 | ### Changed 23 | * Used `GIT_DESCRIBE_TAG` and `GIT_DESCRIBE_NUMBER` in `meta.yaml` instead of manual stepping the numbers [gh-98](github.com/IntelPython/mkl-service/pull/98) 24 | 25 | ## [2.5.2] (07/01/2025) 26 | 27 | ### Fixed 28 | * Updated `meta.yaml` with proper license description to pass the validation rules [gh-87](github.com/IntelPython/mkl-service/pull/87) 29 | 30 | ## [2.5.1] (06/27/2025) 31 | 32 | ### Fixed 33 | * Resolved import issue in the virtual environment which broke loading of MKL libs [gh-85](github.com/IntelPython/mkl-service/pull/85) 34 | 35 | ## [2.5.0] (06/03/2025) 36 | 37 | ### Added 38 | * Added support for python 3.13 [gh-72](github.com/IntelPython/mkl-service/pull/72) 39 | * Added support in virtual environment out of the box [gh-79](github.com/IntelPython/mkl-service/pull/79) 40 | 41 | ### Changed 42 | * Migrated from `setup.py` to `pyproject.toml` [gh-66](github.com/IntelPython/mkl-service/pull/66) 43 | 44 | ## [2.4.2] (10/12/2024) 45 | 46 | Tests checking library version moved to the end of the test suite, as after it is run, the state of the library is finalized, and tests that modify that state may fail. 47 | 48 | Updated installation instructions. 49 | 50 | ## [2.4.1] 51 | 52 | Transition from `nose` to `unittest` and then to `pytest` to enable support for Python 3.12. 53 | 54 | Added Github Actions CI. 55 | 56 | Removed `six` as a dependency. 57 | 58 | ## [2.4.0.post1] 59 | 60 | Update description for PyPI package installation 61 | 62 | ## [2.4.0] 63 | 64 | Fixed issue [#14](https://github.com/IntelPython/mkl-service/issues/14). 65 | 66 | Added [`mkl.set_num_stripes`](https://software.intel.com/content/www/us/en/develop/documentation/onemkl-developer-reference-c/top/support-functions/threading-control/mkl-set-num-stripes.html) and [`mkl.get_num_stripes`](https://software.intel.com/content/www/us/en/develop/documentation/onemkl-developer-reference-c/top/support-functions/threading-control/mkl-get-num-stripes.html) 67 | 68 | Also expanded support `isa` keyword argument values in `mkl.enable_instructions(isa=isa)` function per recent [Intel® oneAPI Math Kernel Library (oneMKL)](https://www.intel.com/content/www/us/en/docs/onemkl/developer-guide-linux/2025-2/instruction-set-specific-dispatch-on-intel-archs.html) support. 69 | 70 | ## [2.3.0] 71 | 72 | Fixed CI to actually execute tests. Populated CBWR constants to match MKL headers. 73 | 74 | Added tests checking that `cbwr_set` and `cbwr_get` round-trip. 75 | 76 | ## [2.2.0] 77 | 78 | Closed issues #8, #7 and #5. 79 | 80 | Extended `mkl.cbwr_set` to recognize `'avx512_e1'`, `'avx512_mic_e1'`, as as strict conditional numerical reproducibility, supported via `'avx2,strict'`, `'avx512,strict'` (see [issue/8](http://github.com/IntelPython/mkl-service/issues/8)). 81 | 82 | Extended `mkl.cbwrt_get()` to mean `mkl.cbwr('all')`. 83 | 84 | ## [2.1.0] 85 | 86 | Change in setup script to not use `numpy.distutils` thus removing numpy as build-time dependency. 87 | 88 | Change in conda-recipe to allow conda build to build the recipe, but ignoring run export on mkl-service coming from mkl-devel metadata. 89 | 90 | ## [2.0.2] 91 | 92 | Correction to `setup.py` to not require Cython at the installation time. 93 | 94 | ## [2.0.1] 95 | 96 | Re-release, with some changes necessary for public CI builds to work. 97 | 98 | ## [2.0.0] 99 | 100 | Work-around for VS 9.0 not having `inline` keyword, allowing the package to build on Windows for Python 2.7 101 | 102 | ## [2.0.0] 103 | 104 | Rerelease of `mkl-service` package with version bumped to 2.0.0 to avoid version clash with `mkl-service` package from Anaconda. 105 | 106 | Improved argument checking, which raises an informative error. 107 | 108 | Loading the package with `import mkl` initializes Intel(R) MKL library to use LP64 interface (i.e. use of environment variable `MKL_INTERFACE` will not have effect). 109 | 110 | The choice of threading layer can be controlled with environment variable `MKL_THREADING_LAYER`. However the unset variable is interpreted differently that in Intel(R) MKL itself. If `mkl-service` detects that Gnu OpenMP has been loaded in Python space, the threading layer of Intle(R) MKL will be set to Gnu OpenMP, instead of Intel(R) OpenMP. 111 | 112 | ## [1.0.0] 113 | 114 | Initial release of `mkl-service` package. 115 | -------------------------------------------------------------------------------- /mkl/_mkl_service.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018, Intel Corporation 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions are met: 5 | # 6 | # * Redistributions of source code must retain the above copyright notice, 7 | # this list of conditions and the following disclaimer. 8 | # * Redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution. 11 | # * Neither the name of Intel Corporation nor the names of its contributors 12 | # may be used to endorse or promote products derived from this software 13 | # without specific prior written permission. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 19 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | 27 | ctypedef long long MKL_INT64 28 | ctypedef unsigned long long MKL_UINT64 29 | ctypedef int MKL_INT 30 | 31 | 32 | cdef extern from "mkl.h": 33 | # MKL Function Domains Constants 34 | int MKL_DOMAIN_BLAS 35 | int MKL_DOMAIN_FFT 36 | int MKL_DOMAIN_VML 37 | int MKL_DOMAIN_PARDISO 38 | int MKL_DOMAIN_ALL 39 | 40 | # MKL Peak Memory Usage Constants 41 | int MKL_PEAK_MEM_ENABLE 42 | int MKL_PEAK_MEM_DISABLE 43 | int MKL_PEAK_MEM 44 | int MKL_PEAK_MEM_RESET 45 | int MKL_MEM_MCDRAM 46 | 47 | # CNR Control Constants 48 | int MKL_CBWR_BRANCH 49 | int MKL_CBWR_ALL 50 | 51 | int MKL_CBWR_STRICT 52 | 53 | int MKL_CBWR_OFF 54 | int MKL_CBWR_BRANCH_OFF 55 | int MKL_CBWR_AUTO 56 | int MKL_CBWR_COMPATIBLE 57 | int MKL_CBWR_SSE2 58 | int MKL_CBWR_SSSE3 59 | int MKL_CBWR_SSE4_1 60 | int MKL_CBWR_SSE4_2 61 | int MKL_CBWR_AVX 62 | int MKL_CBWR_AVX2 63 | int MKL_CBWR_AVX512_MIC 64 | int MKL_CBWR_AVX512 65 | int MKL_CBWR_AVX512_MIC_E1 66 | int MKL_CBWR_AVX512_E1 67 | 68 | int MKL_CBWR_SUCCESS 69 | int MKL_CBWR_ERR_INVALID_SETTINGS 70 | int MKL_CBWR_ERR_INVALID_INPUT 71 | int MKL_CBWR_ERR_UNSUPPORTED_BRANCH 72 | int MKL_CBWR_ERR_UNKNOWN_BRANCH 73 | int MKL_CBWR_ERR_MODE_CHANGE_FAILURE 74 | 75 | # ISA Constants 76 | int MKL_SINGLE_PATH_ENABLE 77 | int MKL_ENABLE_AVX512_E2 78 | int MKL_ENABLE_AVX512_E3 79 | int MKL_ENABLE_AVX512_E4 80 | int MKL_ENABLE_AVX512_MIC_E1 81 | int MKL_ENABLE_AVX512_E1 82 | int MKL_ENABLE_AVX512 83 | int MKL_ENABLE_AVX512_MIC 84 | int MKL_ENABLE_AVX2 85 | int MKL_ENABLE_AVX2_E1 86 | int MKL_ENABLE_AVX 87 | int MKL_ENABLE_SSE4_2 88 | 89 | # MPI Implementation Constants 90 | int MKL_BLACS_CUSTOM 91 | int MKL_BLACS_MSMPI 92 | int MKL_BLACS_INTELMPI 93 | int MKL_BLACS_MPICH2 94 | int MKL_BLACS_LASTMPI 95 | 96 | # VML Constants 97 | int VML_HA 98 | int VML_LA 99 | int VML_EP 100 | int VML_FTZDAZ_ON 101 | int VML_FTZDAZ_OFF 102 | int VML_ERRMODE_IGNORE 103 | int VML_ERRMODE_ERRNO 104 | int VML_ERRMODE_STDERR 105 | int VML_ERRMODE_EXCEPT 106 | int VML_ERRMODE_CALLBACK 107 | int VML_ERRMODE_DEFAULT 108 | int VML_STATUS_OK 109 | int VML_STATUS_ACCURACYWARNING 110 | int VML_STATUS_BADSIZE 111 | int VML_STATUS_BADMEM 112 | int VML_STATUS_ERRDOM 113 | int VML_STATUS_SING 114 | int VML_STATUS_OVERFLOW 115 | int VML_STATUS_UNDERFLOW 116 | int VML_ACCURACY_MASK 117 | int VML_FTZDAZ_MASK 118 | int VML_ERRMODE_MASK 119 | 120 | ctypedef struct MKLVersion: 121 | int MajorVersion 122 | int MinorVersion 123 | int UpdateVersion 124 | char* ProductStatus 125 | char* Build 126 | char* Processor 127 | char* Platform 128 | 129 | # MKL support functions 130 | void mkl_get_version(MKLVersion* pv) 131 | void mkl_get_version_string(char* buf, int len) 132 | 133 | # Threading 134 | void mkl_set_num_threads(int nth) 135 | int mkl_domain_set_num_threads(int nt, int domain) 136 | int mkl_set_num_threads_local(int nth) 137 | void mkl_set_dynamic(int flag) 138 | int mkl_get_max_threads() 139 | int mkl_domain_get_max_threads(int domain) 140 | int mkl_get_dynamic() 141 | int mkl_get_num_stripes() 142 | void mkl_set_num_stripes(int) 143 | 144 | # Timing 145 | float second() 146 | double dsecnd() 147 | void mkl_get_cpu_clocks(MKL_UINT64* clocks) 148 | double mkl_get_cpu_frequency() 149 | double mkl_get_max_cpu_frequency() 150 | double mkl_get_clocks_frequency() 151 | 152 | # Memory 153 | void mkl_free_buffers() 154 | void mkl_thread_free_buffers() 155 | int mkl_disable_fast_mm() 156 | MKL_INT64 mkl_mem_stat(int* buf) 157 | MKL_INT64 mkl_peak_mem_usage(int mode) 158 | int mkl_set_memory_limit(int mem_type, size_t limit) 159 | 160 | # Conditional Numerical Reproducibility 161 | int mkl_cbwr_set(int settings) 162 | int mkl_cbwr_get(int option) 163 | int mkl_cbwr_get_auto_branch() 164 | 165 | # Miscellaneous 166 | int mkl_enable_instructions(int isa) 167 | int mkl_set_env_mode(int mode) 168 | int mkl_verbose(int enable) 169 | int mkl_set_mpi(int vendor, const char* custom_library_name) 170 | 171 | # VM Service Functions 172 | unsigned int vmlSetMode(unsigned int mode) 173 | unsigned int vmlGetMode() 174 | int vmlSetErrStatus(const MKL_INT status) 175 | int vmlGetErrStatus() 176 | int vmlClearErrStatus() 177 | -------------------------------------------------------------------------------- /mkl/_mklinitmodule.c: -------------------------------------------------------------------------------- 1 | /* -*- c -*- */ 2 | 3 | /* 4 | * This is a dummy module whose purpose is to get distutils to generate the 5 | * configuration files before the libraries are made. 6 | */ 7 | 8 | #if (defined(USING_MKL_RT) && defined(__linux__)) 9 | #define FORCE_PRELOADING 1 10 | #define _GNU_SOURCE 1 11 | #include 12 | #include 13 | #include 14 | #undef _GNU_SOURCE 15 | #endif 16 | 17 | #include 18 | #if PY_MAJOR_VERSION >= 3 19 | #define IS_PY3K 20 | #endif 21 | #include "mkl.h" 22 | 23 | static struct PyMethodDef methods[] = {{NULL, NULL, 0, NULL}}; 24 | 25 | #if defined(_MSC_VER) && (_MSC_VER <= 1500) 26 | #define MKL_SERVICE_INLINE 27 | #else 28 | #define MKL_SERVICE_INLINE inline 29 | #endif 30 | 31 | static MKL_SERVICE_INLINE void _set_mkl_ilp64(void); 32 | static MKL_SERVICE_INLINE void _set_mkl_lp64(void); 33 | static MKL_SERVICE_INLINE void _set_mkl_interface(void); 34 | 35 | static const char *mtlayer; 36 | static const char *verbose; 37 | 38 | #if FORCE_PRELOADING 39 | #define VERBOSE(...) \ 40 | if (verbose) \ 41 | printf("mkl-service + Intel(R) MKL: " __VA_ARGS__) 42 | 43 | static void restore_mtlayer(void) { 44 | if (mtlayer) { 45 | VERBOSE( 46 | "Re-setting Intel(R) MKL_THREADING_LAYER=%s for the forked process\n", 47 | mtlayer); 48 | setenv("MKL_THREADING_LAYER", mtlayer, 1); 49 | } else { 50 | VERBOSE("Unsetting Intel(R) MKL_THREADING_LAYER variable for the forked " 51 | "process \n"); 52 | unsetenv("MKL_THREADING_LAYER"); 53 | } 54 | } 55 | #endif 56 | 57 | static void _preload_threading_layer(void) { 58 | #if FORCE_PRELOADING 59 | #define SET_MTLAYER(L) \ 60 | do { \ 61 | VERBOSE("setting Intel(R) MKL to use " #L " OpenMP runtime\n"); \ 62 | mkl_set_threading_layer(MKL_THREADING_##L); \ 63 | setenv("MKL_THREADING_LAYER", #L, 0); \ 64 | pthread_atfork(NULL, NULL, &restore_mtlayer); \ 65 | } while (0) 66 | #define PRELOAD(lib) \ 67 | do { \ 68 | VERBOSE("preloading %s runtime\n", lib); \ 69 | dlopen(lib, RTLD_LAZY | RTLD_GLOBAL); \ 70 | } while (0) 71 | /* 72 | * The following is the pseudo-code skeleton for reinterpreting unset 73 | * MKL_THREADING_LAYER 74 | * 75 | * if MKL_THREADING_LAYER is empty 76 | * if kmp_calloc (or a suitable symbol identified by Terry) is 77 | * loaded, we are using Intel(R) OpenMP, i.e. reinterpret as implicit value of 78 | * INTEL otherwise check if other Open MP is loaded by checking 79 | * get_omp_num_threads symbol if not loaded: assume INTEL, and force loading 80 | * of IOMP5 if loaded: if Gnu OMP, set MKL_THREADING_LAYER=GNU, and call 81 | * set_mkl_threading_layer(MKL_THREADING_GNU) if other vendors? if 82 | * MKL_THREADING_LAYER is INTEL force loading of iomp, to preempt possibility 83 | * of other modules loading other OMP library before MKL is actually used 84 | * 85 | * should we treat other possible values of MKL_THREADING_LAYER 86 | * specially? 87 | * 88 | */ 89 | 90 | const char *libiomp = "libiomp5.so"; 91 | verbose = getenv("MKL_VERBOSE"); 92 | mtlayer = getenv("MKL_THREADING_LAYER"); 93 | 94 | /* Use of RTLD_DEFAULT handler is to indicate that symbol is being lookup-up 95 | * among symbols presently known to this process. 96 | * 97 | * See: https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html 98 | */ 99 | void *omp = dlsym(RTLD_DEFAULT, "omp_get_num_threads"); 100 | const char *omp_name = "(unidentified)"; 101 | const char *iomp = NULL; /* non-zero indicates Intel(R) OpenMP is loaded */ 102 | Dl_info omp_info; 103 | 104 | if (verbose && (verbose[0] == 0 || atoi(verbose) == 0)) 105 | verbose = NULL; 106 | 107 | VERBOSE("THREADING LAYER: %s\n", mtlayer); 108 | 109 | if (omp) { 110 | if (dladdr(omp, &omp_info)) { 111 | omp_name = basename( 112 | omp_info.dli_fname); /* GNU version doesn't modify argument */ 113 | iomp = strstr(omp_name, libiomp); 114 | } 115 | VERBOSE("%s OpenMP runtime %s is already loaded\n", 116 | iomp ? "Intel(R)" : "Other vendor", omp_name); 117 | } 118 | if (!mtlayer || mtlayer[0] == 0) { /* unset or empty */ 119 | if (omp) { /* if OpenMP runtime is loaded */ 120 | if (iomp) /* if Intel runtime is loaded */ 121 | SET_MTLAYER(INTEL); 122 | else /* otherwise, assume it is GNU OpenMP */ 123 | SET_MTLAYER(GNU); 124 | } else { /* nothing is loaded */ 125 | SET_MTLAYER(INTEL); 126 | PRELOAD(libiomp); 127 | } 128 | } else if (strcasecmp(mtlayer, "intel") == 129 | 0) { /* Intel runtime is requested */ 130 | if (omp && !iomp) { 131 | fprintf(stderr, 132 | "Error: mkl-service + Intel(R) MKL: MKL_THREADING_LAYER=INTEL is " 133 | "incompatible with %s library." 134 | "\n\tTry to import numpy first or set the threading layer " 135 | "accordingly. " 136 | "Set MKL_SERVICE_FORCE_INTEL to force it.\n", 137 | omp_name); 138 | if (!getenv("MKL_SERVICE_FORCE_INTEL")) 139 | exit(1); 140 | } else 141 | PRELOAD(libiomp); 142 | } 143 | #endif 144 | return; 145 | } 146 | 147 | static MKL_SERVICE_INLINE void _set_mkl_ilp64(void) { 148 | #ifdef USING_MKL_RT 149 | mkl_set_interface_layer(MKL_INTERFACE_ILP64); 150 | #endif 151 | return; 152 | } 153 | 154 | static MKL_SERVICE_INLINE void _set_mkl_lp64(void) { 155 | #ifdef USING_MKL_RT 156 | mkl_set_interface_layer(MKL_INTERFACE_LP64); 157 | #endif 158 | return; 159 | } 160 | 161 | static MKL_SERVICE_INLINE void _set_mkl_interface(void) { 162 | _set_mkl_lp64(); 163 | _preload_threading_layer(); 164 | } 165 | 166 | #if defined(IS_PY3K) 167 | static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT, 168 | "mklinit", 169 | NULL, 170 | -1, 171 | methods, 172 | NULL, 173 | NULL, 174 | NULL, 175 | NULL}; 176 | #endif 177 | 178 | /* Initialization function for the module */ 179 | #if defined(IS_PY3K) 180 | PyMODINIT_FUNC PyInit__mklinit(void) { 181 | PyObject *m; 182 | 183 | _set_mkl_interface(); 184 | m = PyModule_Create(&moduledef); 185 | if (!m) { 186 | return NULL; 187 | } 188 | 189 | return m; 190 | } 191 | #else 192 | PyMODINIT_FUNC init_mklinit(void) { 193 | _set_mkl_interface(); 194 | Py_InitModule("_mklinit", methods); 195 | } 196 | #endif 197 | -------------------------------------------------------------------------------- /mkl/tests/test_mkl_service.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018, Intel Corporation 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions are met: 5 | # 6 | # * Redistributions of source code must retain the above copyright notice, 7 | # this list of conditions and the following disclaimer. 8 | # * Redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution. 11 | # * Neither the name of Intel Corporation nor the names of its contributors 12 | # may be used to endorse or promote products derived from this software 13 | # without specific prior written permission. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 19 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | # pylint: disable=no-member 27 | 28 | import pytest 29 | 30 | import mkl 31 | 32 | 33 | def test_set_num_threads(): 34 | saved = mkl.get_max_threads() 35 | half_nt = int((1 + saved) / 2) 36 | mkl.set_num_threads(half_nt) 37 | assert mkl.get_max_threads() == half_nt 38 | mkl.set_num_threads(saved) 39 | 40 | 41 | def test_domain_set_num_threads_blas(): 42 | saved_blas_nt = mkl.domain_get_max_threads(domain="blas") 43 | saved_fft_nt = mkl.domain_get_max_threads(domain="fft") 44 | saved_vml_nt = mkl.domain_get_max_threads(domain="vml") 45 | # set 46 | blas_nt = int((3 + saved_blas_nt) / 4) 47 | fft_nt = int((3 + 2 * saved_fft_nt) / 4) 48 | vml_nt = int((3 + 3 * saved_vml_nt) / 4) 49 | status = mkl.domain_set_num_threads(blas_nt, domain="blas") 50 | assert status == "success" 51 | status = mkl.domain_set_num_threads(fft_nt, domain="fft") 52 | assert status == "success" 53 | status = mkl.domain_set_num_threads(vml_nt, domain="vml") 54 | assert status == "success" 55 | # check 56 | assert mkl.domain_get_max_threads(domain="blas") == blas_nt 57 | assert mkl.domain_get_max_threads(domain="fft") == fft_nt 58 | assert mkl.domain_get_max_threads(domain="vml") == vml_nt 59 | # restore 60 | status = mkl.domain_set_num_threads(saved_blas_nt, domain="blas") 61 | assert status == "success" 62 | status = mkl.domain_set_num_threads(saved_fft_nt, domain="fft") 63 | assert status == "success" 64 | status = mkl.domain_set_num_threads(saved_vml_nt, domain="vml") 65 | assert status == "success" 66 | 67 | 68 | def test_domain_set_num_threads_fft(): 69 | status = mkl.domain_set_num_threads(4, domain="fft") 70 | assert status == "success" 71 | 72 | 73 | def test_domain_set_num_threads_vml(): 74 | status = mkl.domain_set_num_threads(4, domain="vml") 75 | assert status == "success" 76 | 77 | 78 | def test_domain_set_num_threads_pardiso(): 79 | status = mkl.domain_set_num_threads(4, domain="pardiso") 80 | assert status == "success" 81 | 82 | 83 | def test_domain_set_num_threads_all(): 84 | status = mkl.domain_set_num_threads(4, domain="all") 85 | assert status == "success" 86 | 87 | 88 | def test_set_num_threads_local(): 89 | mkl.set_num_threads(1) 90 | status = mkl.set_num_threads_local(2) 91 | assert status == "global_num_threads" 92 | status = mkl.set_num_threads_local(4) 93 | assert status == 2 94 | status = mkl.set_num_threads_local(0) 95 | assert status == 4 96 | status = mkl.set_num_threads_local(8) 97 | assert status == "global_num_threads" 98 | 99 | 100 | def test_set_dynamic(): 101 | mkl.set_dynamic(True) 102 | 103 | 104 | def test_get_max_threads(): 105 | mkl.get_max_threads() 106 | 107 | 108 | def test_domain_get_max_threads_blas(): 109 | mkl.domain_get_max_threads(domain="blas") 110 | 111 | 112 | def test_domain_get_max_threads_fft(): 113 | mkl.domain_get_max_threads(domain="fft") 114 | 115 | 116 | def test_domain_get_max_threads_vml(): 117 | mkl.domain_get_max_threads(domain="vml") 118 | 119 | 120 | def test_domain_get_max_threads_pardiso(): 121 | mkl.domain_get_max_threads(domain="pardiso") 122 | 123 | 124 | def test_domain_get_max_threads_all(): 125 | mkl.domain_get_max_threads(domain="all") 126 | 127 | 128 | def test_get_dynamic(): 129 | mkl.get_dynamic() 130 | 131 | 132 | # https://software.intel.com/en-us/mkl-developer-reference-c-timing 133 | def test_second(): 134 | s1 = mkl.second() 135 | s2 = mkl.second() 136 | delta = s2 - s1 137 | assert delta >= 0 138 | 139 | 140 | def test_dsecnd(): 141 | d1 = mkl.dsecnd() 142 | d2 = mkl.dsecnd() 143 | delta = d2 - d1 144 | assert delta >= 0 145 | 146 | 147 | def test_get_cpu_clocks(): 148 | c1 = mkl.get_cpu_clocks() 149 | c2 = mkl.get_cpu_clocks() 150 | delta = c2 - c1 151 | assert delta >= 0 152 | 153 | 154 | def test_get_cpu_frequency(): 155 | assert mkl.get_cpu_frequency() >= 0 156 | 157 | 158 | def test_get_max_cpu_frequency(): 159 | assert mkl.get_max_cpu_frequency() >= 0 160 | 161 | 162 | def test_get_clocks_frequency(): 163 | assert mkl.get_clocks_frequency() >= 0 164 | 165 | 166 | def test_free_buffers(): 167 | mkl.free_buffers() 168 | 169 | 170 | def test_thread_free_buffers(): 171 | mkl.thread_free_buffers() 172 | 173 | 174 | def test_disable_fast_mm(): 175 | mkl.disable_fast_mm() 176 | 177 | 178 | def test_mem_stat(): 179 | mkl.mem_stat() 180 | 181 | 182 | def test_peak_mem_usage_enable(): 183 | mkl.peak_mem_usage("enable") 184 | 185 | 186 | def test_peak_mem_usage_disable(): 187 | mkl.peak_mem_usage("disable") 188 | 189 | 190 | def test_peak_mem_usage_peak_mem(): 191 | mkl.peak_mem_usage("peak_mem") 192 | 193 | 194 | def test_peak_mem_usage_peak_mem_reset(): 195 | mkl.peak_mem_usage("peak_mem_reset") 196 | 197 | 198 | def test_set_memory_limit(): 199 | mkl.set_memory_limit(2**16) 200 | 201 | 202 | def check_cbwr(branch, cnr_const): 203 | status = mkl.cbwr_set(branch=branch) 204 | if status == "success": 205 | expected_value = "branch_off" if branch == "off" else branch 206 | actual_value = mkl.cbwr_get(cnr_const=cnr_const) 207 | assert ( 208 | actual_value == expected_value 209 | ), f"Round-trip failure for CNR branch '{branch}', CNR const '{cnr_const}" 210 | elif status not in ["err_unsupported_branch", "err_mode_change_failure"]: 211 | # if MKL has been initialized already, 212 | # setting CBWR will error with mode_change_failure 213 | pytest.fail(status) 214 | 215 | 216 | branches = [ 217 | "off", 218 | "branch_off", 219 | "auto", 220 | "compatible", 221 | "sse2", 222 | "ssse3", 223 | "sse4_1", 224 | "sse4_2", 225 | "avx", 226 | "avx2", 227 | "avx512_mic", 228 | "avx512", 229 | "avx512_mic_e1", 230 | "avx512_e1", 231 | ] 232 | 233 | 234 | strict = [ 235 | "avx2,strict", 236 | "avx512_mic,strict", 237 | "avx512,strict", 238 | "avx512_e1,strict", 239 | ] 240 | 241 | 242 | @pytest.mark.parametrize("branch", branches) 243 | def test_cbwr_branch(branch): 244 | check_cbwr(branch, "branch") 245 | 246 | 247 | @pytest.mark.parametrize("branch", branches + strict) 248 | def test_cbwr_all(branch): 249 | check_cbwr(branch, "all") 250 | 251 | 252 | def test_cbwr_get_auto_branch(): 253 | mkl.cbwr_get_auto_branch() 254 | 255 | 256 | def test_enable_instructions_avx512_mic_e1(): 257 | mkl.enable_instructions("avx512_mic_e1") 258 | 259 | 260 | def test_enable_instructions_avx512(): 261 | mkl.enable_instructions("avx512") 262 | 263 | 264 | def test_enable_instructions_avx512_mic(): 265 | mkl.enable_instructions("avx512_mic") 266 | 267 | 268 | def test_enable_instructions_avx2(): 269 | mkl.enable_instructions("avx2") 270 | 271 | 272 | def test_enable_instructions_avx(): 273 | mkl.enable_instructions("avx") 274 | 275 | 276 | def test_enable_instructions_sse4_2(): 277 | mkl.enable_instructions("sse4_2") 278 | 279 | 280 | def test_set_env_mode(): 281 | mkl.set_env_mode() 282 | 283 | 284 | def test_get_env_mode(): 285 | mkl.get_env_mode() 286 | 287 | 288 | def test_verbose_false(): 289 | mkl.verbose(False) 290 | 291 | 292 | def test_verbose_true(): 293 | mkl.verbose(True) 294 | 295 | 296 | @pytest.mark.skip(reason="Skipping MPI-related test") 297 | def test_set_mpi_custom(): 298 | mkl.set_mpi("custom", "custom_library_name") 299 | 300 | 301 | @pytest.mark.skip(reason="Skipping MPI-related test") 302 | def test_set_mpi_msmpi(): 303 | mkl.set_mpi("msmpi") 304 | 305 | 306 | @pytest.mark.skip(reason="Skipping MPI-related test") 307 | def test_set_mpi_intelmpi(): 308 | mkl.set_mpi("intelmpi") 309 | 310 | 311 | @pytest.mark.skip(reason="Skipping MPI-related test") 312 | def test_set_mpi_mpich2(): 313 | mkl.set_mpi("mpich2") 314 | 315 | 316 | def test_vml_set_get_mode_roundtrip(): 317 | saved = mkl.vml_get_mode() 318 | mkl.vml_set_mode(*saved) # should not raise errors 319 | 320 | 321 | def test_vml_set_mode_ha_on_ignore(): 322 | mkl.vml_set_mode("ha", "on", "ignore") 323 | 324 | 325 | def test_vml_set_mode_ha_on_errno(): 326 | mkl.vml_set_mode("ha", "on", "errno") 327 | 328 | 329 | def test_vml_set_mode_la_on_stderr(): 330 | mkl.vml_set_mode("la", "on", "stderr") 331 | 332 | 333 | def test_vml_set_mode_la_off_except(): 334 | mkl.vml_set_mode("la", "off", "except") 335 | 336 | 337 | def test_vml_set_mode_op_off_callback(): 338 | mkl.vml_set_mode("ep", "off", "callback") 339 | 340 | 341 | def test_vml_set_mode_ep_off_default(): 342 | mkl.vml_set_mode("ep", "off", "default") 343 | 344 | 345 | def test_vml_get_mode(): 346 | mkl.vml_get_mode() 347 | 348 | 349 | def test_vml_set_err_status_ok(): 350 | mkl.vml_set_err_status("ok") 351 | 352 | 353 | def test_vml_set_err_status_accuracywarning(): 354 | mkl.vml_set_err_status("accuracywarning") 355 | 356 | 357 | def test_vml_set_err_status_badsize(): 358 | mkl.vml_set_err_status("badsize") 359 | 360 | 361 | def test_vml_set_err_status_badmem(): 362 | mkl.vml_set_err_status("badmem") 363 | 364 | 365 | def test_vml_set_err_status_errdom(): 366 | mkl.vml_set_err_status("errdom") 367 | 368 | 369 | def test_vml_set_err_status_sing(): 370 | mkl.vml_set_err_status("sing") 371 | 372 | 373 | def test_vml_set_err_status_overflow(): 374 | mkl.vml_set_err_status("overflow") 375 | 376 | 377 | def test_vml_set_err_status_underflow(): 378 | mkl.vml_set_err_status("underflow") 379 | 380 | 381 | def test_vml_get_err_status(): 382 | mkl.vml_get_err_status() 383 | 384 | 385 | def test_vml_clear_err_status(): 386 | mkl.vml_clear_err_status() 387 | 388 | 389 | def test_get_version(): 390 | """ 391 | Version info sets mode of MKL library, such as 392 | instruction pathways and conditional numerical 393 | reproducibility regime. This test is moved to 394 | the bottom to allow proper testing of functions 395 | controllign those. 396 | """ 397 | v = mkl.get_version() 398 | assert isinstance(v, dict) 399 | assert "MajorVersion" in v 400 | assert "MinorVersion" in v 401 | assert "UpdateVersion" in v 402 | 403 | 404 | def test_get_version_string(): 405 | v = mkl.get_version_string() 406 | assert isinstance(v, str) 407 | assert "Math Kernel Library" in v 408 | -------------------------------------------------------------------------------- /.github/workflows/conda-package.yml: -------------------------------------------------------------------------------- 1 | name: Conda package 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | permissions: read-all 10 | 11 | env: 12 | PACKAGE_NAME: mkl-service 13 | MODULE_NAME: mkl 14 | TEST_ENV_NAME: test_mkl_service 15 | VER_SCRIPT1: "import json; f = open('ver.json', 'r'); j = json.load(f); f.close(); " 16 | VER_SCRIPT2: "d = j['mkl-service'][0]; print('='.join((d[s] for s in ('version', 'build'))))" 17 | 18 | jobs: 19 | build_linux: 20 | runs-on: ubuntu-latest 21 | 22 | strategy: 23 | matrix: 24 | python: ['3.10', '3.11', '3.12', '3.13', '3.14'] 25 | 26 | steps: 27 | - name: Cancel Previous Runs 28 | uses: styfle/cancel-workflow-action@85880fa0301c86cca9da44039ee3bb12d3bedbfa # 0.12.1 29 | with: 30 | access_token: ${{ github.token }} 31 | 32 | - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 33 | with: 34 | fetch-depth: 0 35 | 36 | - name: Set pkgs_dirs 37 | run: | 38 | echo "pkgs_dirs: [~/.conda/pkgs]" >> ~/.condarc 39 | 40 | - name: Cache conda packages 41 | uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 42 | env: 43 | CACHE_NUMBER: 0 # Increase to reset cache 44 | with: 45 | path: ~/.conda/pkgs 46 | key: 47 | ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}-${{hashFiles('**/meta.yaml') }} 48 | restore-keys: | 49 | ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}- 50 | ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}- 51 | 52 | - name: Add conda to system path 53 | run: echo $CONDA/bin >> $GITHUB_PATH 54 | 55 | - name: Install conda-build 56 | run: conda install conda-build 57 | 58 | - name: Store conda paths as envs 59 | shell: bash -el {0} 60 | run: | 61 | echo "CONDA_BLD=/usr/share/miniconda/conda-bld/linux-64/" >> $GITHUB_ENV 62 | echo "WHEELS_OUTPUT_FOLDER=$GITHUB_WORKSPACE/" >> $GITHUB_ENV 63 | 64 | - name: Build conda package 65 | run: | 66 | CHANNELS="-c conda-forge -c conda-forge/label/python_rc -c https://software.repos.intel.com/python/conda --override-channels" 67 | VERSIONS="--python ${{ matrix.python }}" 68 | TEST="--no-test" 69 | 70 | conda build \ 71 | $TEST \ 72 | $VERSIONS \ 73 | $CHANNELS \ 74 | conda-recipe 75 | 76 | - name: Upload artifact 77 | uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 78 | with: 79 | name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python }} 80 | path: ${{ env.CONDA_BLD }}${{ env.PACKAGE_NAME }}-*.conda 81 | 82 | - name: Upload wheels artifact 83 | uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 84 | with: 85 | name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Wheels Python ${{ matrix.python }} 86 | path: ${{ env.WHEELS_OUTPUT_FOLDER }}mkl_service-*.whl 87 | 88 | build_windows: 89 | runs-on: windows-latest 90 | 91 | strategy: 92 | matrix: 93 | python: ['3.10', '3.11', '3.12', '3.13', '3.14'] 94 | 95 | steps: 96 | - name: Cancel Previous Runs 97 | uses: styfle/cancel-workflow-action@85880fa0301c86cca9da44039ee3bb12d3bedbfa # 0.12.1 98 | with: 99 | access_token: ${{ github.token }} 100 | 101 | - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 102 | with: 103 | fetch-depth: 0 104 | - uses: conda-incubator/setup-miniconda@835234971496cad1653abb28a638a281cf32541f # v3.2.0 105 | with: 106 | miniforge-version: latest 107 | use-mamba: 'true' 108 | conda-remove-defaults: 'true' 109 | activate-environment: 'build' 110 | python-version: '3.13' # no python 3.14 support by conda-build 111 | 112 | - name: Cache conda packages 113 | uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 114 | env: 115 | CACHE_NUMBER: 3 # Increase to reset cache 116 | with: 117 | path: /home/runner/conda_pkgs_dir 118 | key: 119 | ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}-${{hashFiles('**/meta.yaml') }} 120 | restore-keys: | 121 | ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}- 122 | ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}- 123 | 124 | - name: Install conda-build 125 | run: conda install conda-build 126 | 127 | - name: Store conda paths as envs 128 | shell: bash -el {0} 129 | run: | 130 | echo "CONDA_BLD=$CONDA_PREFIX\\conda-bld\\win-64\\" >> $GITHUB_ENV 131 | echo "WHEELS_OUTPUT_FOLDER=$GITHUB_WORKSPACE\\" >> $GITHUB_ENV 132 | 133 | - name: Build conda package 134 | run: conda build --no-test --python ${{ matrix.python }} -c https://software.repos.intel.com/python/conda -c conda-forge -c conda-forge/label/python_rc --override-channels conda-recipe 135 | 136 | - name: Upload artifact 137 | uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 138 | with: 139 | name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python }} 140 | path: ${{ env.CONDA_BLD }}${{ env.PACKAGE_NAME }}-*.conda 141 | 142 | - name: Upload wheels artifact 143 | uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 144 | with: 145 | name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Wheels Python ${{ matrix.python }} 146 | path: ${{ env.WHEELS_OUTPUT_FOLDER }}mkl_service-*.whl 147 | 148 | test_linux: 149 | needs: build_linux 150 | runs-on: ${{ matrix.runner }} 151 | 152 | strategy: 153 | matrix: 154 | python: ['3.10', '3.11', '3.12', '3.13', '3.14'] 155 | experimental: [false] 156 | runner: [ubuntu-latest] 157 | continue-on-error: ${{ matrix.experimental }} 158 | env: 159 | CHANNELS: -c conda-forge -c conda-forge/label/python_rc -c https://software.repos.intel.com/python/conda --override-channels 160 | 161 | steps: 162 | - name: Download artifact 163 | uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 164 | with: 165 | name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python }} 166 | 167 | - name: Add conda to system path 168 | run: echo $CONDA/bin >> $GITHUB_PATH 169 | 170 | - name: Install conda-build 171 | run: conda install conda-build 172 | 173 | - name: Create conda channel 174 | run: | 175 | mkdir -p $GITHUB_WORKSPACE/channel/linux-64 176 | conda index $GITHUB_WORKSPACE/channel || exit 1 177 | mv ${PACKAGE_NAME}-*.conda $GITHUB_WORKSPACE/channel/linux-64 || exit 1 178 | conda index $GITHUB_WORKSPACE/channel || exit 1 179 | # Test channel 180 | conda search $PACKAGE_NAME -c $GITHUB_WORKSPACE/channel --override-channels --info --json > $GITHUB_WORKSPACE/ver.json 181 | cat ver.json 182 | 183 | - name: Collect dependencies 184 | run: | 185 | . $CONDA/etc/profile.d/conda.sh 186 | CHANNELS="-c $GITHUB_WORKSPACE/channel ${{ env.CHANNELS }}" 187 | export PACKAGE_VERSION=$(python -c "${VER_SCRIPT1} ${VER_SCRIPT2}") 188 | conda create -n ${{ env.TEST_ENV_NAME }} $PACKAGE_NAME=${PACKAGE_VERSION} python=${{ matrix.python }} $CHANNELS --only-deps --dry-run > lockfile 189 | cat lockfile 190 | 191 | - name: Set pkgs_dirs 192 | run: | 193 | echo "pkgs_dirs: [~/.conda/pkgs]" >> ~/.condarc 194 | 195 | - name: Cache conda packages 196 | uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 197 | env: 198 | CACHE_NUMBER: 0 # Increase to reset cache 199 | with: 200 | path: ~/.conda/pkgs 201 | key: 202 | ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}-${{hashFiles('lockfile') }} 203 | restore-keys: | 204 | ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}- 205 | ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}- 206 | 207 | - name: Install mkl-service 208 | run: | 209 | . $CONDA/etc/profile.d/conda.sh 210 | CHANNELS="-c $GITHUB_WORKSPACE/channel ${{ env.CHANNELS }}" 211 | export PACKAGE_VERSION=$(python -c "${VER_SCRIPT1} ${VER_SCRIPT2}") 212 | conda create -n ${{ env.TEST_ENV_NAME }} $PACKAGE_NAME=${PACKAGE_VERSION} pytest python=${{ matrix.python }} $CHANNELS 213 | # Test installed packages 214 | conda list 215 | 216 | - name: Run tests 217 | run: | 218 | . $CONDA/etc/profile.d/conda.sh 219 | conda activate ${{ env.TEST_ENV_NAME }} 220 | pytest -vv --pyargs ${{ env.MODULE_NAME }} 221 | 222 | test_windows: 223 | needs: build_windows 224 | runs-on: ${{ matrix.runner }} 225 | 226 | strategy: 227 | matrix: 228 | python: ['3.10', '3.11', '3.12', '3.13', '3.14'] 229 | experimental: [false] 230 | runner: [windows-latest] 231 | continue-on-error: ${{ matrix.experimental }} 232 | env: 233 | CHANNELS: -c conda-forge -c conda-forge/label/python_rc -c https://software.repos.intel.com/python/conda --override-channels 234 | 235 | steps: 236 | - name: Download artifact 237 | uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 238 | with: 239 | name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python }} 240 | - uses: conda-incubator/setup-miniconda@835234971496cad1653abb28a638a281cf32541f # v3.2.0 241 | with: 242 | miniforge-version: latest 243 | use-mamba: 'true' 244 | conda-remove-defaults: 'true' 245 | activate-environment: 'test' 246 | python-version: '3.13' # no python 3.14 support by conda-index 247 | 248 | - name: Install conda-index 249 | run: conda install conda-index 250 | 251 | - name: Create conda channel 252 | run: | 253 | mkdir ${{ env.GITHUB_WORKSPACE }}\channel\win-64 254 | move ${{ env.PACKAGE_NAME }}-*.conda ${{ env.GITHUB_WORKSPACE }}\channel\win-64 255 | python -m conda_index ${{ env.GITHUB_WORKSPACE }}/channel 256 | 257 | # Test channel 258 | conda search ${{ env.PACKAGE_NAME }} -c ${{ env.GITHUB_WORKSPACE }}/channel --override-channels --info --json > ${{ env.GITHUB_WORKSPACE }}\ver.json 259 | more ${{ env.GITHUB_WORKSPACE }}\ver.json 260 | 261 | - name: Collect dependencies 262 | shell: cmd 263 | run: | 264 | @ECHO ON 265 | copy /Y ${{ env.GITHUB_WORKSPACE }}\ver.json . 266 | set "SCRIPT=%VER_SCRIPT1% %VER_SCRIPT2%" 267 | FOR /F "tokens=* USEBACKQ" %%F IN (`python -c "%SCRIPT%"`) DO ( 268 | SET PACKAGE_VERSION=%%F 269 | ) 270 | conda create -n ${{ env.TEST_ENV_NAME }} ${{ env.PACKAGE_NAME }}=%PACKAGE_VERSION% python=${{ matrix.python }} -c ${{ env.GITHUB_WORKSPACE }}/channel ${{ env.CHANNELS }} --only-deps --dry-run > lockfile 271 | more lockfile 272 | 273 | - name: Cache conda packages 274 | uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 275 | env: 276 | CACHE_NUMBER: 3 # Increase to reset cache 277 | with: 278 | path: /home/runner/conda_pkgs_dir 279 | key: 280 | ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}-${{hashFiles('lockfile') }} 281 | restore-keys: | 282 | ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}- 283 | ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}- 284 | 285 | # add intel-openmp as an explicit dependency 286 | # to avoid it being missed when package version is specified exactly 287 | - name: Install mkl-service 288 | shell: cmd 289 | run: | 290 | @ECHO ON 291 | copy /Y ${{ env.GITHUB_WORKSPACE }}\ver.json . 292 | set "SCRIPT=%VER_SCRIPT1% %VER_SCRIPT2%" 293 | FOR /F "tokens=* USEBACKQ" %%F IN (`python -c "%SCRIPT%"`) DO ( 294 | SET PACKAGE_VERSION=%%F 295 | ) 296 | SET "WORKAROUND_DEPENDENCIES=intel-openmp" 297 | conda create -n ${{ env.TEST_ENV_NAME }} ${{ env.PACKAGE_NAME }}=%PACKAGE_VERSION% %WORKAROUND_DEPENDENCIES% pytest python=${{ matrix.python }} -c ${{ env.GITHUB_WORKSPACE }}/channel ${{ env.CHANNELS }} 298 | # Test installed packages 299 | conda list 300 | 301 | - name: Run tests 302 | run: | 303 | conda activate -n ${{ env.TEST_ENV_NAME }} 304 | pytest -v --pyargs ${{ env.MODULE_NAME }} 305 | -------------------------------------------------------------------------------- /mkl/_mkl_service.pyx: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018, Intel Corporation 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions are met: 5 | # 6 | # * Redistributions of source code must retain the above copyright notice, 7 | # this list of conditions and the following disclaimer. 8 | # * Redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution. 11 | # * Neither the name of Intel Corporation nor the names of its contributors 12 | # may be used to endorse or promote products derived from this software 13 | # without specific prior written permission. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 19 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | # distutils: language = c 27 | # cython: language_level=3 28 | 29 | import numbers 30 | import warnings 31 | cimport mkl._mkl_service as mkl 32 | 33 | 34 | cdef extern from *: 35 | """ 36 | /* define MKL_BLACS_MPICH2 if undefined */ 37 | #ifndef MKL_BLACS_MPICH2 38 | #define MKL_BLACS_MPICH2 -1 39 | #endif 40 | """ 41 | 42 | ctypedef struct MemStatData: 43 | # DataAllocatedBytes, AllocatedBuffers 44 | mkl.MKL_INT64 allocated_bytes 45 | int allocated_buffers 46 | 47 | 48 | # Version Information 49 | cpdef get_version(): 50 | """ 51 | Returns the Intel(R) MKL version as a dictionary. 52 | """ 53 | return __get_version() 54 | 55 | 56 | cpdef get_version_string(): 57 | """ 58 | Returns the Intel(R) MKL version as a string. 59 | """ 60 | return __get_version_string() 61 | 62 | 63 | # Threading 64 | cpdef set_num_threads(num_threads): 65 | """ 66 | Specifies the number of OpenMP* threads to use. 67 | """ 68 | cdef int c_num_threads = __python_obj_to_int(num_threads, "set_num_threads") 69 | __check_positive_num_threads(c_num_threads, "set_num_threads") 70 | 71 | return __set_num_threads(c_num_threads) 72 | 73 | 74 | cdef int __warn_and_fallback_on_default_domain(domain): 75 | warnings.warn( 76 | f"domain={domain} is expected to be an integer, a string ('blas', " 77 | "'fft', 'vml', 'pardiso', 'all'). Uing domain='all' instead." 78 | ) 79 | return mkl.MKL_DOMAIN_ALL 80 | 81 | 82 | cdef int __domain_to_mkl_domain(domain): 83 | cdef int c_mkl_domain = mkl.MKL_DOMAIN_ALL 84 | _mapping = { 85 | "blas": mkl.MKL_DOMAIN_BLAS, 86 | "fft": mkl.MKL_DOMAIN_FFT, 87 | "vml": mkl.MKL_DOMAIN_VML, 88 | "pardiso": mkl.MKL_DOMAIN_PARDISO, 89 | "all": mkl.MKL_DOMAIN_ALL 90 | } 91 | 92 | if isinstance(domain, numbers.Integral): 93 | c_mkl_domain = domain 94 | elif isinstance(domain, str): 95 | if domain not in _mapping: 96 | c_mkl_domain = __warn_and_fallback_on_default_domain(domain) 97 | else: 98 | c_mkl_domain = _mapping[domain] 99 | else: 100 | c_mkl_domain = __warn_and_fallback_on_default_domain(domain) 101 | 102 | return c_mkl_domain 103 | 104 | 105 | cpdef domain_set_num_threads(num_threads, domain="all"): 106 | """ 107 | Specifies the number of OpenMP* threads for a particular function domain. 108 | """ 109 | cdef c_num_threads = __python_obj_to_int(num_threads, "domain_set_num_threads") 110 | __check_non_negative_num_threads(c_num_threads, "domain_set_num_threads") 111 | 112 | cdef int c_mkl_domain = __domain_to_mkl_domain(domain) 113 | cdef int c_mkl_status = __domain_set_num_threads(c_num_threads, c_mkl_domain) 114 | 115 | return __mkl_status_to_string(c_mkl_status) 116 | 117 | 118 | cpdef set_num_threads_local(num_threads): 119 | """ 120 | Specifies the number of OpenMP* threads for all Intel(R) MKL functions on the 121 | current execution thread. 122 | """ 123 | cdef c_num_threads = 0 124 | if isinstance(num_threads, str): 125 | if num_threads is not "global_num_threads": 126 | raise ValueError( 127 | "The argument of set_num_threads_local is expected " 128 | "to be a non-negative integer or a string 'global_num_threads'" 129 | ) 130 | else: 131 | c_num_threads = __python_obj_to_int(num_threads, "set_num_threads_local") 132 | 133 | __check_non_negative_num_threads(c_num_threads, "set_num_threads_local") 134 | 135 | cdef c_prev_num_threads = __set_num_threads_local(c_num_threads) 136 | if (c_prev_num_threads == 0): 137 | ret_value = "global_num_threads" 138 | else: 139 | ret_value = c_prev_num_threads 140 | 141 | return ret_value 142 | 143 | 144 | cpdef set_dynamic(enable): 145 | """ 146 | Enables Intel(R) MKL to dynamically change the number of OpenMP* threads. 147 | """ 148 | cdef int c_enable = int(enable) 149 | # return the number of threads used 150 | return __set_dynamic(c_enable) 151 | 152 | 153 | cpdef get_max_threads(): 154 | """ 155 | Gets the number of OpenMP* threads targeted for parallelism. 156 | """ 157 | return __get_max_threads() 158 | 159 | 160 | cpdef domain_get_max_threads(domain="all"): 161 | """ 162 | Gets the number of OpenMP* threads targeted for parallelism for a particular 163 | function domain. 164 | """ 165 | cdef int c_mkl_domain = __domain_to_mkl_domain(domain) 166 | return __domain_get_max_threads(c_mkl_domain) 167 | 168 | 169 | cpdef get_dynamic(): 170 | """ 171 | Determines whether Intel(R) MKL is enabled to dynamically change the number 172 | of OpenMP* threads. 173 | """ 174 | return bool(__get_dynamic()) 175 | 176 | 177 | cpdef int set_num_stripes(int num_stripes): 178 | """ 179 | Specifies the number of stripes, or partitions along the leading dimension 180 | of the output matrix, for the parallel ``?gemm`` functions. 181 | 182 | Setting `num_stripes` argument to zero instructs Intel(R) MKL to default 183 | partitioning algorithm. A positive `num_stripes` arguments specifies a hint, 184 | and the library may actually use a smaller numbers. 185 | 186 | Returns the number of stripes the library uses, or a zero. 187 | """ 188 | if num_stripes < 0: 189 | raise ValueError( 190 | "Expected non-negative number of stripes" 191 | ", got {}".format(num_stripes) 192 | ) 193 | mkl.mkl_set_num_stripes(num_stripes) 194 | return mkl.mkl_get_num_stripes() 195 | 196 | 197 | cpdef int get_num_stripes(): 198 | """ 199 | Returns the number of stripes, or partitions along the leading dimension 200 | of the output matrix, for the parallel ``?gemm`` functions. 201 | 202 | Non-positive returned value indicates Intel(R) MKL uses default partitioning 203 | algorithm. 204 | 205 | Positive returned value is a hint, and the library may actually use a 206 | smaller number. 207 | """ 208 | return mkl.mkl_get_num_stripes() 209 | 210 | 211 | # Timing 212 | cpdef second(): 213 | """ 214 | Returns elapsed time in seconds. 215 | Use to estimate real time between two calls to this function. 216 | https://www.intel.com/content/www/us/en/developer/overview.html 217 | """ 218 | return __second() 219 | 220 | 221 | cpdef dsecnd(): 222 | """ 223 | Returns elapsed time in seconds. 224 | Use to estimate real time between two calls to this function. 225 | https://www.intel.com/content/www/us/en/developer/overview.html 226 | """ 227 | return __dsecnd() 228 | 229 | 230 | cpdef get_cpu_clocks(): 231 | """ 232 | Returns elapsed CPU clocks. 233 | https://www.intel.com/content/www/us/en/developer/overview.html 234 | """ 235 | return __get_cpu_clocks() 236 | 237 | 238 | cpdef get_cpu_frequency(): 239 | """ 240 | Returns the current CPU frequency value in GHz. 241 | https://www.intel.com/content/www/us/en/developer/overview.html 242 | """ 243 | return __get_cpu_frequency() 244 | 245 | 246 | cpdef get_max_cpu_frequency(): 247 | """ 248 | Returns the maximum CPU frequency value in GHz. 249 | """ 250 | return __get_max_cpu_frequency() 251 | 252 | 253 | cpdef get_clocks_frequency(): 254 | """ 255 | Returns the frequency value in GHz based on constant-rate Time Stamp Counter. 256 | 257 | """ 258 | return __get_clocks_frequency() 259 | 260 | 261 | # Memory Management. See the Intel(R) MKL Developer Guide for more memory usage 262 | # information. 263 | cpdef free_buffers(): 264 | """ 265 | Frees unused memory allocated by the Intel(R) MKL Memory Allocator. 266 | """ 267 | __free_buffers() 268 | 269 | 270 | cpdef thread_free_buffers(): 271 | """ 272 | Frees unused memory allocated by the Intel(R) MKL Memory Allocator in the current 273 | thread. 274 | """ 275 | __thread_free_buffers() 276 | 277 | 278 | cpdef disable_fast_mm(): 279 | """ 280 | Turns off the Intel(R) MKL Memory Allocator for Intel(R) MKL functions to directly 281 | use the system malloc/free functions. 282 | """ 283 | return __disable_fast_mm() 284 | 285 | 286 | cpdef mem_stat(): 287 | """ 288 | Reports the status of the Intel(R) MKL Memory Allocator. 289 | """ 290 | return __mem_stat() 291 | 292 | 293 | cpdef peak_mem_usage(mem_const): 294 | """ 295 | Reports the peak memory allocated by the Intel(R) MKL Memory Allocator. 296 | """ 297 | return __peak_mem_usage(mem_const) 298 | 299 | 300 | cpdef set_memory_limit(limit): 301 | """ 302 | On Linux, sets the limit of memory that Intel(R) MKL can allocate for a specified 303 | type of memory. 304 | """ 305 | return __set_memory_limit(limit) 306 | 307 | 308 | # Conditional Numerical Reproducibility 309 | cpdef cbwr_set(branch=None): 310 | """ 311 | Configures the CNR mode of Intel(R) MKL. 312 | """ 313 | return __cbwr_set(branch) 314 | 315 | 316 | cpdef cbwr_get(cnr_const="all"): 317 | """ 318 | Returns the current CNR settings. 319 | """ 320 | return __cbwr_get(cnr_const) 321 | 322 | 323 | cpdef cbwr_get_auto_branch(): 324 | """ 325 | Automatically detects the CNR code branch for your platform. 326 | """ 327 | return __cbwr_get_auto_branch() 328 | 329 | 330 | # Miscellaneous 331 | cpdef enable_instructions(isa=None): 332 | """ 333 | Enables dispatching for new Intel architectures or restricts the set of Intel 334 | instruction sets available for dispatching. 335 | """ 336 | return __enable_instructions(isa) 337 | 338 | 339 | cpdef set_env_mode(): 340 | """ 341 | Sets up the mode that ignores environment settings specific to Intel(R) MKL. 342 | See mkl_set_env_mode(1). 343 | """ 344 | return __set_env_mode() 345 | 346 | 347 | cpdef get_env_mode(): 348 | """ 349 | Query the current environment mode. See mkl_set_env_mode(0). 350 | """ 351 | return __get_env_mode() 352 | 353 | 354 | cpdef verbose(enable): 355 | """ 356 | Enables or disables Intel(R) MKL Verbose mode. 357 | """ 358 | cdef int c_enable = int(enable) 359 | return bool(__verbose(c_enable)) 360 | 361 | 362 | cpdef set_mpi(vendor, custom_library_name=None): 363 | """ 364 | Sets the implementation of the message-passing interface to be used by Intel(R) MKL. 365 | """ 366 | return __set_mpi(vendor, custom_library_name) 367 | 368 | 369 | # VM Service Functions 370 | cpdef vml_set_mode(accuracy, ftzdaz, errmode): 371 | """ 372 | Sets a new mode for VM functions according to the mode parameter and stores the 373 | previous VM mode to oldmode. 374 | """ 375 | return __vml_set_mode(accuracy, ftzdaz, errmode) 376 | 377 | 378 | cpdef vml_get_mode(): 379 | """ 380 | Gets the VM mode. 381 | """ 382 | return __vml_get_mode() 383 | 384 | 385 | cpdef vml_set_err_status(status): 386 | """ 387 | Sets the new VM Error Status according to err and stores the previous VM Error 388 | Status to olderr. 389 | """ 390 | return __vml_set_err_status(status) 391 | 392 | 393 | cpdef vml_get_err_status(): 394 | """ 395 | Gets the VM Error Status. 396 | """ 397 | return __vml_get_err_status() 398 | 399 | 400 | cpdef vml_clear_err_status(): 401 | """ 402 | Sets the VM Error Status to VML_STATUS_OK and stores the previous VM Error Status 403 | to olderr. 404 | """ 405 | return __vml_clear_err_status() 406 | 407 | 408 | cdef str __mkl_status_to_string(int mkl_status) noexcept: 409 | if mkl_status == 1: 410 | return "success" 411 | else: 412 | return "error" 413 | 414 | 415 | cdef int __python_obj_to_int(obj, func_name) except *: 416 | if not isinstance(obj, numbers.Integral): 417 | raise ValueError( 418 | "The argument of " + func_name + " is expected to be a positive " 419 | "integer" 420 | ) 421 | cdef int c_int = obj 422 | return c_int 423 | 424 | 425 | cdef void __check_positive_num_threads(int p, func_name) except *: 426 | if p <= 0: 427 | warnings.warn("Non-positive argument of " + func_name + 428 | " is being ignored, number of threads will not be changed") 429 | 430 | 431 | cdef void __check_non_negative_num_threads(int p, func_name) except *: 432 | if p < 0: 433 | warnings.warn("Negative argument of " + func_name + 434 | " is being ignored, number of threads will not be changed") 435 | 436 | 437 | cdef inline int __mkl_str_to_int(variable, possible_variables_dict) except *: 438 | if variable is None: 439 | raise ValueError("Variable can not be None") 440 | if possible_variables_dict is None: 441 | raise RuntimeError( 442 | "Dictionary mapping possible variable value to internal code is " 443 | "missing" 444 | ) 445 | if variable not in possible_variables_dict: 446 | raise ValueError("Variable: <" + str(variable) + "> not in " + 447 | str(possible_variables_dict.keys())) 448 | 449 | return possible_variables_dict[variable] 450 | 451 | 452 | cdef __mkl_int_to_str(int mkl_int_variable, possible_variables_dict) except *: 453 | if possible_variables_dict is None: 454 | raise RuntimeError( 455 | "Dictionary mapping possible internal code to output string is " 456 | "missing" 457 | ) 458 | 459 | if mkl_int_variable not in possible_variables_dict: 460 | raise ValueError("Variable: <" + str(mkl_int_variable) + "> not in " + 461 | str(possible_variables_dict.keys())) 462 | 463 | return possible_variables_dict[mkl_int_variable] 464 | 465 | 466 | # Version Information 467 | cdef mkl.MKLVersion __get_version() noexcept: 468 | """ 469 | Returns the Intel(R) MKL version. 470 | """ 471 | cdef mkl.MKLVersion c_mkl_version 472 | mkl.mkl_get_version(&c_mkl_version) 473 | return c_mkl_version 474 | 475 | 476 | cdef str __get_version_string() except *: 477 | """ 478 | Returns the Intel(R) MKL version in a character string. 479 | """ 480 | cdef int c_string_len = 198 481 | cdef char[198] c_string 482 | mkl.mkl_get_version_string(c_string, c_string_len) 483 | return c_string.decode() 484 | 485 | 486 | # Threading 487 | cdef inline int __set_num_threads(int num_threads) noexcept: 488 | """ 489 | Specifies the number of OpenMP* threads to use. 490 | """ 491 | 492 | cdef int prev_num_threads = __get_max_threads() 493 | mkl.mkl_set_num_threads(num_threads) 494 | return prev_num_threads 495 | 496 | 497 | cdef inline int __domain_set_num_threads(int c_num_threads, int mkl_domain) noexcept: 498 | """ 499 | Specifies the number of OpenMP* threads for a particular function domain. 500 | """ 501 | cdef int mkl_status = mkl.mkl_domain_set_num_threads(c_num_threads, mkl_domain) 502 | return mkl_status 503 | 504 | 505 | cdef inline int __set_num_threads_local(int c_num_threads) noexcept: 506 | """ 507 | Specifies the number of OpenMP* threads for all Intel(R) MKL functions on the 508 | current execution thread. 509 | """ 510 | 511 | cdef int c_mkl_status = mkl.mkl_set_num_threads_local(c_num_threads) 512 | return c_mkl_status 513 | 514 | 515 | cdef inline int __set_dynamic(int c_enable) noexcept: 516 | """ 517 | Enables Intel(R) MKL to dynamically change the number of OpenMP* threads. 518 | """ 519 | 520 | mkl.mkl_set_dynamic(c_enable) 521 | return __get_max_threads() 522 | 523 | 524 | cdef inline int __get_max_threads() noexcept: 525 | """ 526 | Gets the number of OpenMP* threads targeted for parallelism. 527 | """ 528 | return mkl.mkl_get_max_threads() 529 | 530 | 531 | cdef inline int __domain_get_max_threads(int c_mkl_domain) noexcept: 532 | """ 533 | Gets the number of OpenMP* threads targeted for parallelism for a particular 534 | function domain. 535 | """ 536 | cdef int c_num_threads = mkl.mkl_domain_get_max_threads(c_mkl_domain) 537 | 538 | return c_num_threads 539 | 540 | 541 | cdef inline int __get_dynamic() noexcept: 542 | """ 543 | Determines whether Intel(R) MKL is enabled to dynamically change the number of 544 | OpenMP* threads. 545 | """ 546 | return mkl.mkl_get_dynamic() 547 | 548 | 549 | # Timing 550 | cdef inline float __second() noexcept: 551 | """ 552 | Returns elapsed time in seconds. 553 | Use to estimate real time between two calls to this function. 554 | https://www.intel.com/content/www/us/en/developer/overview.html 555 | """ 556 | return mkl.second() 557 | 558 | 559 | cdef inline double __dsecnd() noexcept: 560 | """ 561 | Returns elapsed time in seconds. 562 | Use to estimate real time between two calls to this function. 563 | https://www.intel.com/content/www/us/en/developer/overview.html 564 | """ 565 | return mkl.dsecnd() 566 | 567 | 568 | cdef inline mkl.MKL_UINT64 __get_cpu_clocks() noexcept: 569 | """ 570 | Returns elapsed CPU clocks. 571 | """ 572 | cdef mkl.MKL_UINT64 clocks 573 | mkl.mkl_get_cpu_clocks(&clocks) 574 | return clocks 575 | 576 | 577 | cdef inline double __get_cpu_frequency() noexcept: 578 | """ 579 | Returns the current CPU frequency value in GHz. 580 | """ 581 | return mkl.mkl_get_cpu_frequency() 582 | 583 | 584 | cdef inline double __get_max_cpu_frequency() noexcept: 585 | """ 586 | Returns the maximum CPU frequency value in GHz. 587 | """ 588 | return mkl.mkl_get_max_cpu_frequency() 589 | 590 | 591 | cdef inline double __get_clocks_frequency() noexcept: 592 | """ 593 | Returns the frequency value in GHz based on constant-rate Time Stamp Counter. 594 | """ 595 | return mkl.mkl_get_clocks_frequency() 596 | 597 | 598 | # Memory Management. See the Intel(R) MKL Developer Guide for more memory usage 599 | # information. 600 | cdef inline void __free_buffers() noexcept: 601 | """ 602 | Frees unused memory allocated by the Intel(R) MKL Memory Allocator. 603 | """ 604 | mkl.mkl_free_buffers() 605 | return 606 | 607 | 608 | cdef inline void __thread_free_buffers() noexcept: 609 | """ 610 | Frees unused memory allocated by the Intel(R) MKL Memory Allocator in the current 611 | thread. 612 | """ 613 | mkl.mkl_thread_free_buffers() 614 | return 615 | 616 | 617 | cdef inline int __disable_fast_mm() noexcept: 618 | """ 619 | Turns off the Intel(R) MKL Memory Allocator for Intel(R) MKL functions to directly 620 | use the system malloc/free functions. 621 | """ 622 | return mkl.mkl_disable_fast_mm() 623 | 624 | 625 | cdef inline MemStatData __mem_stat() noexcept: 626 | """ 627 | Reports the status of the Intel(R) MKL Memory Allocator. 628 | """ 629 | cdef MemStatData mem_stat_data 630 | mem_stat_data.allocated_bytes = mkl.mkl_mem_stat(&mem_stat_data.allocated_buffers) 631 | return mem_stat_data 632 | 633 | 634 | cdef object __peak_mem_usage(mem_const) except *: 635 | """ 636 | Reports the peak memory allocated by the Intel(R) MKL Memory Allocator. 637 | """ 638 | __variables = { 639 | "input": { 640 | "enable": mkl.MKL_PEAK_MEM_ENABLE, 641 | "disable": mkl.MKL_PEAK_MEM_DISABLE, 642 | "peak_mem": mkl.MKL_PEAK_MEM, 643 | "peak_mem_reset": mkl.MKL_PEAK_MEM_RESET, 644 | } 645 | } 646 | cdef int c_mkl_mem_const = __mkl_str_to_int(mem_const, __variables["input"]) 647 | 648 | cdef mkl.MKL_INT64 c_memory_allocator = mkl.mkl_peak_mem_usage(c_mkl_mem_const) 649 | 650 | if c_memory_allocator == -1: 651 | memory_allocator = "error" 652 | else: 653 | memory_allocator = c_memory_allocator 654 | return memory_allocator 655 | 656 | 657 | cdef inline object __set_memory_limit(limit) except *: 658 | """ 659 | On Linux, sets the limit of memory that Intel(R) MKL can allocate for a specified 660 | type of memory. 661 | """ 662 | cdef size_t c_limit = limit 663 | 664 | cdef int c_mkl_status = mkl.mkl_set_memory_limit(mkl.MKL_MEM_MCDRAM, c_limit) 665 | return __mkl_status_to_string(c_mkl_status) 666 | 667 | 668 | # Conditional Numerical Reproducibility 669 | cdef object __cbwr_set(branch=None) except *: 670 | """ 671 | Configures the CNR mode of Intel(R) MKL. 672 | """ 673 | __variables = { 674 | "input": { 675 | "off": mkl.MKL_CBWR_OFF, 676 | "branch_off": mkl.MKL_CBWR_BRANCH_OFF, 677 | "auto": mkl.MKL_CBWR_AUTO, 678 | "compatible": mkl.MKL_CBWR_COMPATIBLE, 679 | "sse2": mkl.MKL_CBWR_SSE2, 680 | "ssse3": mkl.MKL_CBWR_SSSE3, 681 | "sse4_1": mkl.MKL_CBWR_SSE4_1, 682 | "sse4_2": mkl.MKL_CBWR_SSE4_2, 683 | "avx": mkl.MKL_CBWR_AVX, 684 | "avx2": mkl.MKL_CBWR_AVX2, 685 | "avx2,strict": mkl.MKL_CBWR_AVX2 | mkl.MKL_CBWR_STRICT, 686 | "avx512_mic": mkl.MKL_CBWR_AVX512_MIC, 687 | "avx512_mic,strict": mkl.MKL_CBWR_AVX512_MIC | mkl.MKL_CBWR_STRICT, 688 | "avx512": mkl.MKL_CBWR_AVX512, 689 | "avx512,strict": mkl.MKL_CBWR_AVX512 | mkl.MKL_CBWR_STRICT, 690 | "avx512_mic_e1": mkl.MKL_CBWR_AVX512_MIC_E1, 691 | "avx512_e1": mkl.MKL_CBWR_AVX512_E1, 692 | "avx512_e1,strict": mkl.MKL_CBWR_AVX512_E1 | mkl.MKL_CBWR_STRICT, 693 | }, 694 | "output": { 695 | mkl.MKL_CBWR_SUCCESS: "success", 696 | mkl.MKL_CBWR_ERR_INVALID_INPUT: "err_invalid_input", 697 | mkl.MKL_CBWR_ERR_UNSUPPORTED_BRANCH: "err_unsupported_branch", 698 | mkl.MKL_CBWR_ERR_MODE_CHANGE_FAILURE: "err_mode_change_failure", 699 | }, 700 | } 701 | mkl_branch = __mkl_str_to_int(branch, __variables["input"]) 702 | 703 | mkl_status = mkl.mkl_cbwr_set(mkl_branch) 704 | 705 | status = __mkl_int_to_str(mkl_status, __variables["output"]) 706 | return status 707 | 708 | 709 | cdef inline __cbwr_get(cnr_const=None) except *: 710 | """ 711 | Returns the current CNR settings. 712 | """ 713 | __variables = { 714 | "input": { 715 | "branch": mkl.MKL_CBWR_BRANCH, 716 | "all": mkl.MKL_CBWR_ALL, 717 | }, 718 | "output": { 719 | mkl.MKL_CBWR_BRANCH_OFF: "branch_off", 720 | mkl.MKL_CBWR_AUTO: "auto", 721 | mkl.MKL_CBWR_COMPATIBLE: "compatible", 722 | mkl.MKL_CBWR_SSE2: "sse2", 723 | mkl.MKL_CBWR_SSSE3: "ssse3", 724 | mkl.MKL_CBWR_SSE4_1: "sse4_1", 725 | mkl.MKL_CBWR_SSE4_2: "sse4_2", 726 | mkl.MKL_CBWR_AVX: "avx", 727 | mkl.MKL_CBWR_AVX2: "avx2", 728 | mkl.MKL_CBWR_AVX2 | mkl.MKL_CBWR_STRICT: "avx2,strict", 729 | mkl.MKL_CBWR_AVX512_MIC: "avx512_mic", 730 | mkl.MKL_CBWR_AVX512_MIC | mkl.MKL_CBWR_STRICT: "avx512_mic,strict", 731 | mkl.MKL_CBWR_AVX512: "avx512", 732 | mkl.MKL_CBWR_AVX512 | mkl.MKL_CBWR_STRICT: "avx512,strict", 733 | mkl.MKL_CBWR_AVX512_MIC_E1: "avx512_mic_e1", 734 | mkl.MKL_CBWR_AVX512_E1: "avx512_e1", 735 | mkl.MKL_CBWR_AVX512_E1 | mkl.MKL_CBWR_STRICT: "avx512_e1,strict", 736 | mkl.MKL_CBWR_ERR_INVALID_INPUT: "err_invalid_input", 737 | }, 738 | } 739 | mkl_cnr_const = __mkl_str_to_int(cnr_const, __variables["input"]) 740 | 741 | mkl_status = mkl.mkl_cbwr_get(mkl_cnr_const) 742 | 743 | status = __mkl_int_to_str(mkl_status, __variables["output"]) 744 | return status 745 | 746 | 747 | cdef object __cbwr_get_auto_branch() except *: 748 | """ 749 | Automatically detects the CNR code branch for your platform. 750 | """ 751 | __variables = { 752 | "output": { 753 | mkl.MKL_CBWR_BRANCH_OFF: "branch_off", 754 | mkl.MKL_CBWR_AUTO: "auto", 755 | mkl.MKL_CBWR_COMPATIBLE: "compatible", 756 | mkl.MKL_CBWR_SSE2: "sse2", 757 | mkl.MKL_CBWR_SSSE3: "ssse3", 758 | mkl.MKL_CBWR_SSE4_1: "sse4_1", 759 | mkl.MKL_CBWR_SSE4_2: "sse4_2", 760 | mkl.MKL_CBWR_AVX: "avx", 761 | mkl.MKL_CBWR_AVX2: "avx2", 762 | mkl.MKL_CBWR_AVX2 | mkl.MKL_CBWR_STRICT: "avx2,strict", 763 | mkl.MKL_CBWR_AVX512_MIC: "avx512_mic", 764 | mkl.MKL_CBWR_AVX512_MIC | mkl.MKL_CBWR_STRICT: "avx512_mic,strict", 765 | mkl.MKL_CBWR_AVX512: "avx512", 766 | mkl.MKL_CBWR_AVX512 | mkl.MKL_CBWR_STRICT: "avx512,strict", 767 | mkl.MKL_CBWR_AVX512_MIC_E1: "avx512_mic_e1", 768 | mkl.MKL_CBWR_AVX512_E1: "avx512_e1", 769 | mkl.MKL_CBWR_AVX512_E1 | mkl.MKL_CBWR_STRICT: "avx512_e1,strict", 770 | mkl.MKL_CBWR_SUCCESS: "success", 771 | mkl.MKL_CBWR_ERR_INVALID_INPUT: "err_invalid_input", 772 | }, 773 | } 774 | 775 | mkl_status = mkl.mkl_cbwr_get_auto_branch() 776 | 777 | status = __mkl_int_to_str(mkl_status, __variables["output"]) 778 | return status 779 | 780 | 781 | # Miscellaneous 782 | cdef object __enable_instructions(isa=None) except *: 783 | """ 784 | Enables dispatching for new Intel architectures or restricts the set of Intel 785 | instruction sets available for dispatching. 786 | """ 787 | __variables = { 788 | "input": { 789 | "single_path": mkl.MKL_SINGLE_PATH_ENABLE, 790 | "avx512_e4": mkl.MKL_ENABLE_AVX512_E4, 791 | "avx512_e3": mkl.MKL_ENABLE_AVX512_E3, 792 | "avx512_e2": mkl.MKL_ENABLE_AVX512_E2, 793 | "avx512_e1": mkl.MKL_ENABLE_AVX512_E1, 794 | "avx512_mic_e1": mkl.MKL_ENABLE_AVX512_MIC_E1, 795 | "avx512": mkl.MKL_ENABLE_AVX512, 796 | "avx512_mic": mkl.MKL_ENABLE_AVX512_MIC, 797 | "avx2_e1": mkl.MKL_ENABLE_AVX2_E1, 798 | "avx2": mkl.MKL_ENABLE_AVX2, 799 | "avx": mkl.MKL_ENABLE_AVX, 800 | "sse4_2": mkl.MKL_ENABLE_SSE4_2, 801 | }, 802 | } 803 | cdef int c_mkl_isa = __mkl_str_to_int(isa, __variables["input"]) 804 | 805 | cdef int c_mkl_status = mkl.mkl_enable_instructions(c_mkl_isa) 806 | 807 | return __mkl_status_to_string(c_mkl_status) 808 | 809 | 810 | cdef object __set_env_mode() except *: 811 | """ 812 | Sets up the mode that ignores environment settings specific to Intel(R) MKL. 813 | See mkl_set_env_mode(1). 814 | """ 815 | __variables = { 816 | "input": None, 817 | "output": { 818 | 0: "default", 819 | 1: "ignore", 820 | }, 821 | } 822 | cdef int c_mkl_status = mkl.mkl_set_env_mode(1) 823 | 824 | status = __mkl_int_to_str(c_mkl_status, __variables["output"]) 825 | return status 826 | 827 | 828 | cdef object __get_env_mode() except *: 829 | """ 830 | Query the current environment mode. See mkl_set_env_mode(0). 831 | """ 832 | __variables = { 833 | "output": { 834 | 0: "default", 835 | 1: "ignore", 836 | }, 837 | } 838 | cdef int c_mkl_status = mkl.mkl_set_env_mode(0) 839 | 840 | status = __mkl_int_to_str(c_mkl_status, __variables["output"]) 841 | return status 842 | 843 | 844 | cdef inline int __verbose(int c_enable) noexcept: 845 | """ 846 | Enables or disables Intel(R) MKL Verbose mode. 847 | """ 848 | return mkl.mkl_verbose(c_enable) 849 | 850 | 851 | cdef __set_mpi(vendor, custom_library_name=None) except *: 852 | """ 853 | Sets the implementation of the message-passing interface to be used by Intel(R) MKL. 854 | """ 855 | __variables = { 856 | "input": { 857 | "custom": mkl.MKL_BLACS_CUSTOM, 858 | "msmpi": mkl.MKL_BLACS_MSMPI, 859 | "intelmpi": mkl.MKL_BLACS_INTELMPI, 860 | }, 861 | "output": { 862 | 0: "success", 863 | -1: "vendor_invalid", 864 | -2: "custom_library_name_invalid", 865 | -3: "MPI library cannot be set at this point", 866 | }, 867 | } 868 | if mkl.MKL_BLACS_LASTMPI > mkl.MKL_BLACS_INTELMPI + 1: 869 | __variables["input"]["mpich2"] = mkl.MKL_BLACS_MPICH2 870 | if ( 871 | (vendor is "custom" or custom_library_name is not None) 872 | and (vendor is not "custom" or custom_library_name is None) 873 | ): 874 | raise ValueError("Selecting custom MPI for BLACS requires specifying " 875 | "the custom library, and specifying custom library " 876 | "necessitates selecting a custom MPI for BLACS library") 877 | mkl_vendor = __mkl_str_to_int(vendor, __variables["input"]) 878 | 879 | cdef bytes c_bytes 880 | cdef char* c_string = "" 881 | if custom_library_name is not None: 882 | c_bytes = custom_library_name.encode() 883 | c_string = c_bytes 884 | mkl_status = mkl.mkl_set_mpi(mkl_vendor, c_string) 885 | 886 | status = __mkl_int_to_str(mkl_status, __variables["output"]) 887 | return status 888 | 889 | 890 | # VM Service Functions 891 | cdef object __vml_set_mode(accuracy, ftzdaz, errmode) except *: 892 | """ 893 | Sets a new mode for VM functions according to the mode parameter and stores the 894 | previous VM mode to oldmode. 895 | """ 896 | __variables = { 897 | "input": { 898 | "accuracy": { 899 | "ha": mkl.VML_HA, 900 | "la": mkl.VML_LA, 901 | "ep": mkl.VML_EP, 902 | }, 903 | "ftzdaz": { 904 | "on": mkl.VML_FTZDAZ_ON, 905 | "off": mkl.VML_FTZDAZ_OFF, 906 | "default": 0, 907 | }, 908 | "errmode": { 909 | "ignore": mkl.VML_ERRMODE_IGNORE, 910 | "errno": mkl.VML_ERRMODE_ERRNO, 911 | "stderr": mkl.VML_ERRMODE_STDERR, 912 | "except": mkl.VML_ERRMODE_EXCEPT, 913 | "callback": mkl.VML_ERRMODE_CALLBACK, 914 | "default": mkl.VML_ERRMODE_DEFAULT, 915 | }, 916 | }, 917 | "output": { 918 | "accuracy": { 919 | mkl.VML_HA: "ha", 920 | mkl.VML_LA: "la", 921 | mkl.VML_EP: "ep", 922 | }, 923 | "ftzdaz": { 924 | mkl.VML_FTZDAZ_ON: "on", 925 | mkl.VML_FTZDAZ_OFF: "off", 926 | 0: "default", 927 | }, 928 | "errmode": { 929 | mkl.VML_ERRMODE_IGNORE: "ignore", 930 | mkl.VML_ERRMODE_ERRNO: "errno", 931 | mkl.VML_ERRMODE_STDERR: "stderr", 932 | mkl.VML_ERRMODE_EXCEPT: "except", 933 | mkl.VML_ERRMODE_CALLBACK: "callback", 934 | mkl.VML_ERRMODE_DEFAULT: "default", 935 | }, 936 | }, 937 | } 938 | cdef int c_mkl_accuracy = __mkl_str_to_int( 939 | accuracy, __variables["input"]["accuracy"] 940 | ) 941 | cdef int c_mkl_ftzdaz = __mkl_str_to_int(ftzdaz, __variables["input"]["ftzdaz"]) 942 | cdef int c_mkl_errmode = __mkl_str_to_int(errmode, __variables["input"]["errmode"]) 943 | 944 | cdef int c_mkl_status = mkl.vmlSetMode( 945 | c_mkl_accuracy | c_mkl_ftzdaz | c_mkl_errmode 946 | ) 947 | 948 | accuracy = __mkl_int_to_str( 949 | c_mkl_status & mkl.VML_ACCURACY_MASK, 950 | __variables["output"]["accuracy"]) 951 | ftzdaz = __mkl_int_to_str( 952 | c_mkl_status & mkl.VML_FTZDAZ_MASK, 953 | __variables["output"]["ftzdaz"]) 954 | errmode = __mkl_int_to_str( 955 | c_mkl_status & mkl.VML_ERRMODE_MASK, 956 | __variables["output"]["errmode"]) 957 | 958 | return (accuracy, ftzdaz, errmode) 959 | 960 | 961 | cdef object __vml_get_mode() except *: 962 | """ 963 | Gets the VM mode. 964 | """ 965 | __variables = { 966 | "output": { 967 | "accuracy": { 968 | mkl.VML_HA: "ha", 969 | mkl.VML_LA: "la", 970 | mkl.VML_EP: "ep", 971 | }, 972 | "ftzdaz": { 973 | mkl.VML_FTZDAZ_ON: "on", 974 | mkl.VML_FTZDAZ_OFF: "off", 975 | 0: "default", 976 | }, 977 | "errmode": { 978 | mkl.VML_ERRMODE_IGNORE: "ignore", 979 | mkl.VML_ERRMODE_ERRNO: "errno", 980 | mkl.VML_ERRMODE_STDERR: "stderr", 981 | mkl.VML_ERRMODE_EXCEPT: "except", 982 | mkl.VML_ERRMODE_CALLBACK: "callback", 983 | mkl.VML_ERRMODE_DEFAULT: "default", 984 | }, 985 | }, 986 | } 987 | 988 | cdef int c_mkl_status = mkl.vmlGetMode() 989 | 990 | accuracy = __mkl_int_to_str( 991 | c_mkl_status & mkl.VML_ACCURACY_MASK, 992 | __variables["output"]["accuracy"]) 993 | ftzdaz = __mkl_int_to_str( 994 | c_mkl_status & mkl.VML_FTZDAZ_MASK, 995 | __variables["output"]["ftzdaz"]) 996 | errmode = __mkl_int_to_str( 997 | c_mkl_status & mkl.VML_ERRMODE_MASK, 998 | __variables["output"]["errmode"]) 999 | return (accuracy, ftzdaz, errmode) 1000 | 1001 | 1002 | __mkl_vml_status = { 1003 | "ok": mkl.VML_STATUS_OK, 1004 | "accuracywarning": mkl.VML_STATUS_ACCURACYWARNING, 1005 | "badsize": mkl.VML_STATUS_BADSIZE, 1006 | "badmem": mkl.VML_STATUS_BADMEM, 1007 | "errdom": mkl.VML_STATUS_ERRDOM, 1008 | "sing": mkl.VML_STATUS_SING, 1009 | "overflow": mkl.VML_STATUS_OVERFLOW, 1010 | "underflow": mkl.VML_STATUS_UNDERFLOW, 1011 | } 1012 | 1013 | 1014 | cdef object __vml_set_err_status(status) except *: 1015 | """ 1016 | Sets the new VM Error Status according to err and stores the previous VM Error 1017 | Status to olderr. 1018 | """ 1019 | __variables = { 1020 | "input": { 1021 | "ok": mkl.VML_STATUS_OK, 1022 | "accuracywarning": mkl.VML_STATUS_ACCURACYWARNING, 1023 | "badsize": mkl.VML_STATUS_BADSIZE, 1024 | "badmem": mkl.VML_STATUS_BADMEM, 1025 | "errdom": mkl.VML_STATUS_ERRDOM, 1026 | "sing": mkl.VML_STATUS_SING, 1027 | "overflow": mkl.VML_STATUS_OVERFLOW, 1028 | "underflow": mkl.VML_STATUS_UNDERFLOW, 1029 | }, 1030 | "output": { 1031 | mkl.VML_STATUS_OK: "ok", 1032 | mkl.VML_STATUS_ACCURACYWARNING: "accuracywarning", 1033 | mkl.VML_STATUS_BADSIZE: "badsize", 1034 | mkl.VML_STATUS_BADMEM: "badmem", 1035 | mkl.VML_STATUS_ERRDOM: "errdom", 1036 | mkl.VML_STATUS_SING: "sing", 1037 | mkl.VML_STATUS_OVERFLOW: "overflow", 1038 | mkl.VML_STATUS_UNDERFLOW: "underflow", 1039 | }, 1040 | } 1041 | cdef int mkl_status_in = __mkl_str_to_int(status, __variables["input"]) 1042 | 1043 | cdef int mkl_status_out = mkl.vmlSetErrStatus(mkl_status_in) 1044 | 1045 | status = __mkl_int_to_str(mkl_status_out, __variables["output"]) 1046 | return status 1047 | 1048 | 1049 | cdef object __vml_get_err_status() except *: 1050 | """ 1051 | Gets the VM Error Status. 1052 | """ 1053 | __variables = { 1054 | "input": None, 1055 | "output": { 1056 | mkl.VML_STATUS_OK: "ok", 1057 | mkl.VML_STATUS_ACCURACYWARNING: "accuracywarning", 1058 | mkl.VML_STATUS_BADSIZE: "badsize", 1059 | mkl.VML_STATUS_BADMEM: "badmem", 1060 | mkl.VML_STATUS_ERRDOM: "errdom", 1061 | mkl.VML_STATUS_SING: "sing", 1062 | mkl.VML_STATUS_OVERFLOW: "overflow", 1063 | mkl.VML_STATUS_UNDERFLOW: "underflow", 1064 | }, 1065 | } 1066 | 1067 | cdef int mkl_status = mkl.vmlGetErrStatus() 1068 | 1069 | status = __mkl_int_to_str(mkl_status, __variables["output"]) 1070 | return status 1071 | 1072 | 1073 | cdef object __vml_clear_err_status() except *: 1074 | """ 1075 | Sets the VM Error Status to VML_STATUS_OK and stores the previous VM Error Status 1076 | to olderr. 1077 | """ 1078 | __variables = { 1079 | "input": None, 1080 | "output": { 1081 | mkl.VML_STATUS_OK: "ok", 1082 | mkl.VML_STATUS_ACCURACYWARNING: "accuracywarning", 1083 | mkl.VML_STATUS_BADSIZE: "badsize", 1084 | mkl.VML_STATUS_BADMEM: "badmem", 1085 | mkl.VML_STATUS_ERRDOM: "errdom", 1086 | mkl.VML_STATUS_SING: "sing", 1087 | mkl.VML_STATUS_OVERFLOW: "overflow", 1088 | mkl.VML_STATUS_UNDERFLOW: "underflow", 1089 | }, 1090 | } 1091 | 1092 | cdef int mkl_status = mkl.vmlClearErrStatus() 1093 | 1094 | status = __mkl_int_to_str(mkl_status, __variables["output"]) 1095 | return status 1096 | --------------------------------------------------------------------------------