2023-11-29 19:00:37 +00:00
//go:build linux || windows
package gpu
/ *
2023-12-14 01:26:47 +00:00
# cgo linux LDFLAGS : - lrt - lpthread - ldl - lstdc ++ - lm
# cgo windows LDFLAGS : - lpthread
2023-11-29 19:00:37 +00:00
# include "gpu_info.h"
* /
import "C"
import (
"fmt"
2024-01-18 18:52:01 +00:00
"log/slog"
2024-01-10 22:39:51 +00:00
"os"
"path/filepath"
2023-12-23 19:35:44 +00:00
"runtime"
2024-06-03 15:31:48 +00:00
"strconv"
2024-01-10 22:39:51 +00:00
"strings"
2023-11-29 19:00:37 +00:00
"sync"
"unsafe"
2024-03-18 09:45:22 +00:00
2024-06-03 15:31:48 +00:00
"github.com/ollama/ollama/envconfig"
2024-05-15 22:13:16 +00:00
"github.com/ollama/ollama/format"
2023-11-29 19:00:37 +00:00
)
type handles struct {
2024-03-30 16:50:05 +00:00
deviceCount int
cudart * C . cudart_handle_t
2024-04-30 23:42:48 +00:00
nvcuda * C . nvcuda_handle_t
2024-05-24 03:18:27 +00:00
oneapi * C . oneapi_handle_t
2023-11-29 19:00:37 +00:00
}
2024-03-18 09:45:22 +00:00
const (
2024-05-10 16:15:28 +00:00
cudaMinimumMemory = 457 * format . MebiByte
rocmMinimumMemory = 457 * format . MebiByte
2024-03-18 09:45:22 +00:00
)
2024-05-15 22:13:16 +00:00
var (
gpuMutex sync . Mutex
bootstrapped bool
cpuCapability CPUCapability
cpus [ ] CPUInfo
cudaGPUs [ ] CudaGPUInfo
nvcudaLibPath string
cudartLibPath string
oneapiLibPath string
rocmGPUs [ ] RocmGPUInfo
oneapiGPUs [ ] OneapiGPUInfo
)
2023-11-29 19:00:37 +00:00
2024-01-20 20:15:50 +00:00
// With our current CUDA compile flags, older than 5.0 will not work properly
var CudaComputeMin = [ 2 ] C . int { 5 , 0 }
2024-01-07 05:40:04 +00:00
2024-03-30 16:50:05 +00:00
var RocmComputeMin = 9
2024-01-10 22:39:51 +00:00
2024-03-30 16:50:05 +00:00
// TODO find a better way to detect iGPU instead of minimum memory
const IGPUMemLimit = 1 * format . GibiByte // 512G is what they typically report, so anything less than 1G must be iGPU
2024-01-10 22:39:51 +00:00
2024-03-25 15:07:44 +00:00
var CudartLinuxGlobs = [ ] string {
"/usr/local/cuda/lib64/libcudart.so*" ,
"/usr/lib/x86_64-linux-gnu/nvidia/current/libcudart.so*" ,
"/usr/lib/x86_64-linux-gnu/libcudart.so*" ,
"/usr/lib/wsl/lib/libcudart.so*" ,
"/usr/lib/wsl/drivers/*/libcudart.so*" ,
"/opt/cuda/lib64/libcudart.so*" ,
"/usr/local/cuda*/targets/aarch64-linux/lib/libcudart.so*" ,
"/usr/lib/aarch64-linux-gnu/nvidia/current/libcudart.so*" ,
"/usr/lib/aarch64-linux-gnu/libcudart.so*" ,
"/usr/local/cuda/lib*/libcudart.so*" ,
"/usr/lib*/libcudart.so*" ,
"/usr/local/lib*/libcudart.so*" ,
}
var CudartWindowsGlobs = [ ] string {
"c:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v*\\bin\\cudart64_*.dll" ,
}
2024-04-30 23:42:48 +00:00
var NvcudaLinuxGlobs = [ ] string {
"/usr/local/cuda*/targets/*/lib/libcuda.so*" ,
"/usr/lib/*-linux-gnu/nvidia/current/libcuda.so*" ,
"/usr/lib/*-linux-gnu/libcuda.so*" ,
"/usr/lib/wsl/lib/libcuda.so*" ,
"/usr/lib/wsl/drivers/*/libcuda.so*" ,
"/opt/cuda/lib*/libcuda.so*" ,
"/usr/local/cuda/lib*/libcuda.so*" ,
"/usr/lib*/libcuda.so*" ,
"/usr/local/lib*/libcuda.so*" ,
}
var NvcudaWindowsGlobs = [ ] string {
"c:\\windows\\system*\\nvcuda.dll" ,
}
2024-05-24 03:18:27 +00:00
var OneapiWindowsGlobs = [ ] string {
"c:\\Windows\\System32\\DriverStore\\FileRepository\\*\\ze_intel_gpu64.dll" ,
}
var OneapiLinuxGlobs = [ ] string {
"/usr/lib/x86_64-linux-gnu/libze_intel_gpu.so*" ,
"/usr/lib*/libze_intel_gpu.so*" ,
}
2024-03-25 15:07:44 +00:00
// Jetson devices have JETSON_JETPACK="x.y.z" factory set to the Jetpack version installed.
// Included to drive logic for reducing Ollama-allocated overhead on L4T/Jetson devices.
var CudaTegra string = os . Getenv ( "JETSON_JETPACK" )
2023-11-29 19:00:37 +00:00
// Note: gpuMutex must already be held
2024-05-15 22:13:16 +00:00
func initCudaHandles ( ) * handles {
2024-01-10 22:39:51 +00:00
2023-12-14 01:26:47 +00:00
// TODO - if the ollama build is CPU only, don't do these checks as they're irrelevant and confusing
2024-01-10 22:39:51 +00:00
2024-03-30 16:50:05 +00:00
gpuHandles := & handles { }
2024-05-15 22:13:16 +00:00
// Short Circuit if we already know which library to use
if nvcudaLibPath != "" {
gpuHandles . deviceCount , gpuHandles . nvcuda , _ = LoadNVCUDAMgmt ( [ ] string { nvcudaLibPath } )
return gpuHandles
}
if cudartLibPath != "" {
gpuHandles . deviceCount , gpuHandles . cudart , _ = LoadCUDARTMgmt ( [ ] string { cudartLibPath } )
return gpuHandles
}
slog . Debug ( "searching for GPU discovery libraries for NVIDIA" )
2024-03-25 15:07:44 +00:00
var cudartMgmtName string
var cudartMgmtPatterns [ ] string
2024-04-30 23:42:48 +00:00
var nvcudaMgmtName string
var nvcudaMgmtPatterns [ ] string
2024-06-03 15:31:48 +00:00
var oneapiMgmtName string
var oneapiMgmtPatterns [ ] string
2024-03-25 15:07:44 +00:00
tmpDir , _ := PayloadsDir ( )
2024-01-10 22:39:51 +00:00
switch runtime . GOOS {
case "windows" :
2024-03-25 15:07:44 +00:00
cudartMgmtName = "cudart64_*.dll"
localAppData := os . Getenv ( "LOCALAPPDATA" )
cudartMgmtPatterns = [ ] string { filepath . Join ( localAppData , "Programs" , "Ollama" , cudartMgmtName ) }
cudartMgmtPatterns = append ( cudartMgmtPatterns , CudartWindowsGlobs ... )
2024-04-30 23:42:48 +00:00
// Aligned with driver, we can't carry as payloads
nvcudaMgmtName = "nvcuda.dll"
nvcudaMgmtPatterns = NvcudaWindowsGlobs
2024-06-03 15:31:48 +00:00
oneapiMgmtName = "ze_intel_gpu64.dll"
oneapiMgmtPatterns = OneapiWindowsGlobs
2024-01-10 22:39:51 +00:00
case "linux" :
2024-03-25 15:07:44 +00:00
cudartMgmtName = "libcudart.so*"
if tmpDir != "" {
// TODO - add "payloads" for subprocess
cudartMgmtPatterns = [ ] string { filepath . Join ( tmpDir , "cuda*" , cudartMgmtName ) }
}
cudartMgmtPatterns = append ( cudartMgmtPatterns , CudartLinuxGlobs ... )
2024-04-30 23:42:48 +00:00
// Aligned with driver, we can't carry as payloads
nvcudaMgmtName = "libcuda.so*"
nvcudaMgmtPatterns = NvcudaLinuxGlobs
2024-06-03 15:31:48 +00:00
oneapiMgmtName = "libze_intel_gpu.so"
oneapiMgmtPatterns = OneapiLinuxGlobs
2024-01-10 22:39:51 +00:00
default :
2024-03-30 22:34:21 +00:00
return gpuHandles
2024-01-10 22:39:51 +00:00
}
2024-04-30 23:42:48 +00:00
nvcudaLibPaths := FindGPULibs ( nvcudaMgmtName , nvcudaMgmtPatterns )
if len ( nvcudaLibPaths ) > 0 {
deviceCount , nvcuda , libPath := LoadNVCUDAMgmt ( nvcudaLibPaths )
if nvcuda != nil {
2024-05-07 21:54:26 +00:00
slog . Debug ( "detected GPUs" , "count" , deviceCount , "library" , libPath )
2024-04-30 23:42:48 +00:00
gpuHandles . nvcuda = nvcuda
gpuHandles . deviceCount = deviceCount
2024-05-15 22:13:16 +00:00
nvcudaLibPath = libPath
2024-04-30 23:42:48 +00:00
return gpuHandles
}
}
2024-03-25 15:07:44 +00:00
cudartLibPaths := FindGPULibs ( cudartMgmtName , cudartMgmtPatterns )
if len ( cudartLibPaths ) > 0 {
2024-03-30 16:50:05 +00:00
deviceCount , cudart , libPath := LoadCUDARTMgmt ( cudartLibPaths )
2024-03-25 15:07:44 +00:00
if cudart != nil {
2024-05-07 21:54:26 +00:00
slog . Debug ( "detected GPUs" , "library" , libPath , "count" , deviceCount )
2024-03-25 15:07:44 +00:00
gpuHandles . cudart = cudart
2024-03-30 16:50:05 +00:00
gpuHandles . deviceCount = deviceCount
2024-05-15 22:13:16 +00:00
cudartLibPath = libPath
2024-03-30 22:34:21 +00:00
return gpuHandles
2024-03-25 15:07:44 +00:00
}
}
2024-05-24 03:18:27 +00:00
2024-06-03 15:31:48 +00:00
oneapiLibPaths := FindGPULibs ( oneapiMgmtName , oneapiMgmtPatterns )
if len ( oneapiLibPaths ) > 0 {
deviceCount , oneapi , libPath := LoadOneapiMgmt ( oneapiLibPaths )
if oneapi != nil {
slog . Debug ( "detected Intel GPUs" , "library" , libPath , "count" , deviceCount )
gpuHandles . oneapi = oneapi
gpuHandles . deviceCount = deviceCount
2024-05-15 22:13:16 +00:00
oneapiLibPath = libPath
2024-06-03 15:31:48 +00:00
return gpuHandles
}
}
2024-03-30 22:34:21 +00:00
return gpuHandles
2023-11-29 19:00:37 +00:00
}
2024-03-30 16:50:05 +00:00
func GetGPUInfo ( ) GpuInfoList {
2023-11-29 19:00:37 +00:00
// TODO - consider exploring lspci (and equivalent on windows) to check for
// GPUs so we can report warnings if we see Nvidia/AMD but fail to load the libraries
gpuMutex . Lock ( )
defer gpuMutex . Unlock ( )
2024-05-15 22:13:16 +00:00
needRefresh := true
var gpuHandles * handles
2024-03-30 22:34:21 +00:00
defer func ( ) {
2024-05-15 22:13:16 +00:00
if gpuHandles == nil {
return
}
2024-03-30 22:34:21 +00:00
if gpuHandles . cudart != nil {
C . cudart_release ( * gpuHandles . cudart )
}
2024-04-30 23:42:48 +00:00
if gpuHandles . nvcuda != nil {
C . nvcuda_release ( * gpuHandles . nvcuda )
}
2024-03-30 22:34:21 +00:00
} ( )
2023-11-29 19:00:37 +00:00
2024-05-15 22:13:16 +00:00
if ! bootstrapped {
slog . Debug ( "Detecting GPUs" )
needRefresh = false
cpuCapability = getCPUCapability ( )
var memInfo C . mem_info_t
C . cpu_check_ram ( & memInfo )
if memInfo . err != nil {
slog . Info ( "error looking up CPU memory" , "error" , C . GoString ( memInfo . err ) )
C . free ( unsafe . Pointer ( memInfo . err ) )
return [ ] GpuInfo { }
}
cpuInfo := CPUInfo {
GpuInfo : GpuInfo {
Library : "cpu" ,
Variant : cpuCapability . ToVariant ( ) ,
} ,
}
cpuInfo . TotalMemory = uint64 ( memInfo . total )
cpuInfo . FreeMemory = uint64 ( memInfo . free )
cpuInfo . ID = C . GoString ( & memInfo . gpu_id [ 0 ] )
cpus = [ ] CPUInfo { cpuInfo }
// Fallback to CPU mode if we're lacking required vector extensions on x86
if cpuCapability < GPURunnerCPUCapability && runtime . GOARCH == "amd64" {
slog . Warn ( "CPU does not have minimum vector extensions, GPU inference disabled" , "required" , GPURunnerCPUCapability . ToString ( ) , "detected" , cpuCapability . ToString ( ) )
bootstrapped = true
// No need to do any GPU discovery, since we can't run on them
return GpuInfoList { cpus [ 0 ] . GpuInfo }
}
2024-01-26 19:11:09 +00:00
2024-05-15 22:13:16 +00:00
// On windows we bundle the nvidia library one level above the runner dir
depPath := ""
if runtime . GOOS == "windows" && envconfig . RunnersDir != "" {
depPath = filepath . Dir ( envconfig . RunnersDir )
2024-03-25 15:07:44 +00:00
}
2024-05-15 22:13:16 +00:00
// Load ALL libraries
gpuHandles = initCudaHandles ( )
// TODO needs a refactoring pass to init oneapi handles
// NVIDIA
for i := range gpuHandles . deviceCount {
if gpuHandles . cudart != nil || gpuHandles . nvcuda != nil {
gpuInfo := CudaGPUInfo {
GpuInfo : GpuInfo {
Library : "cuda" ,
} ,
index : i ,
}
var driverMajor int
var driverMinor int
if gpuHandles . cudart != nil {
C . cudart_bootstrap ( * gpuHandles . cudart , C . int ( i ) , & memInfo )
} else {
C . nvcuda_bootstrap ( * gpuHandles . nvcuda , C . int ( i ) , & memInfo )
driverMajor = int ( gpuHandles . nvcuda . driver_major )
driverMinor = int ( gpuHandles . nvcuda . driver_minor )
}
if memInfo . err != nil {
slog . Info ( "error looking up nvidia GPU memory" , "error" , C . GoString ( memInfo . err ) )
C . free ( unsafe . Pointer ( memInfo . err ) )
continue
}
if memInfo . major < CudaComputeMin [ 0 ] || ( memInfo . major == CudaComputeMin [ 0 ] && memInfo . minor < CudaComputeMin [ 1 ] ) {
slog . Info ( fmt . Sprintf ( "[%d] CUDA GPU is too old. Compute Capability detected: %d.%d" , i , memInfo . major , memInfo . minor ) )
continue
}
gpuInfo . TotalMemory = uint64 ( memInfo . total )
gpuInfo . FreeMemory = uint64 ( memInfo . free )
gpuInfo . ID = C . GoString ( & memInfo . gpu_id [ 0 ] )
gpuInfo . Compute = fmt . Sprintf ( "%d.%d" , memInfo . major , memInfo . minor )
gpuInfo . MinimumMemory = cudaMinimumMemory
gpuInfo . DependencyPath = depPath
gpuInfo . Name = C . GoString ( & memInfo . gpu_name [ 0 ] )
gpuInfo . DriverMajor = int ( driverMajor )
gpuInfo . DriverMinor = int ( driverMinor )
// TODO potentially sort on our own algorithm instead of what the underlying GPU library does...
cudaGPUs = append ( cudaGPUs , gpuInfo )
2024-05-24 03:18:27 +00:00
}
2024-05-15 22:13:16 +00:00
if gpuHandles . oneapi != nil {
gpuInfo := OneapiGPUInfo {
GpuInfo : GpuInfo {
Library : "oneapi" ,
} ,
index : i ,
}
// TODO - split bootstrapping from updating free memory
C . oneapi_check_vram ( * gpuHandles . oneapi , & memInfo )
var totalFreeMem float64 = float64 ( memInfo . free ) * 0.95 // work-around: leave some reserve vram for mkl lib used in ggml-sycl backend.
memInfo . free = C . uint64_t ( totalFreeMem )
gpuInfo . TotalMemory = uint64 ( memInfo . total )
gpuInfo . FreeMemory = uint64 ( memInfo . free )
gpuInfo . ID = strconv . Itoa ( i )
oneapiGPUs = append ( oneapiGPUs , gpuInfo )
}
}
rocmGPUs = AMDGetGPUInfo ( )
bootstrapped = true
}
// For detected GPUs, load library if not loaded
// Refresh free memory usage
if needRefresh {
// TODO - CPU system memory tracking/refresh
var memInfo C . mem_info_t
if gpuHandles == nil && len ( cudaGPUs ) > 0 {
gpuHandles = initCudaHandles ( )
}
for i , gpu := range cudaGPUs {
2024-05-24 03:18:27 +00:00
if gpuHandles . cudart != nil {
2024-05-15 22:13:16 +00:00
C . cudart_bootstrap ( * gpuHandles . cudart , C . int ( gpu . index ) , & memInfo )
2024-05-24 03:18:27 +00:00
} else {
2024-05-15 22:13:16 +00:00
C . nvcuda_get_free ( * gpuHandles . nvcuda , C . int ( gpu . index ) , & memInfo . free )
2024-05-24 03:18:27 +00:00
}
if memInfo . err != nil {
2024-05-15 22:13:16 +00:00
slog . Warn ( "error looking up nvidia GPU memory" , "error" , C . GoString ( memInfo . err ) )
2024-05-24 03:18:27 +00:00
C . free ( unsafe . Pointer ( memInfo . err ) )
continue
}
2024-05-15 22:13:16 +00:00
if memInfo . free == 0 {
slog . Warn ( "error looking up nvidia GPU memory" )
2024-05-24 03:18:27 +00:00
continue
}
2024-05-15 22:13:16 +00:00
slog . Debug ( "updating cuda free memory" , "gpu" , gpu . ID , "name" , gpu . Name , "before" , format . HumanBytes2 ( gpu . FreeMemory ) , "now" , format . HumanBytes2 ( uint64 ( memInfo . free ) ) )
cudaGPUs [ i ] . FreeMemory = uint64 ( memInfo . free )
2023-12-14 01:26:47 +00:00
}
2024-05-15 22:13:16 +00:00
err := RocmGPUInfoList ( rocmGPUs ) . RefreshFreeMemory ( )
if err != nil {
slog . Debug ( "problem refreshing ROCm free memory" , "error" , err )
2024-06-03 15:31:48 +00:00
}
2023-12-14 01:26:47 +00:00
}
2024-03-30 16:50:05 +00:00
2024-05-15 22:13:16 +00:00
resp := [ ] GpuInfo { }
for _ , gpu := range cudaGPUs {
resp = append ( resp , gpu . GpuInfo )
}
for _ , gpu := range rocmGPUs {
resp = append ( resp , gpu . GpuInfo )
}
2024-03-30 16:50:05 +00:00
if len ( resp ) == 0 {
2024-05-15 22:13:16 +00:00
resp = append ( resp , cpus [ 0 ] . GpuInfo )
2023-11-29 19:00:37 +00:00
}
return resp
}
2024-03-30 16:50:05 +00:00
func GetCPUMem ( ) ( memInfo , error ) {
2023-12-22 23:43:31 +00:00
var ret memInfo
var info C . mem_info_t
C . cpu_check_ram ( & info )
if info . err != nil {
defer C . free ( unsafe . Pointer ( info . err ) )
return ret , fmt . Errorf ( C . GoString ( info . err ) )
}
ret . FreeMemory = uint64 ( info . free )
ret . TotalMemory = uint64 ( info . total )
return ret , nil
}
2024-04-30 23:42:48 +00:00
func FindGPULibs ( baseLibName string , defaultPatterns [ ] string ) [ ] string {
2024-01-10 22:39:51 +00:00
// Multiple GPU libraries may exist, and some may not work, so keep trying until we exhaust them
var ldPaths [ ] string
2024-04-30 23:42:48 +00:00
var patterns [ ] string
2024-01-10 22:39:51 +00:00
gpuLibPaths := [ ] string { }
2024-03-30 16:50:05 +00:00
slog . Debug ( "Searching for GPU library" , "name" , baseLibName )
2024-01-10 22:39:51 +00:00
switch runtime . GOOS {
case "windows" :
ldPaths = strings . Split ( os . Getenv ( "PATH" ) , ";" )
case "linux" :
ldPaths = strings . Split ( os . Getenv ( "LD_LIBRARY_PATH" ) , ":" )
default :
return gpuLibPaths
}
// Start with whatever we find in the PATH/LD_LIBRARY_PATH
for _ , ldPath := range ldPaths {
d , err := filepath . Abs ( ldPath )
if err != nil {
continue
}
patterns = append ( patterns , filepath . Join ( d , baseLibName + "*" ) )
}
2024-04-30 23:42:48 +00:00
patterns = append ( patterns , defaultPatterns ... )
2024-03-30 16:50:05 +00:00
slog . Debug ( "gpu library search" , "globs" , patterns )
2024-01-10 22:39:51 +00:00
for _ , pattern := range patterns {
2024-05-03 18:55:32 +00:00
// Nvidia PhysX known to return bogus results
if strings . Contains ( pattern , "PhysX" ) {
slog . Debug ( "skipping PhysX cuda library path" , "path" , pattern )
2024-06-13 20:17:19 +00:00
continue
2024-05-03 18:55:32 +00:00
}
2024-01-10 22:39:51 +00:00
// Ignore glob discovery errors
matches , _ := filepath . Glob ( pattern )
for _ , match := range matches {
// Resolve any links so we don't try the same lib multiple times
// and weed out any dups across globs
libPath := match
tmp := match
var err error
for ; err == nil ; tmp , err = os . Readlink ( libPath ) {
if ! filepath . IsAbs ( tmp ) {
tmp = filepath . Join ( filepath . Dir ( libPath ) , tmp )
}
libPath = tmp
}
new := true
for _ , cmp := range gpuLibPaths {
if cmp == libPath {
new = false
break
}
}
if new {
gpuLibPaths = append ( gpuLibPaths , libPath )
}
}
}
2024-03-30 16:50:05 +00:00
slog . Debug ( "discovered GPU libraries" , "paths" , gpuLibPaths )
2024-01-10 22:39:51 +00:00
return gpuLibPaths
}
2024-03-30 16:50:05 +00:00
func LoadCUDARTMgmt ( cudartLibPaths [ ] string ) ( int , * C . cudart_handle_t , string ) {
2024-03-25 15:07:44 +00:00
var resp C . cudart_init_resp_t
2024-01-23 00:03:32 +00:00
resp . ch . verbose = getVerboseState ( )
2024-03-25 15:07:44 +00:00
for _ , libPath := range cudartLibPaths {
2024-01-10 22:39:51 +00:00
lib := C . CString ( libPath )
defer C . free ( unsafe . Pointer ( lib ) )
2024-03-25 15:07:44 +00:00
C . cudart_init ( lib , & resp )
2024-01-10 22:39:51 +00:00
if resp . err != nil {
2024-03-30 16:50:05 +00:00
slog . Debug ( "Unable to load cudart" , "library" , libPath , "error" , C . GoString ( resp . err ) )
2024-01-10 22:39:51 +00:00
C . free ( unsafe . Pointer ( resp . err ) )
} else {
2024-03-30 16:50:05 +00:00
return int ( resp . num_devices ) , & resp . ch , libPath
2024-01-10 22:39:51 +00:00
}
}
2024-03-30 16:50:05 +00:00
return 0 , nil , ""
2024-01-10 22:39:51 +00:00
}
2024-04-30 23:42:48 +00:00
func LoadNVCUDAMgmt ( nvcudaLibPaths [ ] string ) ( int , * C . nvcuda_handle_t , string ) {
var resp C . nvcuda_init_resp_t
resp . ch . verbose = getVerboseState ( )
for _ , libPath := range nvcudaLibPaths {
lib := C . CString ( libPath )
defer C . free ( unsafe . Pointer ( lib ) )
C . nvcuda_init ( lib , & resp )
if resp . err != nil {
slog . Debug ( "Unable to load nvcuda" , "library" , libPath , "error" , C . GoString ( resp . err ) )
C . free ( unsafe . Pointer ( resp . err ) )
} else {
return int ( resp . num_devices ) , & resp . ch , libPath
}
}
return 0 , nil , ""
}
2024-05-24 03:18:27 +00:00
func LoadOneapiMgmt ( oneapiLibPaths [ ] string ) ( int , * C . oneapi_handle_t , string ) {
var resp C . oneapi_init_resp_t
resp . oh . verbose = getVerboseState ( )
for _ , libPath := range oneapiLibPaths {
lib := C . CString ( libPath )
defer C . free ( unsafe . Pointer ( lib ) )
C . oneapi_init ( lib , & resp )
if resp . err != nil {
slog . Debug ( "Unable to load oneAPI management library" , "library" , libPath , "error" , C . GoString ( resp . err ) )
C . free ( unsafe . Pointer ( resp . err ) )
} else {
return int ( resp . num_devices ) , & resp . oh , libPath
}
}
return 0 , nil , ""
}
2024-01-23 00:03:32 +00:00
func getVerboseState ( ) C . uint16_t {
2024-05-04 18:46:01 +00:00
if envconfig . Debug {
2024-01-23 00:03:32 +00:00
return C . uint16_t ( 1 )
}
return C . uint16_t ( 0 )
}
2024-03-30 16:50:05 +00:00
// Given the list of GPUs this instantiation is targeted for,
// figure out the visible devices environment variable
//
// If different libraries are detected, the first one is what we use
func ( l GpuInfoList ) GetVisibleDevicesEnv ( ) ( string , string ) {
if len ( l ) == 0 {
return "" , ""
}
switch l [ 0 ] . Library {
case "cuda" :
return cudaGetVisibleDevicesEnv ( l )
case "rocm" :
return rocmGetVisibleDevicesEnv ( l )
2024-05-24 03:18:27 +00:00
case "oneapi" :
return oneapiGetVisibleDevicesEnv ( l )
2024-03-30 16:50:05 +00:00
default :
slog . Debug ( "no filter required for library " + l [ 0 ] . Library )
return "" , ""
}
}