Repository navigation
llm: set ROCm Tensile lib path - #15527
HEETMEHTA18 wants to merge 5 commits into
Conversation
Resolve rocBLAS Tensile path from bundled ROCm libs and pass it to the runner when unset. Add tests for path detection and env injection.
There was a problem hiding this comment.
Pull request overview
This PR makes ROCm runner startup more deterministic by locating the bundled rocBLAS Tensile library directory from gpuLibs and injecting Tensile-related env vars into the runner environment when they aren’t already provided, reducing noisy rocblaslt “Cannot read TensileLibrary…” warnings on gfx1200-class systems.
Changes:
- Add ROCm Tensile library path detection from common bundled ROCm layouts.
- Inject
ROCBLAS*_TENSILE_LIBPATH/HIPBLASLT_TENSILE_LIBPATHinto the runner env when not already set. - Add unit tests covering path detection and env injection / non-overwrite behavior.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| llm/server.go | Adds Tensile path detection and env injection during StartRunner. |
| llm/server_test.go | Adds unit tests validating Tensile path detection and env injection behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| for _, key := range []string{"ROCBLAS_TENSILE_LIBPATH", "ROCBLASLT_TENSILE_LIBPATH", "HIPBLASLT_TENSILE_LIBPATH"} { | ||
| if _, ok := os.LookupEnv(key); ok { | ||
| return extraEnvs | ||
| } | ||
| if extraEnvs != nil { | ||
| if _, ok := extraEnvs[key]; ok { | ||
| return extraEnvs | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if extraEnvs == nil { | ||
| extraEnvs = map[string]string{} | ||
| } | ||
|
|
||
| extraEnvs["ROCBLAS_TENSILE_LIBPATH"] = tensilePath | ||
| extraEnvs["ROCBLASLT_TENSILE_LIBPATH"] = tensilePath | ||
| extraEnvs["HIPBLASLT_TENSILE_LIBPATH"] = tensilePath | ||
|
|
There was a problem hiding this comment.
ensureRocmTensileEnv currently returns early if any of the Tensile env vars are set in the process env or extraEnvs, which means it will not inject the remaining vars when only one is provided. If (for example) ROCBLAS_TENSILE_LIBPATH is set but ROCBLASLT_TENSILE_LIBPATH is not, the rocBLASLt startup warning can still occur. Consider setting each of the three variables independently when it is not already present (leaving any explicitly provided values untouched).
| for _, key := range []string{"ROCBLAS_TENSILE_LIBPATH", "ROCBLASLT_TENSILE_LIBPATH", "HIPBLASLT_TENSILE_LIBPATH"} { | |
| if _, ok := os.LookupEnv(key); ok { | |
| return extraEnvs | |
| } | |
| if extraEnvs != nil { | |
| if _, ok := extraEnvs[key]; ok { | |
| return extraEnvs | |
| } | |
| } | |
| } | |
| if extraEnvs == nil { | |
| extraEnvs = map[string]string{} | |
| } | |
| extraEnvs["ROCBLAS_TENSILE_LIBPATH"] = tensilePath | |
| extraEnvs["ROCBLASLT_TENSILE_LIBPATH"] = tensilePath | |
| extraEnvs["HIPBLASLT_TENSILE_LIBPATH"] = tensilePath | |
| if extraEnvs == nil { | |
| extraEnvs = map[string]string{} | |
| } | |
| for _, key := range []string{"ROCBLAS_TENSILE_LIBPATH", "ROCBLASLT_TENSILE_LIBPATH", "HIPBLASLT_TENSILE_LIBPATH"} { | |
| if _, ok := os.LookupEnv(key); ok { | |
| continue | |
| } | |
| if _, ok := extraEnvs[key]; ok { | |
| continue | |
| } | |
| extraEnvs[key] = tensilePath | |
| } |
| t.Run("do not override explicit extra env", func(t *testing.T) { | ||
| in := map[string]string{"ROCBLASLT_TENSILE_LIBPATH": "/custom/path"} | ||
| envs := ensureRocmTensileEnv([]string{root}, in) | ||
| if envs["ROCBLASLT_TENSILE_LIBPATH"] != "/custom/path" { | ||
| t.Fatalf("ROCBLASLT_TENSILE_LIBPATH = %q, want /custom/path", envs["ROCBLASLT_TENSILE_LIBPATH"]) | ||
| } | ||
| if _, ok := envs["ROCBLAS_TENSILE_LIBPATH"]; ok { | ||
| t.Fatalf("ROCBLAS_TENSILE_LIBPATH should not be injected when explicit env is set") | ||
| } | ||
| }) |
There was a problem hiding this comment.
The test case "do not override explicit extra env" asserts that no other Tensile env vars are injected when one (ROCBLASLT_TENSILE_LIBPATH) is explicitly set. If the intended behavior is to inject only the missing vars (without overriding the explicitly-set one), this test should be updated to expect injection of the other keys rather than blocking all injection.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if _, ok := os.LookupEnv(key); ok { | ||
| continue | ||
| } | ||
| if extraEnvs != nil { | ||
| if _, ok := extraEnvs[key]; ok { |
There was a problem hiding this comment.
ensureRocmTensileEnv treats an environment variable as “set” purely based on os.LookupEnv. If any of these vars exist but are an empty string (common in some service/unit configs), the helper will skip injection and the rocBLASLt relative lookup noise can still occur. Consider treating empty values as unset (e.g., check val != "" for both process env and extraEnvs).
| if _, ok := os.LookupEnv(key); ok { | |
| continue | |
| } | |
| if extraEnvs != nil { | |
| if _, ok := extraEnvs[key]; ok { | |
| if val, ok := os.LookupEnv(key); ok && val != "" { | |
| continue | |
| } | |
| if extraEnvs != nil { | |
| if val, ok := extraEnvs[key]; ok && val != "" { |
| t.Run("inject when unset", func(t *testing.T) { | ||
| envs := ensureRocmTensileEnv([]string{root}, nil) | ||
| if envs["ROCBLAS_TENSILE_LIBPATH"] != tensile { | ||
| t.Fatalf("ROCBLAS_TENSILE_LIBPATH = %q, want %q", envs["ROCBLAS_TENSILE_LIBPATH"], tensile) | ||
| } | ||
| if envs["ROCBLASLT_TENSILE_LIBPATH"] != tensile { | ||
| t.Fatalf("ROCBLASLT_TENSILE_LIBPATH = %q, want %q", envs["ROCBLASLT_TENSILE_LIBPATH"], tensile) | ||
| } | ||
| if envs["HIPBLASLT_TENSILE_LIBPATH"] != tensile { | ||
| t.Fatalf("HIPBLASLT_TENSILE_LIBPATH = %q, want %q", envs["HIPBLASLT_TENSILE_LIBPATH"], tensile) | ||
| } | ||
| }) |
There was a problem hiding this comment.
These subtests assume ROCBLAS*_TENSILE_LIBPATH/HIPBLASLT_TENSILE_LIBPATH are unset in the parent process. On ROCm CI runners (or developer machines) they may already be set, causing the “inject when unset” assertions to fail. Make the test hermetic by explicitly clearing those env vars for the subtest (e.g., unset with cleanup, or set to empty if the helper treats empty-as-unset).
|
@HEETMEHTA18 Thanks for working on this — the underlying issue (#15452) is real and worth addressing. One thing worth noting: However, the root cause of the missing |
|
@slojosic-amd Okaay ! I understood your reply.
I could re work on this pr and revert the previous made change and add the right changes into this pr. |
|
@slojosic-amd i have added the changes in the CMakeList.txt with adding the required library to install to solve the issue and reverted all the old env changes which where temporary changes which i thought it would work but now this should be working now as from the ref of #14979. |
Resolve rocBLAS Tensile path from bundled ROCm libs and pass it to the runner when unset. Add tests for path detection and env injection. rocblaslt error: Cannot read "TensileLibrary_lazy_gfx1200.dat": No such file or directory #15452
Summary
Fix ROCm Tensile library path resolution for runner startup on gfx1200-class systems.
On some ROCm setups,
rocBLASLtfirst attempts a relative lookup forTensileLibrary_lazy_gfx1200.dat, logs a "No such fileor directory" warning, and then falls back to an absolute path. Inference may still work, but startup is noisy and path
resolution is fragile.
This patch makes lookup deterministic by resolving the Tensile library directory from
gpuLibsand setting env vars at runnerstartup when they are not already provided.
Changes
llm/server.go:findRocmTensileLibraryPath(gpuLibs []string) stringensureRocmTensileEnv(gpuLibs []string, extraEnvs map[string]string) map[string]stringensureRocmTensileEnv(...)inStartRunner(...)before environment assemblyROCBLAS_TENSILE_LIBPATHROCBLASLT_TENSILE_LIBPATHHIPBLASLT_TENSILE_LIBPATH<lib>/rocblas/library<lib>/rocm/rocblas/libraryTests
Added unit tests in
llm/server_test.gofor:Why this change
This addresses path-resolution fragility behind issue #15452 and removes noisy false-negative file lookup behavior in runner
startup.
Compatibility
Closes #15452