Skip to content

Commit 2bac198

Browse files
committed
FEAT: Add meson build + ctypes/pytest test driver with MPFR oracle
Top-level meson build compiles each op's test kernels into their own dlopen-able plugin, with Highway as a build-time subproject. The numpy_sr package dlopens the plugins and dispatches over numpy buffers via ctypes; tests are plain pytest. - Targets per ISA with ops exposed at module scope (numpy_sr.sin), accuracy= keyword taking Precise() profiles, fenv context manager. - Correctly-rounded MPFR reference kernels as oracle. - ULP assertion helpers and reusable test-data generators; first suite covers sin/cos. - Random test seed by default (NPSR_SEED overrides), shared across xdist workers so all sweep identical data. - spin build/test commands - CI smoke + stress.
1 parent ca4f3e6 commit 2bac198

27 files changed

Lines changed: 1760 additions & 17 deletions

.github/workflows/tests.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Per-arch `spin build` + `spin test` on native hosted runners: a fast smoke
2+
# pass first, then the stress sweeps (MPFR-validated, marked `stress`).
3+
name: Tests
4+
5+
on:
6+
push:
7+
branches: [main]
8+
pull_request:
9+
10+
concurrency:
11+
group: ${{ github.workflow }}-${{ github.ref }}
12+
cancel-in-progress: true
13+
14+
jobs:
15+
test:
16+
name: ${{ matrix.arch }}
17+
runs-on: ${{ matrix.runner }}
18+
timeout-minutes: 60
19+
strategy:
20+
fail-fast: false
21+
matrix:
22+
include:
23+
- arch: x86-64
24+
runner: ubuntu-24.04
25+
- arch: arm64
26+
runner: ubuntu-24.04-arm
27+
steps:
28+
- uses: actions/checkout@v4
29+
- uses: actions/setup-python@v5
30+
with:
31+
python-version: '3.12' # project minimum
32+
- name: Install dependencies
33+
run: |
34+
sudo apt-get update
35+
sudo apt-get install -y --no-install-recommends libmpfr-dev
36+
python -m pip install -r test_requirements.txt
37+
- name: Build
38+
run: spin build
39+
- name: Smoke test
40+
run: spin test -- -m "not stress" -q
41+
- name: Stress test
42+
run: spin test -- -m stress -q

.gitignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,16 @@
2222
###########
2323
*.patch
2424
*.diff
25+
build/
26+
build-install/
27+
# Test unit's default report artifact (override path via NPSR_TEST_REPORT)
28+
/npsr-test-report.json
29+
subprojects/highway/
30+
subprojects/packagecache/
31+
subprojects/googletest-1.17.0/
32+
.venv/
33+
.cache/
34+
__pycache__/
35+
# Hypothesis example database (numpy_sr test suite)
36+
.hypothesis/
37+
/subprojects/.wraplock

.spin/cmds.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import pathlib
22
import sys
3+
34
import click
45

56
curdir = pathlib.Path(__file__).parent

meson.build

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
project(
2+
'npsr',
3+
'cpp',
4+
version: '0.1.0',
5+
meson_version: '>= 1.3.0',
6+
license: 'BSD-3-Clause',
7+
default_options: [
8+
'cpp_std=c++17',
9+
'buildtype=release',
10+
],
11+
)
12+
13+
py = import('python').find_installation()
14+
npsr_inc = include_directories('.')
15+
16+
# `numpy_sr` scans the op sources (npsr/**/tests/<op>.cc), builds them, and
17+
# installs the Python package (harness + kernels + tests).
18+
if get_option('tests').disable_auto_if(meson.is_subproject()).allowed()
19+
subdir('numpy_sr')
20+
endif

meson_options.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
option('tests', type: 'feature', value: 'auto', description: 'Build per-operation shared libraries for the pytest harness')

npsr/lut-inl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#endif
77

88
#include <tuple>
9+
#include <limits>
910

1011
#include "npsr/hwy.h"
1112

npsr/trig/tests/cos.cc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// npsr Cos test library: one Operation registered per Highway target;
2+
// npsr_py_load comes from pyext.cc, the MPFR oracle from mpfr.cc.
3+
#undef HWY_TARGET_INCLUDE
4+
#define HWY_TARGET_INCLUDE "npsr/trig/tests/cos.cc"
5+
#include "hwy/foreach_target.h" // IWYU pragma: keep
6+
#include "hwy/highway.h"
7+
#include "numpy_sr/pyext-inl.h"
8+
9+
HWY_BEFORE_NAMESPACE();
10+
namespace npsr::py::HWY_NAMESPACE {
11+
struct CosFn {
12+
template <class P, class V>
13+
V operator()(P& p, V v) const {
14+
return ::npsr::HWY_NAMESPACE::Cos(p, v);
15+
}
16+
};
17+
static RegisteredOperation reg_cos{MakeUnaryOperation<CosFn>("cos")};
18+
} // namespace npsr::py::HWY_NAMESPACE
19+
HWY_AFTER_NAMESPACE();

npsr/trig/tests/mpfr.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// MPFR reference oracles for all trig ops (numpy_sr.mpfr.*): one plugin
2+
// library, no Highway targets; npsr_py_load comes from pyext.cc.
3+
#include "numpy_sr/pyext-mpfr.h"
4+
5+
namespace npsr::py {
6+
static RegisteredOperation ops{MakeMpfr<mpfr_sin>("sin"),
7+
MakeMpfr<mpfr_cos>("cos")};
8+
} // namespace npsr::py

npsr/trig/tests/sin.cc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// npsr Sin test library: one Operation registered per Highway target;
2+
// npsr_py_load comes from pyext.cc, the MPFR oracle from mpfr.cc.
3+
#undef HWY_TARGET_INCLUDE
4+
#define HWY_TARGET_INCLUDE "npsr/trig/tests/sin.cc"
5+
#include "hwy/foreach_target.h" // IWYU pragma: keep
6+
#include "hwy/highway.h"
7+
#include "numpy_sr/pyext-inl.h"
8+
9+
HWY_BEFORE_NAMESPACE();
10+
namespace npsr::py::HWY_NAMESPACE {
11+
struct SinFn {
12+
template <class P, class V>
13+
V operator()(P& p, V v) const {
14+
return ::npsr::HWY_NAMESPACE::Sin(p, v);
15+
}
16+
};
17+
static RegisteredOperation reg_sin{MakeUnaryOperation<SinFn>("sin")};
18+
} // namespace npsr::py::HWY_NAMESPACE
19+
HWY_AFTER_NAMESPACE();

0 commit comments

Comments
 (0)