Skip to content

Commit d3ac3c2

Browse files
committed
merge origin/main: resolve FastSenseWidget + accept .planning deletions
Conflicts resolved: libs/Dashboard/FastSenseWidget.m — keep both sides: main's new formatTimeAxis_(ax) call (PR #66 datetime axis migration) AND the PR #68 autoScaleY_ / YLimits branch. formatTimeAxis_ is now invoked inside a try/catch after fp.render() so it can't mask the autoscale logic on older Octave versions that lack axes property listeners. .planning/ROADMAP.md, .planning/STATE.md — accept main's deletion; the planning artefacts were removed upstream in the milestone completion cleanup (#65). test_mex_prebuilt failure (testNeedsBuildReturnsTrueWhenBinaryMissing) is pre-existing on plain main — it asserts the local MEX binary is absent, which does not hold in this worktree. Not introduced by this PR.
2 parents 6b768cb + 85e63b7 commit d3ac3c2

527 files changed

Lines changed: 6321 additions & 110045 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/_build-mex-octave.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,12 @@ jobs:
2424
with:
2525
path: |
2626
libs/FastSense/private/*.mex
27+
libs/FastSense/private/octave-linux-x86_64/*.mex
28+
libs/FastSense/octave-linux-x86_64/*.mex
2729
libs/SensorThreshold/private/*.mex
30+
libs/SensorThreshold/private/octave-linux-x86_64/*.mex
2831
libs/FastSense/mksqlite.mex
29-
key: mex-linux-${{ hashFiles('libs/FastSense/private/mex_src/**', 'libs/FastSense/build_mex.m') }}
32+
key: mex-linux-${{ hashFiles('libs/FastSense/private/mex_src/**', 'libs/FastSense/build_mex.m', 'libs/FastSense/private/.mex-version') }}
3033

3134
- name: Compile MEX files
3235
if: steps.cache-mex.outputs.cache-hit != 'true'
@@ -38,6 +41,9 @@ jobs:
3841
name: ${{ inputs.artifact-name }}
3942
path: |
4043
libs/FastSense/private/*.mex
44+
libs/FastSense/private/octave-linux-x86_64/*.mex
45+
libs/FastSense/octave-linux-x86_64/*.mex
4146
libs/SensorThreshold/private/*.mex
47+
libs/SensorThreshold/private/octave-linux-x86_64/*.mex
4248
libs/FastSense/mksqlite.mex
4349
retention-days: 1

.github/workflows/benchmark.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ jobs:
4545
run: git config --global --add safe.directory /__w/FastSense/FastSense
4646

4747
- name: Store benchmark results
48-
uses: benchmark-action/github-action-benchmark@v1.21.0
48+
uses: benchmark-action/github-action-benchmark@v1.22.0
4949
with:
5050
name: FastSense Performance
5151
tool: customSmallerIsBetter
Lines changed: 320 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,320 @@
1+
name: Refresh MEX Binaries
2+
3+
# Builds the full 7-way platform x runtime matrix (4 MATLAB + 3 Octave) on
4+
# every push to main that touches MEX sources, and on manual dispatch. The
5+
# aggregator job collects all 7 artifacts, regenerates the .mex-version
6+
# stamp, and opens/updates a PR on `chore/refresh-mex-binaries` refreshing
7+
# the committed binaries.
8+
#
9+
# Non-retrigger invariant:
10+
# The auto-PR only touches binaries + .mex-version. Neither of those are
11+
# in `paths`, so merging the PR does not loop. Belt-and-braces: each job
12+
# ignores github-actions[bot] as actor.
13+
#
14+
# Source of truth for the stamp formula is libs/FastSense/private/mex_stamp.m.
15+
# The aggregator mirrors its concatenation ordering: sorted *.c files in
16+
# mex_src/, then sorted *.h files in mex_src/, then build_mex.m, then
17+
# mksqlite.c.
18+
19+
on:
20+
push:
21+
branches: [main]
22+
paths:
23+
- 'libs/FastSense/private/mex_src/**'
24+
- 'libs/FastSense/build_mex.m'
25+
- 'libs/FastSense/mksqlite.c'
26+
# Defensive: refresh if the stamp formula itself changes. The formula
27+
# is reimplemented in bash inside the aggregator job; if mex_stamp.m
28+
# and the aggregator drift, stamps mismatch and binaries rebuild
29+
# without the committed stamp updating -- infinite rebuild loop.
30+
- 'libs/FastSense/mex_stamp.m'
31+
workflow_dispatch:
32+
33+
concurrency:
34+
group: refresh-mex-${{ github.ref }}
35+
cancel-in-progress: true
36+
37+
permissions:
38+
contents: write
39+
pull-requests: write
40+
41+
jobs:
42+
build-matlab:
43+
name: MATLAB MEX ${{ matrix.label }}
44+
if: github.actor != 'github-actions[bot]'
45+
timeout-minutes: 45
46+
strategy:
47+
fail-fast: false
48+
matrix:
49+
include:
50+
- label: macos-arm64
51+
os: macos-14
52+
release: R2023b
53+
mexext: mexmaca64
54+
- label: macos-x86_64
55+
os: macos-15-intel
56+
release: R2023b
57+
mexext: mexmaci64
58+
- label: linux-x86_64
59+
os: ubuntu-22.04
60+
release: R2020b
61+
mexext: mexa64
62+
- label: windows-x86_64
63+
os: windows-latest
64+
release: R2020b
65+
mexext: mexw64
66+
runs-on: ${{ matrix.os }}
67+
steps:
68+
- uses: actions/checkout@v6
69+
70+
- uses: matlab-actions/setup-matlab@v3
71+
with:
72+
release: ${{ matrix.release }}
73+
cache: true
74+
75+
- name: Delete stale binaries for this platform
76+
shell: bash
77+
run: |
78+
find libs -type f -name "*.${{ matrix.mexext }}" -delete || true
79+
80+
- name: Verify mexext on runner
81+
uses: matlab-actions/run-command@v3
82+
with:
83+
command: "assert(strcmp(mexext(), '${{ matrix.mexext }}'), sprintf('Expected %s, got %s', '${{ matrix.mexext }}', mexext()));"
84+
85+
- name: Compile via install()
86+
uses: matlab-actions/run-command@v3
87+
with:
88+
command: "install();"
89+
90+
- name: Upload artifact
91+
uses: actions/upload-artifact@v7
92+
with:
93+
name: mex-matlab-${{ matrix.label }}
94+
path: |
95+
libs/FastSense/private/*.${{ matrix.mexext }}
96+
libs/FastSense/mksqlite.${{ matrix.mexext }}
97+
libs/SensorThreshold/private/*.${{ matrix.mexext }}
98+
if-no-files-found: error
99+
retention-days: 3
100+
101+
build-octave-linux:
102+
name: Octave MEX linux-x86_64
103+
if: github.actor != 'github-actions[bot]'
104+
timeout-minutes: 30
105+
runs-on: ubuntu-22.04
106+
container: gnuoctave/octave:11.1.0
107+
steps:
108+
- uses: actions/checkout@v6
109+
110+
- name: Delete stale Octave binaries
111+
run: find libs -type f -name '*.mex' -delete || true
112+
113+
- name: Compile via install()
114+
run: octave --eval "install();"
115+
116+
- name: Verify subdir output
117+
run: |
118+
test -f libs/FastSense/private/octave-linux-x86_64/binary_search_mex.mex
119+
test -f libs/FastSense/octave-linux-x86_64/mksqlite.mex
120+
121+
- uses: actions/upload-artifact@v7
122+
with:
123+
name: mex-octave-linux-x86_64
124+
path: |
125+
libs/FastSense/private/octave-linux-x86_64/*.mex
126+
libs/FastSense/octave-linux-x86_64/*.mex
127+
libs/SensorThreshold/private/octave-linux-x86_64/*.mex
128+
if-no-files-found: error
129+
retention-days: 3
130+
131+
build-octave-macos:
132+
name: Octave MEX macos-arm64
133+
if: github.actor != 'github-actions[bot]'
134+
timeout-minutes: 30
135+
runs-on: macos-14
136+
steps:
137+
- uses: actions/checkout@v6
138+
139+
- name: Install Octave
140+
run: brew install octave
141+
142+
- name: Delete stale Octave binaries
143+
run: find libs -type f -name '*.mex' -delete || true
144+
145+
- name: Compile via install()
146+
run: octave --eval "install();"
147+
148+
- name: Verify subdir output
149+
run: |
150+
test -f libs/FastSense/private/octave-macos-arm64/binary_search_mex.mex
151+
test -f libs/FastSense/octave-macos-arm64/mksqlite.mex
152+
153+
- uses: actions/upload-artifact@v7
154+
with:
155+
name: mex-octave-macos-arm64
156+
path: |
157+
libs/FastSense/private/octave-macos-arm64/*.mex
158+
libs/FastSense/octave-macos-arm64/*.mex
159+
libs/SensorThreshold/private/octave-macos-arm64/*.mex
160+
if-no-files-found: error
161+
retention-days: 3
162+
163+
build-octave-windows:
164+
name: Octave MEX windows-x86_64
165+
if: github.actor != 'github-actions[bot]'
166+
timeout-minutes: 45
167+
runs-on: windows-latest
168+
steps:
169+
- name: Allow paths with colons (wiki files)
170+
run: git config --global core.protectNTFS false
171+
172+
- uses: actions/checkout@v6
173+
with:
174+
sparse-checkout: |
175+
libs
176+
install.m
177+
sparse-checkout-cone-mode: false
178+
179+
- name: Install Octave
180+
shell: pwsh
181+
run: |
182+
# Try Chocolatey first
183+
choco install octave.portable --yes --version=9.2.0 --no-progress 2>$null
184+
$octExe = Get-ChildItem -Path "C:\ProgramData\chocolatey\lib\octave.portable\tools" -Recurse -Filter "octave-cli.exe" -ErrorAction SilentlyContinue | Select-Object -First 1
185+
if ($octExe) {
186+
Write-Host "Octave installed via Chocolatey at: $($octExe.FullName)"
187+
echo "OCTAVE_EXE=$($octExe.FullName)" >> $env:GITHUB_ENV
188+
exit 0
189+
}
190+
# Fallback: direct download from mirror
191+
$LASTEXITCODE = 0
192+
$global:LASTEXITCODE = 0
193+
Write-Host "::warning::Chocolatey install failed (ftp.gnu.org may be down). Downloading from mirror..."
194+
$url = "https://mirrors.kernel.org/gnu/octave/windows/octave-9.2.0-w64.zip"
195+
$zip = "$env:TEMP\octave.zip"
196+
$dest = "C:\octave"
197+
Invoke-WebRequest -Uri $url -OutFile $zip -UseBasicParsing
198+
Expand-Archive -Path $zip -DestinationPath $dest -Force
199+
$octExe = Get-ChildItem -Path $dest -Recurse -Filter "octave-cli.exe" | Select-Object -First 1
200+
if (-not $octExe) {
201+
Write-Error "Failed to find octave-cli.exe after direct download"
202+
exit 1
203+
}
204+
Write-Host "Octave installed via direct download at: $($octExe.FullName)"
205+
echo "OCTAVE_EXE=$($octExe.FullName)" >> $env:GITHUB_ENV
206+
timeout-minutes: 15
207+
208+
- name: Delete stale Octave binaries
209+
shell: pwsh
210+
run: Get-ChildItem -Recurse libs -Filter '*.mex' -ErrorAction SilentlyContinue | Remove-Item -Force
211+
212+
- name: Compile via install()
213+
shell: pwsh
214+
run: |
215+
$octExe = $env:OCTAVE_EXE
216+
if (-not $octExe -or -not (Test-Path $octExe)) {
217+
Write-Error "OCTAVE_EXE not set or not found: $octExe"
218+
exit 1
219+
}
220+
& $octExe --no-window-system --eval "install();"
221+
222+
- name: Verify subdir output
223+
shell: pwsh
224+
run: |
225+
if (-not (Test-Path 'libs/FastSense/private/octave-windows-x86_64/binary_search_mex.mex')) { throw "kernel missing under libs/FastSense/private/octave-windows-x86_64/" }
226+
if (-not (Test-Path 'libs/FastSense/octave-windows-x86_64/mksqlite.mex')) { throw "mksqlite missing under libs/FastSense/octave-windows-x86_64/" }
227+
228+
- uses: actions/upload-artifact@v7
229+
with:
230+
name: mex-octave-windows-x86_64
231+
path: |
232+
libs/FastSense/private/octave-windows-x86_64/*.mex
233+
libs/FastSense/octave-windows-x86_64/*.mex
234+
libs/SensorThreshold/private/octave-windows-x86_64/*.mex
235+
if-no-files-found: error
236+
retention-days: 3
237+
238+
open-refresh-pr:
239+
name: Aggregate + Open PR
240+
needs:
241+
- build-matlab
242+
- build-octave-linux
243+
- build-octave-macos
244+
- build-octave-windows
245+
if: always() && !cancelled() && github.actor != 'github-actions[bot]'
246+
runs-on: ubuntu-22.04
247+
permissions:
248+
contents: write
249+
pull-requests: write
250+
steps:
251+
- uses: actions/checkout@v6
252+
253+
# Download ALL artifacts into the workspace; merge-multiple preserves
254+
# the repo-relative paths each artifact was uploaded with, dropping
255+
# them back into libs/.../{,octave-<tag>/}.
256+
- uses: actions/download-artifact@v8
257+
with:
258+
pattern: mex-*
259+
merge-multiple: true
260+
261+
- name: Regenerate .mex-version stamp
262+
shell: bash
263+
run: |
264+
# Mirror libs/FastSense/private/mex_stamp.m: sorted *.c then sorted
265+
# *.h from mex_src (non-recursive), then build_mex.m, then mksqlite.c.
266+
set -euo pipefail
267+
src_dir="libs/FastSense/private/mex_src"
268+
mapfile -t c_files < <(find "$src_dir" -maxdepth 1 -name '*.c' | LC_ALL=C sort)
269+
mapfile -t h_files < <(find "$src_dir" -maxdepth 1 -name '*.h' | LC_ALL=C sort)
270+
tmp="$(mktemp)"
271+
for f in "${c_files[@]}" "${h_files[@]}" libs/FastSense/build_mex.m libs/FastSense/mksqlite.c; do
272+
cat "$f" >> "$tmp"
273+
done
274+
hex="$(sha256sum "$tmp" | awk '{print $1}')"
275+
rm -f "$tmp"
276+
printf 'sha256:%s\n' "$hex" > libs/FastSense/private/.mex-version
277+
echo "Stamp:"
278+
cat libs/FastSense/private/.mex-version
279+
280+
- name: Show refreshed tree
281+
run: |
282+
find libs -type f \( \
283+
-name '*.mexmaca64' -o -name '*.mexmaci64' -o \
284+
-name '*.mexa64' -o -name '*.mexw64' -o \
285+
-name '*.mex' \
286+
\) | sort
287+
echo "--- stamp ---"
288+
cat libs/FastSense/private/.mex-version
289+
290+
- uses: peter-evans/create-pull-request@v7
291+
with:
292+
branch: chore/refresh-mex-binaries
293+
delete-branch: true
294+
commit-message: "chore(mex): refresh prebuilt MEX binaries"
295+
title: "chore: refresh prebuilt MEX binaries"
296+
body: |
297+
Auto-generated by `.github/workflows/refresh-mex-binaries.yml`.
298+
299+
Regenerates committed MEX binaries for all 7 platform x runtime
300+
combinations and updates `libs/FastSense/private/.mex-version`.
301+
302+
Merging this PR does NOT retrigger the workflow (binaries and
303+
the stamp are excluded from the workflow's `paths` filter).
304+
add-paths: |
305+
libs/FastSense/private/*.mexmaca64
306+
libs/FastSense/private/*.mexmaci64
307+
libs/FastSense/private/*.mexa64
308+
libs/FastSense/private/*.mexw64
309+
libs/FastSense/mksqlite.mexmaca64
310+
libs/FastSense/mksqlite.mexmaci64
311+
libs/FastSense/mksqlite.mexa64
312+
libs/FastSense/mksqlite.mexw64
313+
libs/SensorThreshold/private/*.mexmaca64
314+
libs/SensorThreshold/private/*.mexmaci64
315+
libs/SensorThreshold/private/*.mexa64
316+
libs/SensorThreshold/private/*.mexw64
317+
libs/FastSense/private/octave-*/**
318+
libs/FastSense/octave-*/**
319+
libs/SensorThreshold/private/octave-*/**
320+
libs/FastSense/private/.mex-version

.github/workflows/release.yml

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,10 @@ jobs:
5959
cp install.m LICENSE README.md CITATION.cff "${DIRNAME}/"
6060
cp -r examples "${DIRNAME}/"
6161
62-
# Copy libs, excluding compiled MEX binaries
62+
# Copy libs including committed prebuilt MEX binaries.
63+
# Binaries are refreshed by .github/workflows/refresh-mex-binaries.yml
64+
# and shipped in the release archive so end users skip compilation.
6365
cp -r libs "${DIRNAME}/"
64-
find "${DIRNAME}/libs" -type f \( \
65-
-name "*.mexmaca64" -o -name "*.mexmaci64" \
66-
-o -name "*.mexa64" -o -name "*.mexw64" \
67-
-o -name "*.mex" \) -delete
6866
6967
# Create archives
7068
tar czf "${DIRNAME}.tar.gz" "${DIRNAME}"
@@ -81,7 +79,7 @@ jobs:
8179
8280
## Installation
8381
84-
Download the archive, extract it, and run `install` in MATLAB/Octave to add libraries to path and compile MEX accelerators.
82+
Download the archive, extract it, and run `install` in MATLAB/Octave. Prebuilt MEX binaries are bundled — compilation only happens on unsupported platforms.
8583
files: |
8684
FastSense-${{ steps.version.outputs.VERSION }}.tar.gz
8785
FastSense-${{ steps.version.outputs.VERSION }}.zip

0 commit comments

Comments
 (0)