amd_common.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. //go:build linux || windows
  2. package gpu
  3. import (
  4. "fmt"
  5. "log/slog"
  6. "os"
  7. "path/filepath"
  8. "runtime"
  9. "strings"
  10. )
  11. // Determine if the given ROCm lib directory is usable by checking for existence of some glob patterns
  12. func rocmLibUsable(libDir string) bool {
  13. slog.Debug("evaluating potential rocm lib dir " + libDir)
  14. for _, g := range ROCmLibGlobs {
  15. res, _ := filepath.Glob(filepath.Join(libDir, g))
  16. if len(res) == 0 {
  17. return false
  18. }
  19. }
  20. return true
  21. }
  22. func GetSupportedGFX(libDir string) ([]string, error) {
  23. var ret []string
  24. files, err := filepath.Glob(filepath.Join(libDir, "rocblas", "library", "TensileLibrary_lazy_gfx*.dat"))
  25. if err != nil {
  26. return nil, err
  27. }
  28. for _, file := range files {
  29. ret = append(ret, strings.TrimSuffix(strings.TrimPrefix(filepath.Base(file), "TensileLibrary_lazy_"), ".dat"))
  30. }
  31. return ret, nil
  32. }
  33. func rocmGetVisibleDevicesEnv(gpuInfo []GpuInfo) (string, string) {
  34. ids := []string{}
  35. for _, info := range gpuInfo {
  36. if info.Library != "rocm" {
  37. // TODO shouldn't happen if things are wired correctly...
  38. slog.Debug("rocmGetVisibleDevicesEnv skipping over non-rocm device", "library", info.Library)
  39. continue
  40. }
  41. ids = append(ids, info.ID)
  42. }
  43. return "HIP_VISIBLE_DEVICES", strings.Join(ids, ",")
  44. }
  45. func commonAMDValidateLibDir() (string, error) {
  46. // We try to favor system paths first, so that we can wire up the subprocess to use
  47. // the system version. Only use our bundled version if the system version doesn't work
  48. // This gives users a more recovery options if versions have subtle problems at runtime
  49. // Prefer explicit HIP env var
  50. hipPath := os.Getenv("HIP_PATH")
  51. if hipPath != "" {
  52. hipLibDir := filepath.Join(hipPath, "bin")
  53. if rocmLibUsable(hipLibDir) {
  54. slog.Debug("detected ROCM via HIP_PATH=" + hipPath)
  55. return hipLibDir, nil
  56. }
  57. }
  58. // Scan the LD_LIBRARY_PATH or PATH
  59. pathEnv := "LD_LIBRARY_PATH"
  60. if runtime.GOOS == "windows" {
  61. pathEnv = "PATH"
  62. }
  63. paths := os.Getenv(pathEnv)
  64. for _, path := range filepath.SplitList(paths) {
  65. d, err := filepath.Abs(path)
  66. if err != nil {
  67. continue
  68. }
  69. if rocmLibUsable(d) {
  70. return d, nil
  71. }
  72. }
  73. // Well known location(s)
  74. for _, path := range RocmStandardLocations {
  75. if rocmLibUsable(path) {
  76. return path, nil
  77. }
  78. }
  79. // Installer payload location if we're running the installed binary
  80. exe, err := os.Executable()
  81. if err == nil {
  82. rocmTargetDir := filepath.Join(filepath.Dir(exe), "rocm")
  83. if rocmLibUsable(rocmTargetDir) {
  84. slog.Debug("detected ROCM next to ollama executable " + rocmTargetDir)
  85. return rocmTargetDir, nil
  86. }
  87. }
  88. return "", fmt.Errorf("no suitable rocm found, falling back to CPU")
  89. }