feat: broaden CPU and platform coverage across PyPI, nodes, and crate… (#26)
* feat: broaden CPU and platform coverage across PyPI, nodes, and crates.io Replace static SIMD with runtime CPU-feature dispatch and expand the release wheel matrix so one set of artifacts runs on any target CPU and platform without illegal-instruction crashes. Rust core: - Add multiversion runtime dispatch (crates/ferro_ta_core/src/simd.rs); drop compile-time `wide`. `simd` feature is now default-on and forwarded through the pyo3 crate, and stays compatible with #![forbid(unsafe_code)]. Packaging: - abi3-py310: one cp310-abi3 wheel per platform (covers CPython 3.10+). - CI matrix adds Linux aarch64 + musllinux (x86_64/aarch64) and Windows arm64. Node/Docker + docs: - api/Dockerfile: document baseline+dispatch (no target-cpu pin) and add a fail-fast import check; aarch64 containers now install cleanly. - Rewrite docs/guides/simd.md; fix stale `wide` mention in ADR 0003. - Add ADR 0006 (CPU coverage strategy). Also bundles in-flight release prep already staged in the tree (DTW exception types, SBOM/provenance security, supporting docs). * fix(ci): clear cargo-deny and pip-audit failures; apply dependency bumps cargo-deny (advisories): - Ignore pyo3 RUSTSEC-2026-0176 / RUSTSEC-2026-0177 in deny.toml with a documented rationale: ferro-ta uses neither affected code path (PyList/PyTuple nth iterators; PyCFunction::new_closure). Upstream fix needs pyo3 >=0.29 (large API migration), tracked as a follow-up. pip-audit: - Bump dev lockfile idna 3.18, pytest 9.1.1, urllib3 2.7.0 to clear PYSEC-2026-215, CVE-2025-71176, PYSEC-2026-141/142. Dependency bumps (supersede open dependabot PRs; they auto-close on merge): - cargo: log 0.4.32, serde_json 1.0.150, rayon 1.12.0 - api/requirements.txt: uvicorn>=0.49.0, pydantic>=2.13.4, ferro-ta>=1.1.4 - CI actions: deploy-pages v5, upload-pages-artifact v5, action-gh-release v3 The open `wide` 1.5.0 bump (PR #24) is obsolete — the crate is removed in this branch. * chore: address CodeRabbit review; remove docs/adr section CodeRabbit findings: - CI sbom job: add `attestations: write` so attest-build-provenance can run (it had only contents:write + id-token:write). - simd.rs: vectorize `wma_seed` with lane-local accumulators — it was scalar behind the multiversion wrapper, adding dispatch overhead for no SIMD gain. - CHANGELOG: consolidate the duplicate `### Changed` heading. - python/ferro_ta/__init__.py: also re-export the `FerroTaError` alias. - docs/guides/dtw.md: soften "byte-for-byte" parity to within-tolerance. Remove docs/adr/ at maintainer request and clean up the ADR links in the SIMD and DTW guides. The ADR files remain in commit 9506a30 if ever needed.
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
name: Nightly benchmarks
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# 03:15 UTC every day — off peak, avoids colliding with the regular CI surge.
|
||||
- cron: "15 3 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
bench:
|
||||
name: Run perf contract and regression checks
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
RUSTFLAGS: "" # override target-cpu=native from .cargo/config.toml
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: dtolnay/rust-toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Install uv
|
||||
run: pip install uv
|
||||
|
||||
- name: Build ferro-ta wheel
|
||||
run: |
|
||||
uv sync --extra dev
|
||||
uv run maturin build --release --out dist
|
||||
uv run pip install --force-reinstall dist/*.whl
|
||||
|
||||
- name: Run vs-TA-Lib benchmark
|
||||
run: uv run python benchmarks/bench_vs_talib.py --output benchmarks/artifacts/nightly_vs_talib.json
|
||||
|
||||
- name: Run SIMD benchmark matrix
|
||||
run: uv run python benchmarks/bench_simd.py --output benchmarks/artifacts/nightly_simd.json
|
||||
|
||||
- name: Check hotspot regression
|
||||
id: hotspot
|
||||
continue-on-error: true
|
||||
run: uv run python benchmarks/check_hotspot_regression.py --tolerance 0.05
|
||||
|
||||
- name: Check vs-TA-Lib regression
|
||||
id: vs_talib
|
||||
continue-on-error: true
|
||||
run: uv run python benchmarks/check_vs_talib_regression.py --tolerance 0.05
|
||||
|
||||
- name: Run criterion bench (build only)
|
||||
run: cargo bench -p ferro_ta_core --no-run
|
||||
|
||||
- name: Upload nightly artifacts
|
||||
uses: actions/upload-artifact@v7
|
||||
if: always()
|
||||
with:
|
||||
name: nightly-bench-${{ github.run_id }}
|
||||
path: benchmarks/artifacts/
|
||||
retention-days: 30
|
||||
|
||||
- name: Open issue on regression
|
||||
if: steps.hotspot.outcome == 'failure' || steps.vs_talib.outcome == 'failure'
|
||||
uses: actions/github-script@v8
|
||||
env:
|
||||
HOTSPOT_OUTCOME: ${{ steps.hotspot.outcome }}
|
||||
VS_TALIB_OUTCOME: ${{ steps.vs_talib.outcome }}
|
||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
with:
|
||||
script: |
|
||||
const hotspot = process.env.HOTSPOT_OUTCOME;
|
||||
const vsTalib = process.env.VS_TALIB_OUTCOME;
|
||||
const runUrl = process.env.RUN_URL;
|
||||
const failed = [];
|
||||
if (hotspot === 'failure') failed.push('hotspot');
|
||||
if (vsTalib === 'failure') failed.push('vs-TA-Lib');
|
||||
const title = `Nightly benchmark regression: ${failed.join(' + ')}`;
|
||||
const body = [
|
||||
`The nightly benchmark workflow reported a >5% regression in: **${failed.join(', ')}**.`,
|
||||
'',
|
||||
`Run: ${runUrl}`,
|
||||
'',
|
||||
'Artifacts with the raw JSON are attached to the run above.',
|
||||
'If this is a known regression, update the baseline JSON and close.',
|
||||
'If it is unexpected, investigate the last commit on `main` before the nightly ran.',
|
||||
].join('\n');
|
||||
await github.rest.issues.create({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
title,
|
||||
body,
|
||||
labels: ['performance', 'regression', 'nightly'],
|
||||
});
|
||||
Reference in New Issue
Block a user