ci: give the MSVC viewer /arch:AVX, and write down why -march lives in CI
Build Packages / build:viewer-tgz:cpu (push) Successful in 6m47s
Build Packages / build:viewer-tgz:cuda (push) Successful in 7m11s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 10m9s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 9m45s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 10m39s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 11m48s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 11m26s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 11m48s
Build Packages / build:rpm (rocky8) (push) Successful in 10m35s
Build Packages / build:rpm (rocky9) (push) Successful in 11m22s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 11m41s
Build Packages / Generate python client (push) Successful in 17s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 12m21s
Build Packages / Create release (push) Skipped
Build Packages / Build documentation (push) Successful in 49s
Build Packages / XDS test (durin plugin) (push) Successful in 8m19s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 7m42s
Build Packages / XDS test (neggia plugin) (push) Successful in 6m32s
Build Packages / DIALS test (push) Successful in 12m35s
Build Packages / Unit tests (push) Successful in 1h3m57s
Build Packages / build:windows:nocuda (push) Failing after 2s
Build Packages / build:windows:cuda (push) Failing after 3s

The Linux jobs already pass -march=x86-64-v3; the MSVC viewer job passed nothing,
so it built at the x64 baseline. MSVC has no spelling for the x86-64-v2 level, but
/arch:AVX is the nearest and implies SSE4.1/4.2 - which is the part that matters,
because below SSE4.1 Eigen has no vectorised round and falls back to one libm call
per element. AVX is Sandy Bridge and up, a safe floor for a desktop viewer.

The architecture flags stay OUT of CMakeLists on purpose, so a site can build
x86-64-v4 on an AVX-512 cluster, or -march=native, or the plain baseline. That is
easy to mistake for an oversight and "fix", so say it in CLAUDE.md - together with
the consequence that catches anyone profiling: a default local Release build is not
what CI or production runs, and the gap is not uniform. GPU-bound work is
unaffected, but the CPU and Eigen bound phases - first-pass indexing and
scaling/merging - measure about 26% slower without the flags. That is enough to
make rounding look like a tenth of all cycles when a real build has it nearly free,
and to send a reader at the wrong code.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-01 21:58:36 +02:00
co-authored by Claude Opus 5
parent 6e805f53c0
commit b47bce7c3b
2 changed files with 26 additions and 1 deletions
+5 -1
View File
@@ -2,6 +2,10 @@ name: Build Packages
env:
MARCH_CMAKE_FLAGS: '-DCMAKE_CXX_FLAGS="-march=x86-64-v3" -DCMAKE_C_FLAGS="-march=x86-64-v3"'
# MSVC has no spelling for the x86-64-v2 level; /arch:AVX is the nearest and implies SSE4.1/4.2,
# which is what matters here - without it Eigen has no vectorised round and falls back to a libm
# call per element. AVX is Sandy Bridge (2011) and up, a safe floor for a desktop viewer.
MSVC_ARCH_CMAKE_FLAGS: '-DCMAKE_CXX_FLAGS="/arch:AVX" -DCMAKE_C_FLAGS="/arch:AVX"'
on:
push:
@@ -83,7 +87,7 @@ jobs:
run: |
for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -property installationPath`) do set "VSPATH=%%i"
call "%VSPATH%\VC\Auxiliary\Build\vcvars64.bat"
cmake -G Ninja -B build -DJFJOCH_USE_CUDA=${{ matrix.use_cuda }} -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="C:/deps;C:/Qt/6.11.1/msvc2022_64"
cmake -G Ninja -B build -DJFJOCH_USE_CUDA=${{ matrix.use_cuda }} -DCMAKE_BUILD_TYPE=Release ${{ env.MSVC_ARCH_CMAKE_FLAGS }} -DCMAKE_PREFIX_PATH="C:/deps;C:/Qt/6.11.1/msvc2022_64"
- name: Build viewer
shell: cmd
run: |
+21
View File
@@ -43,6 +43,27 @@ Key CMake options:
- `SLS9` (default OFF) — build against slsDetectorPackage 9.2.0 instead of 8.0.2.
- `JFJOCH_INSTALL_DRIVER_SOURCE` (default OFF) — install the PCIe driver source for DKMS/RPM.
### `-march` is deliberately NOT set in CMakeLists
The build system sets no architecture flags, so a site can pick its own — `x86-64-v4` on an
AVX-512 cluster, `-march=native`, or the plain baseline. **CI passes them explicitly**
(`.gitea/workflows/build_and_test.yml`): every Linux configure gets
`-march=x86-64-v3`, and the MSVC viewer job gets `/arch:AVX` (MSVC has no x86-64-v2 spelling;
`/arch:AVX` is the nearest and implies SSE4.1/4.2).
**This matters when profiling.** A plain `cmake -DCMAKE_BUILD_TYPE=Release ..` produces a
*baseline* binary that is not what CI or production runs, and the difference is not uniform:
GPU-bound work is unaffected, but the CPU/Eigen-bound phases — first-pass indexing and
scaling/merging — are **~26% slower** without the flags (measured). Eigen in particular has no
vectorised `round` below SSE4.1 and falls back to a libm call per element, which can make
rounding look like ~10% of all cycles when it is nearly free in a real build. Pass the CI flags
when measuring anything CPU-side, or the profile will point at the wrong code:
```
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-march=x86-64-v3" \
-DCMAKE_C_FLAGS="-march=x86-64-v3" ..
```
The frontend is a separate custom target: `make frontend` (in `frontend/`: `npm ci`,
`npm run build`, plus the third-party-licenses, Redoc and Sphinx-docs bundling steps). It is never
built automatically — `make install` only copies whatever already sits in `frontend/dist/`.