Repository navigation
Commit 8f67ff7
authored
Fall back to cudaMalloc on CUDA devices without memory pools (pytorch#23405)
The CUDA backend's stream-ordered allocations fail on any device that
does not support
memory pools, which includes data-center GPUs in TCC mode on Windows
(A10G, A100, H100 and
the like). There cudaMemPoolCreate and cudaMallocAsync return
cudaErrorNotSupported, and
nothing falls back:
E cuda_allocator.cpp:99] cudaMemPoolCreate failed for device 0:
operation not supported. Using the default pool.
E cuda_allocator.cpp:448] cudaMallocAsync failed: operation not
supported (requested 512 bytes on device 0)
F storage.h:126] In function allocate(), assert failed (result.ok()):
CudaAllocator::allocate_async failed for 512 bytes on device 0
That is from a CUDA program running on the Windows GPU CI runner (an
A10G) in pytorch#23123, the
first CI job to run the delegate on Windows with a driver installed. A
GeForce card in WDDM
mode supports memory pools, which is why a local run passes.
## Change
- CudaAllocator (extension/cuda/cuda_allocator, where pytorch#23447 moved it)
asks each device once
whether it supports memory pools
(cudaDevAttrMemoryPoolsSupported) and caches the answer in per-device
atomics. On a device
that does not, allocate_async allocates with cudaMalloc and
deallocate_async frees with
cudaFree, deciding by the device the pointer lives on. A failed
attribute query keeps the
stream-ordered path.
- On a device with memory pools the paths are the ones they were:
allocate_async adds one
atomic load, and deallocate_async looks up the pointer's device only
once some device
without pools has been seen, so a process whose devices all have them
frees exactly as
before.
- The fallback refuses while the stream is capturing a CUDA graph. In
relaxed capture mode
cudaMalloc and cudaFree succeed, so a block freed during capture would
be handed out
again while every replay still writes to it; refusing keeps the loud
failure the
stream-ordered call gave, and a free kept during a capture is reported
to the caller
(deallocate_stream_ordered returns NotSupported; a failed cudaFree
returns Internal). On
such a device the backend also does not turn CUDA graphs on for a method
that asks for
them (enable_cuda_graph_for_method), and says so in the log.
- sort.cu and rand.cu called cudaMallocAsync/cudaFreeAsync directly.
They now call
CudaAllocator::allocate_stream_ordered / deallocate_stream_ordered with
their real device,
which is cudaMallocAsync/cudaFreeAsync on the stream as before (the
device default pool,
not the allocator's retaining pool) and the cudaMalloc fallback without
pools. rand passes
the current device, the one its stream was created on.
- rand's one-time RNG state allocation now reports a failure: the shims
return an error
instead of launching their kernels with a null state, and a later call
tries again.
## Tests and CI
- test_cuda_allocator: AllocateAsyncRoundtrip and
StreamOrderedScratchRoundtrip run on every
device. Four tests run on a device without pools:
FallsBackWithoutMemoryPools checks that
the fallback allocation is actually released by deallocate_async,
FallbackRefusesWhileCapturing that neither allocator falls back inside a
capture,
FallbackKeepsBlocksFreedWhileCapturing that blocks freed during a
capture, through both
free paths, stay allocated and intact through a replay and that the kept
block is
reported, and CudaGraphStaysOffWithoutMemoryPools that the CUDA graph
state the backend
starts from (CudaGraphState::start_warmup) stays disabled. They skip on
a device with pools,
except where EXECUTORCH_CUDA_TEST_REQUIRE_NO_MEMORY_POOLS is set, as the
Windows job does,
where they fail instead so the fallback cannot go untested; with it set,
no visible CUDA
device fails the tests too rather than skipping them. The pool tests
move to a
fixture that skips on a device without pools, alongside
CudaGraphStartsWithMemoryPools.
- test_cuda_sort_rand (new): runs the sort shim along both dims of a 2-D
tensor (the
transpose path that allocates two scratch buffers, and thrust's scratch)
on input with
repeated values in every slice, against a host stable sort, checking
values and indices,
and the rand shim. Built only where sort.cu and
rand.cu are (a CUDA build that found a CUDA compiler).
- cuda-windows.yml gains unittest-cuda-runtime-windows, the Windows
counterpart of
cuda.yml's unittest-cuda-runtime: it builds llm-release-cuda with tests
and runs the same
runtime tests plus test_cuda_sort_rand. The Windows runner's A10G has no
memory pools, so
this covers the fallback; the Linux job, which now runs
test_cuda_sort_rand too, covers
the pool path. Its pull_request paths include the scripts and
tools/cmake/Test.cmake it
depends on.
- The Windows GPU runners come without an NVIDIA driver (nvcuda.dll is
missing and
cudaGetDeviceCount returns cudaErrorInsufficientDriver), so the job
first installs the
data-center driver that pytorch/pytorch's Windows CUDA smoke tests
install
(driver_update.bat, 580.88, from the same bucket);
install_nvidia_driver_windows.ps1.
- et_cxx_test copies a test's runtime DLLs ($<TARGET_RUNTIME_DLLS>)
beside it on Windows,
which records no search path: the CUDA tests link extension_cuda.dll
from another
directory and could not start otherwise.
- extension/cuda/test/cuda_allocator_exit.cpp (Linux only) fakes every
CUDA call on its
path; it now also fakes cudaDeviceGetAttribute to report pools, since
the pool query is new
on that path and would otherwise make the test depend on the machine's
GPU.
## Test plan
- Windows 11, RTX 5080 (WDDM, memory pools supported), CUDA 13.0,
llm-release-cuda with
tests, rebased on main with the allocator in extension/cuda: all six
runtime tests pass
(test_cuda_allocator 22 passed with the four no-pool tests skipped;
mutable_state 15,
weight_cache 11, sort_rand 2, guard 7, stream_guard 21). With
EXECUTORCH_CUDA_TEST_REQUIRE_NO_MEMORY_POOLS set, the four no-pool tests
fail there, as
intended. test_cuda_allocator_exit is Linux only and runs in the Linux
job.
- The no-pool path runs in the Windows CI job on the A10G; on the
previous revision of this
PR that job passed the fallback tests there.
- Linux: the pool path is covered by the existing unittest-cuda-runtime
job.
Found while adding the Windows CUDA wheel (pytorch#23123), which needs this to
run on the Windows
GPU runner; this PR does not depend on it.1 parent f11a5f8 commit 8f67ff7
16 files changed
Lines changed: 893 additions & 49 deletions
File tree
- .ci/scripts
- .github/workflows
- backends/cuda
- runtime
- shims
- test
- extension/cuda
- test
- tools/cmake
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
20 | 25 | | |
21 | 26 | | |
22 | 27 | | |
| |||
223 | 228 | | |
224 | 229 | | |
225 | 230 | | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
226 | 266 | | |
227 | 267 | | |
228 | 268 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
577 | 577 | | |
578 | 578 | | |
579 | 579 | | |
580 | | - | |
| 580 | + | |
581 | 581 | | |
582 | 582 | | |
583 | 583 | | |
| 584 | + | |
584 | 585 | | |
585 | 586 | | |
586 | 587 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
475 | 475 | | |
476 | 476 | | |
477 | 477 | | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
478 | 487 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
89 | 89 | | |
90 | 90 | | |
91 | 91 | | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
92 | 101 | | |
93 | 102 | | |
94 | 103 | | |
| |||
539 | 548 | | |
540 | 549 | | |
541 | 550 | | |
542 | | - | |
| 551 | + | |
| 552 | + | |
543 | 553 | | |
544 | | - | |
545 | | - | |
546 | | - | |
547 | | - | |
548 | | - | |
549 | | - | |
550 | | - | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
| 558 | + | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
551 | 567 | | |
552 | 568 | | |
553 | 569 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
135 | 135 | | |
136 | 136 | | |
137 | 137 | | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
138 | 145 | | |
139 | 146 | | |
140 | 147 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
| 14 | + | |
14 | 15 | | |
15 | 16 | | |
16 | 17 | | |
| |||
20 | 21 | | |
21 | 22 | | |
22 | 23 | | |
| 24 | + | |
23 | 25 | | |
24 | 26 | | |
25 | 27 | | |
| |||
57 | 59 | | |
58 | 60 | | |
59 | 61 | | |
60 | | - | |
61 | | - | |
62 | | - | |
63 | | - | |
64 | | - | |
65 | | - | |
66 | | - | |
67 | | - | |
68 | | - | |
69 | | - | |
70 | | - | |
71 | | - | |
72 | | - | |
73 | | - | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
74 | 93 | | |
75 | 94 | | |
76 | 95 | | |
| |||
211 | 230 | | |
212 | 231 | | |
213 | 232 | | |
214 | | - | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
215 | 237 | | |
216 | 238 | | |
217 | 239 | | |
| |||
271 | 293 | | |
272 | 294 | | |
273 | 295 | | |
274 | | - | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
275 | 300 | | |
276 | 301 | | |
277 | 302 | | |
| |||
0 commit comments