Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Higher-precedence file overrides; lower must not restate overridden guidance.
## Contribution expectations
- Keep diffs minimal; prefer atomic single-purpose commits.
- Preserve public API signatures in `mkl/__init__.py` unless change is explicitly requested.
- For user-visible behavior changes: update tests in `mkl/tests/test_mkl_service.py`.
- For user-visible behavior changes: update tests in `mkl/tests/test_mkl_service.py`, or `mkl/tests/test_mkl_memory.py` for `MKLMemory`.
- For bug fixes: add or extend regression tests in the same change.
- Do not generate code without corresponding test updates when behavior changes.
- Run `pre-commit run --all-files` when `.pre-commit-config.yaml` is present.
Expand All @@ -37,8 +37,8 @@ Higher-precedence file overrides; lower must not restate overridden guidance.
- Build/config: `pyproject.toml`, `meson.build`
- Recipe/deps: `conda-recipe/meta.yaml`, `conda-recipe/conda_build_config.yaml`
- CI: `.github/workflows/*.{yml,yaml}`
- API contracts: `mkl/__init__.py`, `mkl/_py_mkl_service.pyx`
- Tests: `mkl/tests/test_mkl_service.py`
- API contracts: `mkl/__init__.py`, `mkl/_py_mkl_service.pyx`, `mkl/_mkl_memory.pyx`
- Tests: `mkl/tests/test_mkl_service.py`, `mkl/tests/test_mkl_memory.py`

## MKL-specific constraints
- Linux runtime init path may require `RTLD_GLOBAL` preloading (`mkl/_mklinitmodule.c`).
Expand Down
6 changes: 4 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Entry point for agent context in this repo.
- Threading control (set/get number of threads, domain-specific threading)
- Version information (MKL version, build info)
- Memory management (peak memory usage, memory statistics)
- Aligned memory allocation (`MKLMemory`, a buffer-protocol object backed by `mkl_malloc`)
- Conditional Numerical Reproducibility (CNR)
- Timing functions (get CPU/wall clock time)
- Miscellaneous utilities (MKL_VERBOSE control, etc.)
Expand All @@ -16,6 +17,7 @@ Originally part of Intel® Distribution for Python*, now a standalone package av
## Key components
- **Python interface:** `mkl/__init__.py` — public API surface
- **Cython wrapper:** `mkl/_py_mkl_service.pyx` — wraps MKL support functions
- **Cython allocator:** `mkl/_mkl_memory.pyx` — `MKLMemory`, wraps `mkl_malloc`/`mkl_calloc`/`mkl_realloc`/`mkl_free`
- **C init module:** `mkl/_mklinitmodule.c` — Linux-side MKL runtime preloading / initialization
- **Helper:** `mkl/_init_helper.py` — Windows venv DLL loading helper
- **Build system:** meson-python + Cython
Expand Down Expand Up @@ -74,11 +76,11 @@ mkl.get_version_string() # MKL version info
- **API stability:** Preserve existing function signatures (widely used in ecosystem)
- **Threading:** Changes to threading control must be thread-safe
- **CNR:** Conditional Numerical Reproducibility flags require careful documentation
- **Testing:** Add tests to `mkl/tests/test_mkl_service.py`
- **Testing:** Add tests to `mkl/tests/test_mkl_service.py`, or `mkl/tests/test_mkl_memory.py` for `MKLMemory`
- **Docs:** MKL support functions documented in [Intel oneMKL Developer Reference](https://www.intel.com/content/www/us/en/docs/onemkl/developer-reference-c/2025-2/support-functions.html)

## Code structure
- **Cython layer:** `_py_mkl_service.pyx` + `_mkl_service.pxd` (C declarations)
- **Cython layer:** `_py_mkl_service.pyx` and `_mkl_memory.pyx` + `_mkl_service.pxd` (C declarations)
- **C init:** `_mklinitmodule.c` handles Linux preloading (`dlopen(..., RTLD_GLOBAL)`) for MKL runtime
- **Windows loading helper:** `_init_helper.py` handles DLL path setup in Windows venv
- **Python wrapper:** `__init__.py` imports `_py_mkl_service` (generated from `.pyx`)
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Enabled support of Python 3.15 [gh-243](https://github.com/IntelPython/mkl-service/pull/243)
* Added support for free-threaded (GIL-disabled) CPython builds: the Cython extension is compiled with `freethreading_compatible=True` and `_mklinit` declares `Py_MOD_GIL_NOT_USED`, so importing `mkl` no longer re-enables the GIL [gh-213](https://github.com/IntelPython/mkl-service/pull/213)
* Added support for new build option `ilp64` to initialize MKL with the ILP64 interface, which also resolves some build warnings [gh-184](https://github.com/IntelPython/mkl-service/pull/184)
* Exposed `mkl_malloc` and related MKL calls to Python via `MKLMemory` class which supports the Python buffer protocol [gh-182](https://github.com/IntelPython/mkl-service/pull/182)

### Changed
* Raised the minimum build-time `Cython` requirement to `3.1.0`, the first release providing the `freethreading_compatible` directive [gh-213](https://github.com/IntelPython/mkl-service/pull/213)
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ For more information about the usage of support functions see [Developer Referen
## Building

A C compiler and Intel(R) oneAPI Math Kernel Library (oneMKL) are required to build mkl-service from source.
The compiler must support C11 atomics (i.e., for Windows, Visual Studio 2022 17.5 or newer).

Executing
```sh
Expand Down
33 changes: 31 additions & 2 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ project(
).stdout().strip(),
meson_version: '>=1.8.3',
default_options: [
'c_std=c11',
'buildtype=release',
]
)
Expand All @@ -25,6 +26,20 @@ endif
thread_dep = dependency('threads')

cc = meson.get_compiler('c')

atomics_args = []
if cc.get_id() == 'msvc'
atomics_args += '/experimental:c11atomics'
endif

# checked to fail early if missing header
if not cc.has_header('stdatomic.h', args: atomics_args)
error(
'mkl-service requires a C compiler supporting C11 atomics',
'(i.e., for Windows, Visual Studio 2022 17.5 or newer).'
)
endif

mkl_dep = dependency('MKL', method: 'cmake',
modules: ['MKL::MKL'],
cmake_args: [
Expand Down Expand Up @@ -60,7 +75,7 @@ py.extension_module(
subdir: 'mkl'
)

# Cython extension
# Cython extensions
py.extension_module(
'_py_mkl_service',
sources: ['mkl/_py_mkl_service.pyx'],
Expand All @@ -71,6 +86,17 @@ py.extension_module(
subdir: 'mkl'
)

py.extension_module(
Comment thread
ndgrigorian marked this conversation as resolved.
'_mkl_memory',
sources: ['mkl/_mkl_memory.pyx'],
dependencies: [mkl_dep],
c_args: c_args + atomics_args,
link_args: rpath_link_args,
install: true,
subdir: 'mkl'
)


# Python sources
py.install_sources(
[
Expand All @@ -82,6 +108,9 @@ py.install_sources(
)

py.install_sources(
['mkl/tests/test_mkl_service.py'],
[
'mkl/tests/test_mkl_memory.py',
'mkl/tests/test_mkl_service.py',
],
subdir: 'mkl/tests'
)
11 changes: 11 additions & 0 deletions mkl/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Core Python/Cython implementation: MKL support function wrappers and runtime con
## Structure
- `__init__.py` — public API, RTLD_GLOBAL context manager, module initialization
- `_py_mkl_service.pyx` — Cython wrappers for MKL support functions
- `_mkl_memory.pyx` — `MKLMemory`, a buffer-protocol object over MKL's allocator
- `_mkl_service.pxd` — Cython declarations (C function signatures)
- `_mklinitmodule.c` — C extension for Linux-side MKL runtime preloading/init
- `_init_helper.py` — Windows loading helper (DLL path setup in venv)
Expand All @@ -26,6 +27,13 @@ Core Python/Cython implementation: MKL support function wrappers and runtime con
- `peak_mem_usage(memtype)` — peak memory usage stats
- `mem_stat()` — memory allocation statistics

### Memory allocation
- `MKLMemory(nbytes, alignment=64)` — aligned allocation via `mkl_malloc`
- `MKLMemory(num, elem_size, alignment=64)` — zeroed allocation via `mkl_calloc`
- `MKLMemory(other, alignment=other.alignment)` — copy of another allocation
- `realloc(new_nbytes, refcheck=True)` — resize in place via `mkl_realloc`
- `nbytes` / `__len__`, `alignment`, `tobytes()`, buffer protocol, pickling

### CNR (Conditional Numerical Reproducibility)
- `set_num_threads_local(n)` — thread-local thread count
- CNR mode control functions
Expand All @@ -39,11 +47,14 @@ Core Python/Cython implementation: MKL support function wrappers and runtime con
- **API stability:** Preserve function signatures (widely used in ecosystem)
- **MKL dependency:** Assumes MKL is available at runtime (conda: mkl package). Do **not** list `mkl` in `pyproject.toml` `[project].dependencies` — its PyPI wheel lacks `.dist-info`, which breaks `pip check`; on conda-forge there is no pip-visible `mkl` distribution.
- **RTLD_GLOBAL preload path:** Linux preload is handled in `_mklinitmodule.c`; Windows DLL setup is in `_init_helper.py`
- **`MKLMemory` mutation:** `realloc` moves the underlying block, so it must refuse while a buffer is exported, while another thread is resizing, or (unless `refcheck=False`) while the object looks referenced elsewhere. The GIL must not be released across those checks and the pointer store, mirroring NumPy's `PyArray_Resize`. The reference-count check stays NumPy's: `PyUnstable_Object_IsUniquelyReferenced` from 3.14, `Py_REFCNT > 2` before it, keyed on `PY_VERSION_HEX` and not on `Py_GIL_DISABLED`. It is a check against dangling references, not against other threads — on a free-threaded build before 3.14 it cannot be either, and resizing an allocation another thread can reach is the caller's responsibility, as it is for `numpy.ndarray.resize`.

## Cython details
- `_py_mkl_service.pyx` → generates `_py_mkl_service` extension module
- `_mkl_memory.pyx` → generates `_mkl_memory` extension module
- `.pxd` file declares external C functions from MKL headers
- Cython build requires MKL headers (`mkl-devel`)
- `_mkl_memory.pyx` uses C11 atomics (`<stdatomic.h>`); `meson.build` scopes MSVC's `/experimental:c11atomics` to that one target

## C init module
- `_mklinitmodule.c` → `_mklinit` extension
Expand Down
2 changes: 2 additions & 0 deletions mkl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ def __exit__(self, *args):

del RTLD_for_MKL

from ._mkl_memory import MKLMemory
from ._py_mkl_service import (
cbwr_get,
cbwr_get_auto_branch,
Expand Down Expand Up @@ -121,6 +122,7 @@ def __exit__(self, *args):
"mem_stat",
"peak_mem_usage",
"set_memory_limit",
"MKLMemory",
"cbwr_set",
"cbwr_get",
"cbwr_get_auto_branch",
Expand Down
Loading
Loading