Skip to content

BQRRP MEX: bulk memcpy marshal, factor in output buffers, static libstdc++ - #2

Merged
mmelnich merged 2 commits into
mainfrom
bqrrp-mex-marshal
Aug 5, 2026
Merged

mmelnich merged 2 commits into
mainfrom
bqrrp-mex-marshal

Conversation

@mmelnich

@mmelnich mmelnich commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Performance and buildability fixes for the BQRRP MEX (release-plan item C2). Two commits:

  1. Statically link libstdc++ on GNU/Linux. MATLAB ships its own older libstdc++.so.6, which lacks the GLIBCXX symbols emitted by GCC 13+, so a MEX built with a modern toolchain fails to load (GLIBCXX_x.y.z not found). This is the same treatment the funnystrompp branch already carries; main needs it to be buildable with current GCC at all. GCC/Linux-only; the flag list is empty for other compilers (AppleClang rejects -static-libgcc, and macOS has no GLIBCXX problem).

  2. Bulk memcpy marshal; factor directly inside the output buffers. The input marshal bound a non-const TypedArray, which triggers MATLAB's copy-on-write unshare (a full deep copy of A before a single element is read), then copied element by element into a value-initialized std::vector (a third full pass, zeroing memory that is immediately overwritten). It is now a single memcpy from a const TypedArray view. In implicit mode the input is marshaled straight into the out1 MATLAB buffer and BQRRP factors in place, writing tau and J directly into their output buffers, so no scratch allocations or output round-trips remain; explicit mode keeps one non-value-initialized scratch (R extraction and ungqr post-process the factored form) and writes J in place.

Measured at 20000x500, implicit mode, median of 7 calls, interleaved old/new runs: 948 ms to 855 ms end to end (the ~93 ms delta is the eliminated copy passes over the 80 MB input plus the output round-trip). Correctness: test_bqrrp passes all six size/type cases (double/single at three shapes).

This is the same copy_into insight already applied to the funnystrompp MEX on the add-funnystrompp-mex branch (where the marshal cost was measured to dominate at n = 3000); PR #1 will merge cleanly over it since the CMake block is byte-identical.

MATLAB ships its own older libstdc++.so.6, which lacks the GLIBCXX
symbols emitted by GCC 13+, so a MEX built with a modern toolchain
fails to load with 'GLIBCXX_x.y.z not found'. Statically linking
libstdc++/libgcc into the MEX removes the runtime dependency. Same
treatment the funnystrompp branch already carries; main needs it to be
buildable with current GCC at all.
The input marshal bound a non-const TypedArray, which triggers
MATLAB's copy-on-write unshare (a full deep copy of A before a single
element is read), then copied element by element into a
value-initialized std::vector (a third full pass to zero memory that
is overwritten immediately). The marshal is now one memcpy from a
const TypedArray view.

Implicit mode goes further: BQRRP factors in place, so the input is
marshaled straight into the out1 MATLAB buffer and the driver writes
tau and J directly into their output buffers; no scratch allocations
and no output round-trips remain. Explicit mode keeps one scratch copy
(R extraction and ungqr post-process the factored form) allocated
without value-initialization, and J is still written in place.

Measured on 20000x500 implicit calls (median of 7, interleaved runs):
948 ms -> 855 ms end to end. Correctness: test_bqrrp passes all six
size/type cases.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant