Skip to content

[lapack][cusolver] Use the 64-bit pivot API for getrf and getrs - #759

Open
zjin-lcf wants to merge 2 commits into
uxlfoundation:developfrom
zjin-lcf:feature/cusolver-64bit-pivots
Open

[lapack][cusolver] Use the 64-bit pivot API for getrf and getrs#759
zjin-lcf wants to merge 2 commits into
uxlfoundation:developfrom
zjin-lcf:feature/cusolver-64bit-pivots

Conversation

@zjin-lcf

Copy link
Copy Markdown
Contributor

Summary

Fixes #230.

oneMath types ipiv as int64_t, while the legacy cuSOLVER and cuBLAS entry points take int. Every affected routine therefore allocated a temporary 32-bit array and ran a cast kernel around the call, and in the USM paths it also forced a queue.wait() to release that temporary.

cuSOLVER has accepted int64_t pivots since CUDA 11.0, so getrf, getrs and their batch variants now pass the user's ipiv straight through. That removes 10 of the 14 temporary allocations and their cast kernels.

The entry points are named cusolverDnGetrf/cusolverDnGetrs in CUDA 11.0 and were renamed to cusolverDnXgetrf/cusolverDnXgetrs in 11.1. Inline wrappers hide that difference, and CUDA 10.x keeps the previous conversion path, so no minimum-toolkit requirement changes.

sytrf and getri_batch have no 64-bit counterpart. Their pivot array is now carved out of the tail of the scratchpad rather than allocated separately, which removes the blocking wait that releasing it required. The matching *_scratchpad_size queries account for the tail, so callers that query the size (as the API requires) are unaffected.

Because the 64-bit API takes the dimensions as int64_t, getrf and getrs no longer need the overflow_check that rejected sizes above the 32-bit limit, so these routines now accept dimensions beyond 2^31.

Scope note

This reduces synchronization but does not make the USM paths fully asynchronous: routines that report info still block in lapack_info_check, which is pre-existing behaviour shared by the rest of the backend and left for separate work.

Separate commit

The first commit is an independent bug fix in get_cusolver_devinfo, kept separate for review. It issued an asynchronous memcpy and returned without waiting, while callers read the host vector immediately and then freed the device buffer, so the copy raced with both a destroyed destination and a released source. The copy was also hard-coded to a single int even though batched routines pass batch_size as the info count, leaving the remaining entries uninitialised and allowing a spurious computation_error. This is latent on develop; removing the pivot waits widened the window enough to make it reproducible.

Test plan

Built against CUDA 13.3.1 with DPC++ and tested on an NVIDIA A100.

  • Functional LAPACK tests, both compile-time and run-time dispatch: 328 passed, 0 failed, 70 skipped, matching the develop baseline. Covers getrf, getrs, getri, sytrf and the getrf_batch, getrs_batch, getri_batch variants for all four types in both buffer and USM forms.
  • Repeated full-suite runs (6x compile-time, plus run-time dispatch) to rule out intermittency.
  • The devinfo fix was validated against a flaky Unmtr/Ormtr dependency failure: 2 failures in 60 focused runs before the fix, 0 in 60 after, versus 0 in 60 on the unmodified baseline.
  • Version-guarded fallbacks compile-checked against real headers for CUDA 10.2 (cuSOLVER 10.3.0, legacy conversion path), 11.0.3 (10.6.0, non-X names via wrappers), 11.1.1 (11.0.1, X names) and 12.0.1.
  • clang-format clean against the repository's _clang-format.

zjin-lcf and others added 2 commits August 14, 2026 07:52
get_cusolver_devinfo issued an asynchronous memcpy and returned without
waiting on it. Callers read the host vector immediately and then free the
device buffer, so the copy raced with both a destroyed destination and a
released source.

The copy was also hard-coded to a single int while batched routines pass
batch_size as the info count, leaving the remaining entries uninitialised
and allowing a spurious computation_error.

Wait on the copy and size it to the requested element count.

Co-authored-by: Cursor <cursoragent@cursor.com>
oneMath types ipiv as int64_t while the legacy cuSOLVER and cuBLAS entry
points take int, so every affected routine allocated a temporary 32-bit
array and ran a cast kernel around the call. In the USM paths that also
forced a queue.wait() to release the temporary.

cuSOLVER has taken int64_t pivots since CUDA 11.0, so getrf, getrs and
their batch variants now pass the user's ipiv straight through, removing
ten temporary allocations and their cast kernels. The entry points are
named cusolverDnGetrf/Getrs in CUDA 11.0 and cusolverDnXgetrf/Xgetrs from
11.1 onwards; inline wrappers hide that difference, and CUDA 10.x keeps
the previous conversion path.

sytrf and getri_batch have no 64-bit counterpart. Their pivot array is
now carved out of the tail of the scratchpad instead of being allocated
separately, which removes the blocking wait that releasing it required.
The corresponding scratchpad_size queries account for the tail.

As the X API takes the dimensions as int64_t, getrf and getrs no longer
need the overflow_check that rejects sizes above the 32-bit limit.

Closes uxlfoundation#230

Co-authored-by: Cursor <cursoragent@cursor.com>
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.

[LAPACK][CUSOLVER] Inefficient conversion from 32-bit ints to 64-bit ints.

1 participant