Fix cuDNN 9 libraries not being preloaded on Windows CUDA builds - #3873
Open
gijreyneveld wants to merge 2 commits into
Open
Fix cuDNN 9 libraries not being preloaded on Windows CUDA builds#3873gijreyneveld wants to merge 2 commits into
gijreyneveld wants to merge 2 commits into
Conversation
This was referenced Aug 22, 2026
There was a problem hiding this comment.
Pull request overview
This PR addresses Windows CUDA initialization failures for the PyTorch engine by ensuring cuDNN 9 DLLs are preloaded before torch_cuda.dll, and by fixing the Gradle test PATH setup so Windows tests can reproduce and catch the issue.
Changes:
- Extend
LibUtils.loadLibTorch()to preload cuDNN 9 DLLs (ahead of existing cuDNN 8/7 handling) on Windows. - Update
pytorch-engineGradle test configuration to correctly constructPATHon Windows by reading the inherited environment viaSystem.getenv("PATH").
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/jni/LibUtils.java | Adds explicit cuDNN 9 preload sequence to avoid torch_cuda.dll dependency failures on Windows CUDA builds. |
| engines/pytorch/pytorch-engine/build.gradle.kts | Adjusts test worker PATH setup to avoid losing the inherited Windows PATH due to case-sensitive Gradle environment map lookup. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
30
to
32
| test { | ||
| environment("PATH" to "src/test/bin:${environment["PATH"]}") | ||
| environment("PATH", "src/test/bin;${System.getenv("PATH")}") | ||
| } |
Comment on lines
+173
to
+182
| if (Files.exists((libDir.resolve("cudnn64_9.dll")))) { | ||
| loadNativeLibrary(libDir.resolve("cudnn_graph64_9.dll").toString()); | ||
| loadNativeLibrary(libDir.resolve("cudnn_engines_precompiled64_9.dll").toString()); | ||
| loadNativeLibrary(libDir.resolve("cudnn_engines_runtime_compiled64_9.dll").toString()); | ||
| loadNativeLibrary(libDir.resolve("cudnn_heuristic64_9.dll").toString()); | ||
| loadNativeLibrary(libDir.resolve("cudnn_ops64_9.dll").toString()); | ||
| loadNativeLibrary(libDir.resolve("cudnn_cnn64_9.dll").toString()); | ||
| loadNativeLibrary(libDir.resolve("cudnn_adv64_9.dll").toString()); | ||
| loadNativeLibrary(libDir.resolve("cudnn64_9.dll").toString()); | ||
| } else if (Files.exists((libDir.resolve("cudnn64_8.dll")))) { |
Contributor
|
@gijreyneveld Thanks for the contribution! Could you please take care of the review comments and fix CI? |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
I use an open-source desktop application for bioimage analysis (QuPath) that depends on DJL for GPU inference.
Our community has been struggling to set this up, because libraries are somehow not pre-loaded (
torch_cuda.dllUnsatisfiedLinkError).We made a workaround to add a directory that supplies the DJL chache directory to
PATHbefore launching, (or sometimes a conda environment). However, I wanted to find the root cause of this so that we might make the GPU inference in our application more user friendly. This is what I found;LibUtils.loadLibTorch()walks the native library directory and explicitly skips every cuDNN file (so not everything as we first expected):cuDNN is then instead preloaded separately, by hardcoded filename;
However, it is only compatible with cuDNN6 v7 and cuDNN v8, whereas the
cu128/win-x86_64bundle for PyTorch 2.7.1 that DJL 0.36.0 downloads comes with cuDNN 9. Therefore, it matches nothing and the files are passed over a second time and thentorch_cuda.dlloads with nothing behind it.I made the edit to hardcode cuDNN9 and tested it with the desktop application and the command line. I had to tweak
build.gradle.ktsto reproduce it in the command line, see second change below.Longer term, cuDNN version 10 will run into the same thing. Something version-agnostic would avoid that, though I didn't want to change the loading behaviour of the existing cuDNN 8/7 paths without understanding why the explicit ordering of cuDNN 8 and 7 is there.
Changes
1.
LibUtils.loadLibTorch()— adds a cuDNN 9 branch ahead of the existing cuDNN 8 / 7 checks. The older version paths are unchanged. After patching this locally and rebuildingpytorch-engine, the PyTorch engine initialises with CUDA and GPU inference runs with noPATHchanges at all. Verified on two Windows machines with CUDA 12.8 and from command line2.
engines/pytorch/pytorch-engine/build.gradle.kts— this was needed in order to reproduce the above from the command line on Windows. I didn't pro-actively think about making this piece system-agnostic, so it can be a separate thing.The test task sets
PATHlike this:Gradle's environment map is case-sensitive, but the inherited Windows variable is named
Path. Soenvironment["PATH"]is null and interpolates as the literal string"null", andPATHgets added as a second key alongsidePath. Windowsis case-insensitive when creating the process and uses
PATH. DumpingSystem.getenv()from inside a test worker shows:So test workers on Windows run with no usable
PATH, and CUDA loading fails atcublas64_12.dlllong before it ever reaches the cuDNN code. Maybe this is why the issue above was never caught by the Windows tests?System.getenv("PATH")looks up case-insensitively and returns the goodPathvalue, so this is invisible from inside Java unless you dump the raw keys.Change sets
PATHwith the;separator. It leaves the duplicatePathkey in place.Reproduction
Windows, CUDA 12.8, with no directory on
PATHsupplying cuDNN. Change 2 is needed for the test to get far enough to show the bug.Before — note there is no
cudnn*line anywhere in the sequence:After — the cuDNN 9 libraries load and initialisation completes:
Related issues
#3480 reports the same error on 2.4.0-cu124. There's no load log attached so I can't confirm it, but the workaround that resolved it there was adding the DJL cache directory to
PATH.#3740 same problem as the log shows DJL downloading all eight cuDNN 9 files and then not loading any of them before
torch_cuda.dllfails. Here, adding the DJL cache directoryPATHresolved it as well.Notes
checkstyleMainpasses but couldn't runformatJava