Skip to content

[Windows] Drop the torch/lib DLL preload glob - #202206

Closed
zklaus wants to merge 1 commit into
pytorch:mainfrom
zklaus:windows-drop-dll-preload-glob
Closed

zklaus wants to merge 1 commit into
pytorch:mainfrom
zklaus:windows-drop-dll-preload-glob

Conversation

@zklaus

@zklaus zklaus commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Linked issue or supporting maintainer

Part of #199894. Supersedes #200856 and #199925: without the preload there is no list of test-only DLLs to maintain.

BC-breaking?

No for the supported configurations. import torch no longer preloads every DLL in torch/lib; libraries that are loaded on demand are now loaded only on demand, and the PATH fallback for systems without AddDllDirectory (pre Windows 8 without KB2533623) is gone.

Summary (human written only)

On Windows we are preloading all libraries in torch/lib. This is somewhat costly and leads to occasional problems. Furthermore, it is likely no longer necessary because the loading code has become smarter and is now able to load dependencies on demand. This PR is here to test that hypothesis in CI.

Agent details (if applicable)

Analysis and change prepared with Claude Code, reviewed by me. The commit message carries the full reasoning. Agent notes:

The Windows loader has preloaded every DLL in torch/lib since #35362, because caffe2_nvrtc.dll was loaded by name from CUDAHooks.cpp and plain LoadLibraryW did not search directories registered with AddDllDirectory. Two later changes made that moot: #45674 (2020-10) switched CUDA builds to the in-tree LazyNVRTC, so caffe2_nvrtc.dll is only loaded by name on ROCm, and #49781 (2021-01) moved at::DynamicLibrary to LoadLibraryExW with LOAD_LIBRARY_SEARCH_DEFAULT_DIRS, which searches what os.add_dll_directory registers. Meanwhile the preload keeps turning on-demand libraries into import-time failures (#199894, #179024, #182123). The glob only ever preloaded torch's own DLLs with the default search flags; the NVIDIA wheel directories come from the cuda-pathfinder loop (and, on CI, from the toolkit bin dir fallback), which this PR does not touch.

Tested on hardware, since trunk has had no Windows CUDA test shards since #139336: Windows 11 VM with an RTX 2060 (driver 610.88), 2026-10-26 cu132 nightly wheel, torch/__init__.py replaced by this PR's version (hash-checked against the base commit). Results:

  • With the stock cuda-pathfinder 1.8.4 the import fails on a clean machine with and without this change, for a reason outside this PR (below). The failure point moves from a WinError 126 on shm.dll in the glob to "DLL load failed while importing _C".
  • With a per-library try in the pathfinder loop (not part of this PR), import, torch.cuda.is_available(), cuDNN conv2d, cuBLAS matmul, cuFFT, cuRAND, cuSOLVER and a jiterator kernel (NVRTC) all pass with the glob removed. 8 of 13 torch/lib DLLs are resident afterwards; caffe2_nvrtc, torch_global_deps, nvToolsExt64_1, libiompstubs5md and torch.dll were never needed.
  • The [Windows] import torch preloads test-only DLLs from torch/lib (aoti_custom_ops.dll), so a failure loading them breaks import #199894 mechanism reproduces: a broken stray zz_broken_test.dll in torch/lib aborts import torch with the glob (WinError 193) and is ignored without it.

Found on the way, independent of this PR: the stock cu132 Windows nightly does not import on a clean machine. nvidia-cuda-cupti 13.2.86 ships cupti64_2026.1.2.dll, which cuda-pathfinder 1.8.4 does not know; the pathfinder loop in torch/__init__.py is one try around all eleven libraries, so the CUPTI miss also skips cuDNN, nvidia\cudnn\bin is never registered, and cudnn64_9.dll (a static import of torch_python.dll and torch_cuda.dll) cannot be found. CUPTI itself still resolves, because a later library in the loop registers the shared nvidia\cu13\bin directory. CI does not see this: the Windows CUDA wheel smoke test runs on a T4 with the CUDA toolkit and cuDNN installed under Program Files, and torch/__init__.py adds that directory to the search path. A per-library try fixes the import with a warning; a pathfinder release that knows the name fixes it silently.

CI on this PR: the full CPU suite on the 12 win-vs2022-cpu-py3 shards, the win-vs2022-cuda13.2-py3 build, and the binaries_wheel smoke tests for every Python version (CUDA wheels on a T4: import, CUDA tensor, magma, cuDNN, RNN and CNN smoke; XPU wheels import on CPU runners). Not covered: the full CUDA test suite on Windows.

🤖 Generated with Claude Code

cc @peterjc123 @mszhanyi @skyline75489 @nbcsm @iremyux @Blackhex @nkhasbag-nv

@pytorch-bot

pytorch-bot Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

🔗 Helpful Links

🧪 See artifacts and rendered test results at hud.pytorch.org/pr/202206

Note: Links to docs will display an error until the docs builds have been completed.

✅ You can merge normally! (2 Unrelated Failures)

As of commit 6416904 with merge base 3481ae5 (image):

NEW FAILURES SUPPRESSED BY AI (non-blocking) - The following jobs failed, but the AI CI Advisor judged the failures not to be evidence against this change:

  • linux-aarch64-binary-manywheel / manywheel-cuda-aarch64-cu130-build (gh) (this job did not run on the merge base, so DrCI cannot tell whether the failure is pre-existing)
    mt-l-arm64g3-61-463

    AI verdict: AI verdict: infra issue

    Both completed failures are the ARC runner pod getting stuck in ImagePullBackOff/ErrImagePull for the full 7200s, then hitting "backoff timeout". The job never ran any build steps. The suspect commit only removes Windows DLL-preload code in torch/init.py, which has no way to affect pulling the container image on an aarch64 Kubernetes runner.

    Full reasoning on HUD →

  • linux-aarch64-binary-manywheel / manywheel-cuda-aarch64-cu132-build (gh) (this job did not run on the merge base, so DrCI cannot tell whether the failure is pre-existing)
    mt-l-arm64g3-61-463

    AI verdict: AI verdict: infra issue

    The job never started. The runner pod sat in Pending with ErrImagePull/ImagePullBackOff on the builder image pytorch/manylinuxaarch64-builder:cuda13.2-8f69b2477f... until the backoff timed out. The suspect commit only removes Windows-only DLL preload code from torch/init.py, and that cannot change which container image the aarch64 Linux job pulls or whether the pull succeeds.

    Full reasoning on HUD →

This comment was automatically generated by Dr. CI and updates every 15 minutes.

@zklaus zklaus added the ciflow/trunk Trigger trunk jobs on your pull request label Oct 27, 2026
@zklaus zklaus added the ciflow/binaries_wheel Trigger binary build and upload jobs for wheel on the PR label Oct 27, 2026
On Windows, `_load_dll_libraries` loads every DLL in torch/lib at import time. The glob was added in pytorch#35362 (2020-03) because `caffe2_nvrtc.dll` was loaded lazily by name from `CUDAHooks.cpp`, and plain `LoadLibraryW` does not search directories registered with `AddDllDirectory`, so the by-name load failed on Python 3.8. Two later changes made that moot: pytorch#45674 (2020-10) switched CUDA builds to the in-tree LazyNVRTC, so `caffe2_nvrtc.dll` is only loaded by name on ROCm, and pytorch#49781 (2021-01) switched `at::DynamicLibrary` to `LoadLibraryExW` with `LOAD_LIBRARY_SEARCH_DEFAULT_DIRS`, which does search the directories that `os.add_dll_directory` registers.

The preload also has a cost: it loads libraries that are only meant to be loaded on demand, such as the INSTALL_TEST libraries (`aoti_custom_ops`, `torchbind_test`, `jitbackend_test`, `backend_with_compiler`), and any failure in one of them aborts `import torch` (pytorch#199894, pytorch#179024, pytorch#182123).

This PR removes the glob and the fallback PATH patching that only mattered on systems without `AddDllDirectory`, keeping `os.add_dll_directory` for torch/lib and the other DLL directories. Everything that remains in torch/lib is a link-time dependency of `_C.pyd` or of a library it pulls in, which Windows resolves through the registered directories.

Test Plan
Trunk CI has no Windows CUDA test shards (removed in pytorch#139336); the Windows CPU build and all its test shards pass with this change, and the Windows CUDA build passes. The CUDA side was verified on a Windows 11 VM with an RTX 2060 (driver 610.88) using the 2026-10-26 cu132 nightly wheel with this change applied to its `torch/__init__.py`: import, `torch.cuda.is_available()`, cuDNN conv2d, cuBLAS matmul, cuFFT, cuRAND, cuSOLVER and a jiterator (NVRTC) kernel all pass, 8 of the 13 DLLs in torch/lib end up resident, and a deliberately broken stray DLL in torch/lib no longer aborts the import (with the glob it fails with WinError 193). Lint:

```
lintrunner -a torch/__init__.py
```

Authored with an AI assistant (Claude Code); the analysis and the change were reviewed by the human author.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
@zklaus
zklaus force-pushed the windows-drop-dll-preload-glob branch from f193ca1 to 6416904 Compare October 27, 2026 14:43

@atalman atalman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, if its work this is great

@zklaus
zklaus marked this pull request as ready for review October 29, 2026 12:48
@zklaus zklaus changed the title [Windows] Drop the torch/lib DLL preload glob (CI experiment) [Windows] Drop the torch/lib DLL preload glob Oct 29, 2026
@zklaus

zklaus commented Oct 29, 2026

Copy link
Copy Markdown
Collaborator Author

@akarale-nv @nkhasbag-nv @tinglvv this drops the torch/lib preload glob that #199894 and #200856 work around. Andrey approved it on Tuesday; before I merge I would like your eyes on it, since it touches the Windows CUDA import path you have been working on.
Hardware results are in the description. Two things I found on the way are not this PR: cuda-pathfinder 1.8.4 does not know cupti64_2026.1.2.dll from nvidia-cuda-cupti 13.2.86, and the pathfinder loop in torch/__init__.py is one try around all eleven libraries, so that miss takes cuDNN down with it and the stock cu132 nightly does not import on a clean Windows machine. CI does not see it because the T4 runner has the toolkit and cuDNN under Program Files. The pathfinder side is NVIDIA/cuda-python#3279 (one line; verified on the VM that with it the stock nightly imports again). The per-library try in torch/__init__.py I can send as a follow-up, or leave to you if you prefer; cc @eqy, @xuhancn for the XPU wheels and @jeffdaily for the TheRock Windows wheels, same import path.

@akarale-nv

Copy link
Copy Markdown
Contributor

Thanks for pointing this out @zklaus , I will take a look at both the cuda-pathfinder and the per-dll loading logic issues.

rwgk added a commit to NVIDIA/cuda-python that referenced this pull request Oct 29, 2026
* Add pathfinder support for cupti64_2026.1.2.dll (CTK 13.2.2)

nvidia-cuda-cupti 13.2.86 (CUDA 13.2.2) ships cupti64_2026.1.2.dll on
Windows, which the cupti descriptor does not list, so
load_nvidia_dynamic_lib("cupti") fails on a machine that only has the
13.2 wheels installed.

Found via the PyTorch cu132 Windows nightly, which loads the CUDA wheel
libraries through cuda-pathfinder at import time
(pytorch/pytorch#202206).

Signed-off-by: Klaus Zimmermann <[email protected]>

* docs(pathfinder): prepare 1.8.5 release notes

Signed-off-by: Ralf W. Grosse-Kunstleve <[email protected]>

---------

Signed-off-by: Klaus Zimmermann <[email protected]>
Signed-off-by: Ralf W. Grosse-Kunstleve <[email protected]>
Co-authored-by: Ralf W. Grosse-Kunstleve <[email protected]>
@nkhasbag-nv

Copy link
Copy Markdown
Contributor

Thanks @zklaus. This looks good to me functionally, and it covers the test-only DLL preload failures that #200856 was working around (#199894). I will close them when this PR merges.

I'll leave the cupti64_2026.1.2.dll problem to @akarale-nv, who has #202589 open for it.

@nkhasbag-nv

Copy link
Copy Markdown
Contributor

Flakiness because of this preload is causing failures in OOT Windows CI. The log file is truncated, message is seen after downloading all logs:

OSError: [WinError 6] The handle is invalid.
Error loading "C:\pt\build\win_tmp\build\torch\lib\aoti_custom_ops.dll" or one of its dependencies.

The 2 failures in this PR seem to be infra related failures. Can we merge this if it looks ok?
@zklaus @atalman

@zklaus

zklaus commented Nov 3, 2026

Copy link
Copy Markdown
Collaborator Author

@pytorchbot merge -i

@pytorchmergebot

Copy link
Copy Markdown
Collaborator

Merge failed

Reason: This PR needs a release notes: label
If your changes are user facing and intended to be a part of release notes, please use a label starting with release notes:.

If not, please add the topic: not user facing label.

To add a label, you can comment to pytorchbot, for example
@pytorchbot label "topic: not user facing"

For more information, see
https://github.com/pytorch/pytorch/wiki/PyTorch-AutoLabel-Bot#why-categorize-for-release-notes-and-how-does-it-work.

Details for Dev Infra team

Raised by workflow job

@zklaus zklaus added release notes: build release notes category topic: bug fixes topic category module: windows Windows support for PyTorch labels Nov 3, 2026
@zklaus

zklaus commented Nov 3, 2026

Copy link
Copy Markdown
Collaborator Author

@pytorchbot merge -i

@pytorchmergebot

Copy link
Copy Markdown
Collaborator

Merge started

Your change will be merged while ignoring the following 2 checks: linux-aarch64-binary-manywheel / manywheel-cuda-aarch64-cu132-build, linux-aarch64-binary-manywheel / manywheel-cuda-aarch64-cu130-build

Learn more about merging in the wiki.

Questions? Feedback? Please reach out to the PyTorch DevX Team

Advanced Debugging
Check the merge workflow status
here

dominikjastrzebskix pushed a commit to dominikjastrzebskix/pytorch that referenced this pull request Nov 5, 2026
## Linked issue or supporting maintainer

Part of pytorch#199894. Supersedes pytorch#200856 and pytorch#199925: without the preload there is no list of test-only DLLs to maintain.

## BC-breaking?

No for the supported configurations. `import torch` no longer preloads every DLL in `torch/lib`; libraries that are loaded on demand are now loaded only on demand, and the `PATH` fallback for systems without `AddDllDirectory` (pre Windows 8 without KB2533623) is gone.

## Summary (human written only)

On Windows we are preloading all libraries in torch/lib. This is somewhat costly and leads to occasional problems. Furthermore, it is likely no longer necessary because the loading code has become smarter and is now able to load dependencies on demand. This PR is here to test that hypothesis in CI.

## Agent details (if applicable)

Analysis and change prepared with Claude Code, reviewed by me. The commit message carries the full reasoning. Agent notes:

The Windows loader has preloaded every DLL in `torch/lib` since pytorch#35362, because `caffe2_nvrtc.dll` was loaded by name from `CUDAHooks.cpp` and plain `LoadLibraryW` did not search directories registered with `AddDllDirectory`. Two later changes made that moot: pytorch#45674 (2020-10) switched CUDA builds to the in-tree LazyNVRTC, so `caffe2_nvrtc.dll` is only loaded by name on ROCm, and pytorch#49781 (2021-01) moved `at::DynamicLibrary` to `LoadLibraryExW` with `LOAD_LIBRARY_SEARCH_DEFAULT_DIRS`, which searches what `os.add_dll_directory` registers. Meanwhile the preload keeps turning on-demand libraries into import-time failures (pytorch#199894, pytorch#179024, pytorch#182123). The glob only ever preloaded torch's own DLLs with the default search flags; the NVIDIA wheel directories come from the cuda-pathfinder loop (and, on CI, from the toolkit bin dir fallback), which this PR does not touch.

Tested on hardware, since trunk has had no Windows CUDA test shards since pytorch#139336: Windows 11 VM with an RTX 2060 (driver 610.88), 2026-10-26 cu132 nightly wheel, `torch/__init__.py` replaced by this PR's version (hash-checked against the base commit). Results:

- With the stock cuda-pathfinder 1.8.4 the import fails on a clean machine with and without this change, for a reason outside this PR (below). The failure point moves from a `WinError 126` on `shm.dll` in the glob to "DLL load failed while importing _C".
- With a per-library `try` in the pathfinder loop (not part of this PR), import, `torch.cuda.is_available()`, cuDNN conv2d, cuBLAS matmul, cuFFT, cuRAND, cuSOLVER and a jiterator kernel (NVRTC) all pass with the glob removed. 8 of 13 `torch/lib` DLLs are resident afterwards; `caffe2_nvrtc`, `torch_global_deps`, `nvToolsExt64_1`, `libiompstubs5md` and `torch.dll` were never needed.
- The pytorch#199894 mechanism reproduces: a broken stray `zz_broken_test.dll` in `torch/lib` aborts `import torch` with the glob (WinError 193) and is ignored without it.

Found on the way, independent of this PR: the stock cu132 Windows nightly does not import on a clean machine. `nvidia-cuda-cupti` 13.2.86 ships `cupti64_2026.1.2.dll`, which cuda-pathfinder 1.8.4 does not know; the pathfinder loop in `torch/__init__.py` is one `try` around all eleven libraries, so the CUPTI miss also skips cuDNN, `nvidia\cudnn\bin` is never registered, and `cudnn64_9.dll` (a static import of `torch_python.dll` and `torch_cuda.dll`) cannot be found. CUPTI itself still resolves, because a later library in the loop registers the shared `nvidia\cu13\bin` directory. CI does not see this: the Windows CUDA wheel smoke test runs on a T4 with the CUDA toolkit and cuDNN installed under Program Files, and `torch/__init__.py` adds that directory to the search path. A per-library `try` fixes the import with a warning; a pathfinder release that knows the name fixes it silently.

CI on this PR: the full CPU suite on the 12 `win-vs2022-cpu-py3` shards, the `win-vs2022-cuda13.2-py3` build, and the `binaries_wheel` smoke tests for every Python version (CUDA wheels on a T4: import, CUDA tensor, magma, cuDNN, RNN and CNN smoke; XPU wheels import on CPU runners). Not covered: the full CUDA test suite on Windows.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Pull Request resolved: pytorch#202206
Approved by: https://github.com/atalman
prewaskar-nv added a commit to NVIDIA/pytorch-windows-ci that referenced this pull request Nov 6, 2026
#38)

cuDNN tests on the WoA shards crash at import/first use with
"Invalid handle. Cannot load symbol cudnnGetVersion" (exit 0xC0000409).

Root cause: the torch wheel bundles cudnn64_9.dll plus its sub-libraries
(cudnn_graph64_9.dll, cudnn_ops64_9.dll, ...) in torch\lib. cudnn64_9.dll
loads the sub-libraries lazily by bare name. pytorch/pytorch#202206 removed
the Windows preload of torch\lib\*.dll that used to make them resident, so
the lookup now searches PATH only. With no cuDNN on PATH the load fails
(the CI failure); with another cuDNN on PATH the wrong version is picked
(reproduced locally: front DLL 9.27 from torch\lib, cudnn_graph64_9.dll
9.25 from PATH -> "compiled against 9.27 but found runtime 9.25").
Preloading torch\lib\cudnn*.dll by full path fixed both cases locally.

Fix: after the venv is activated, resolve torch's package directory from
the active interpreter (find_spec, no import) and prepend its lib dir to
PATH before run_test.py starts. This works for any venv or conda env, not
only C:\ci\woa\scratch\venv. A PATH prepend is the smallest change; the
alternatives (SetDllDirectory, a lazy C++ preload, cuDNN pip wheels) need
changes in torch itself and are better done upstream.

Test Plan:
  Parsed both scripts with the PowerShell AST parser (0 errors).
  Exercised Add-TorchLibToPath against a stub torch package on PYTHONPATH:
  it returned <stub>\torch\lib and put it first on PATH.
  Not yet run on a WoA runner; verify with a test shard that the cuDNN
  tests (e.g. test_cpp_api_parity, test_cuda) no longer crash.

Authored with an AI assistant (Claude Code); reviewed by the committer.

Co-authored-by: nkhasbag <[email protected]>
Co-authored-by: Claude Sonnet 5.5 <[email protected]>
pytorchmergebot pushed a commit that referenced this pull request Nov 7, 2026
## Linked issue or supporting maintainer

Fixes #203660
Fixes: #203725

## Summary (human written only)

Since #202206 removed the preload of every DLL in torch\lib, Windows wheels that bundle cuDNN crash on first cuDNN use when no cuDNN is on PATH with error Invalid handle. Cannot load symbol cudnnGetVersion and the process exits with 0xC0000409.

This hit every CUDA test shard of NVIDIA's [Windows on Arm CI](https://github.com/NVIDIA/pytorch-windows-ci/actions/runs/41810565607/job/126556054590#step:20:181).

Windows x86 CI did not run into this failure because those workflows follow upstream and prepend $PATH with cuda and cudnn path. This is ok for CI workflows but should not become a requirement for developers when using torch wheels.

This PR restores a cuDNN-only preload without bringing back #199894

## Agent details (if applicable)

> Drafted with Claude Code; I reviewed the change and ran the tests below.
>
> **Change:** at the end of `_load_dll_libraries()`, `LoadLibraryExW` each `torch\lib\cudnn*.dll` by full path with `LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR` (the flags the pre-#202206 loop used). A failed load emits a warning instead of raising.
>
> **Why no unit test:** the failure depends on process-wide DLL state and on PATH contents at process start; a meaningful test needs a fresh Windows process with cuDNN removed from PATH and a wheel that bundles cuDNN. Verified manually on Windows on Arm:
>
> ```
> where.exe cudnn64_9.dll   # not found
> python -c "import torch,torch.nn as nn; x=torch.randn(1,3,8,8,device='cuda'); print(nn.Conv2d(3,4,3).cuda()(x).shape)"
> ```
>
> - Before: `Invalid handle. Cannot load symbol cudnnGetVersion`, exit -1073740791
> - After: `torch.Size([1, 4, 6, 6])`, `torch.backends.cudnn.version() == 92600`, all 10 `cudnn*.dll` loaded from `torch\lib`; Conv2d+BatchNorm2d, 2-layer LSTM, and SDPA (`CUDNN_ATTENTION`) forward/backward pass, no preload warnings.
>

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Pull Request resolved: #203663
Approved by: https://github.com/atalman

Co-authored-by: Claude Opus 5.5 <[email protected]>
dominikjastrzebskix pushed a commit to dominikjastrzebskix/pytorch that referenced this pull request Nov 9, 2026
## Linked issue or supporting maintainer

Part of pytorch#199894. Supersedes pytorch#200856 and pytorch#199925: without the preload there is no list of test-only DLLs to maintain.

## BC-breaking?

No for the supported configurations. `import torch` no longer preloads every DLL in `torch/lib`; libraries that are loaded on demand are now loaded only on demand, and the `PATH` fallback for systems without `AddDllDirectory` (pre Windows 8 without KB2533623) is gone.

## Summary (human written only)

On Windows we are preloading all libraries in torch/lib. This is somewhat costly and leads to occasional problems. Furthermore, it is likely no longer necessary because the loading code has become smarter and is now able to load dependencies on demand. This PR is here to test that hypothesis in CI.

## Agent details (if applicable)

Analysis and change prepared with Claude Code, reviewed by me. The commit message carries the full reasoning. Agent notes:

The Windows loader has preloaded every DLL in `torch/lib` since pytorch#35362, because `caffe2_nvrtc.dll` was loaded by name from `CUDAHooks.cpp` and plain `LoadLibraryW` did not search directories registered with `AddDllDirectory`. Two later changes made that moot: pytorch#45674 (2020-10) switched CUDA builds to the in-tree LazyNVRTC, so `caffe2_nvrtc.dll` is only loaded by name on ROCm, and pytorch#49781 (2021-01) moved `at::DynamicLibrary` to `LoadLibraryExW` with `LOAD_LIBRARY_SEARCH_DEFAULT_DIRS`, which searches what `os.add_dll_directory` registers. Meanwhile the preload keeps turning on-demand libraries into import-time failures (pytorch#199894, pytorch#179024, pytorch#182123). The glob only ever preloaded torch's own DLLs with the default search flags; the NVIDIA wheel directories come from the cuda-pathfinder loop (and, on CI, from the toolkit bin dir fallback), which this PR does not touch.

Tested on hardware, since trunk has had no Windows CUDA test shards since pytorch#139336: Windows 11 VM with an RTX 2060 (driver 610.88), 2026-10-26 cu132 nightly wheel, `torch/__init__.py` replaced by this PR's version (hash-checked against the base commit). Results:

- With the stock cuda-pathfinder 1.8.4 the import fails on a clean machine with and without this change, for a reason outside this PR (below). The failure point moves from a `WinError 126` on `shm.dll` in the glob to "DLL load failed while importing _C".
- With a per-library `try` in the pathfinder loop (not part of this PR), import, `torch.cuda.is_available()`, cuDNN conv2d, cuBLAS matmul, cuFFT, cuRAND, cuSOLVER and a jiterator kernel (NVRTC) all pass with the glob removed. 8 of 13 `torch/lib` DLLs are resident afterwards; `caffe2_nvrtc`, `torch_global_deps`, `nvToolsExt64_1`, `libiompstubs5md` and `torch.dll` were never needed.
- The pytorch#199894 mechanism reproduces: a broken stray `zz_broken_test.dll` in `torch/lib` aborts `import torch` with the glob (WinError 193) and is ignored without it.

Found on the way, independent of this PR: the stock cu132 Windows nightly does not import on a clean machine. `nvidia-cuda-cupti` 13.2.86 ships `cupti64_2026.1.2.dll`, which cuda-pathfinder 1.8.4 does not know; the pathfinder loop in `torch/__init__.py` is one `try` around all eleven libraries, so the CUPTI miss also skips cuDNN, `nvidia\cudnn\bin` is never registered, and `cudnn64_9.dll` (a static import of `torch_python.dll` and `torch_cuda.dll`) cannot be found. CUPTI itself still resolves, because a later library in the loop registers the shared `nvidia\cu13\bin` directory. CI does not see this: the Windows CUDA wheel smoke test runs on a T4 with the CUDA toolkit and cuDNN installed under Program Files, and `torch/__init__.py` adds that directory to the search path. A per-library `try` fixes the import with a warning; a pathfinder release that knows the name fixes it silently.

CI on this PR: the full CPU suite on the 12 `win-vs2022-cpu-py3` shards, the `win-vs2022-cuda13.2-py3` build, and the `binaries_wheel` smoke tests for every Python version (CUDA wheels on a T4: import, CUDA tensor, magma, cuDNN, RNN and CNN smoke; XPU wheels import on CPU runners). Not covered: the full CUDA test suite on Windows.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Pull Request resolved: pytorch#202206
Approved by: https://github.com/atalman
dominikjastrzebskix pushed a commit to dominikjastrzebskix/pytorch that referenced this pull request Nov 9, 2026
## Linked issue or supporting maintainer

Fixes pytorch#203660
Fixes: pytorch#203725

## Summary (human written only)

Since pytorch#202206 removed the preload of every DLL in torch\lib, Windows wheels that bundle cuDNN crash on first cuDNN use when no cuDNN is on PATH with error Invalid handle. Cannot load symbol cudnnGetVersion and the process exits with 0xC0000409.

This hit every CUDA test shard of NVIDIA's [Windows on Arm CI](https://github.com/NVIDIA/pytorch-windows-ci/actions/runs/41810565607/job/126556054590#step:20:181).

Windows x86 CI did not run into this failure because those workflows follow upstream and prepend $PATH with cuda and cudnn path. This is ok for CI workflows but should not become a requirement for developers when using torch wheels.

This PR restores a cuDNN-only preload without bringing back pytorch#199894

## Agent details (if applicable)

> Drafted with Claude Code; I reviewed the change and ran the tests below.
>
> **Change:** at the end of `_load_dll_libraries()`, `LoadLibraryExW` each `torch\lib\cudnn*.dll` by full path with `LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR` (the flags the pre-pytorch#202206 loop used). A failed load emits a warning instead of raising.
>
> **Why no unit test:** the failure depends on process-wide DLL state and on PATH contents at process start; a meaningful test needs a fresh Windows process with cuDNN removed from PATH and a wheel that bundles cuDNN. Verified manually on Windows on Arm:
>
> ```
> where.exe cudnn64_9.dll   # not found
> python -c "import torch,torch.nn as nn; x=torch.randn(1,3,8,8,device='cuda'); print(nn.Conv2d(3,4,3).cuda()(x).shape)"
> ```
>
> - Before: `Invalid handle. Cannot load symbol cudnnGetVersion`, exit -1073740791
> - After: `torch.Size([1, 4, 6, 6])`, `torch.backends.cudnn.version() == 92600`, all 10 `cudnn*.dll` loaded from `torch\lib`; Conv2d+BatchNorm2d, 2-layer LSTM, and SDPA (`CUDNN_ATTENTION`) forward/backward pass, no preload warnings.
>

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Pull Request resolved: pytorch#203663
Approved by: https://github.com/atalman

Co-authored-by: Claude Opus 5.5 <[email protected]>

This branch was previously deployed

1 inactive deployment
bedrock — 6416904f Deployed Oct 29, 2026 by zklaus via analyze #17588
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ciflow/binaries_wheel Trigger binary build and upload jobs for wheel on the PR ciflow/trunk Trigger trunk jobs on your pull request Merged module: windows Windows support for PyTorch open source release notes: build release notes category topic: bug fixes topic category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants