123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- package discover
- import (
- "bufio"
- "fmt"
- "os"
- "reflect"
- "regexp"
- "strings"
- "github.com/ollama/ollama/format"
- )
- var CudartGlobs = []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 NvmlGlobs = []string{}
- var NvcudaGlobs = []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 OneapiGlobs = []string{
- "/usr/lib/x86_64-linux-gnu/libze_intel_gpu.so*",
- "/usr/lib*/libze_intel_gpu.so*",
- }
- var (
- CudartMgmtName = "libcudart.so*"
- NvcudaMgmtName = "libcuda.so*"
- NvmlMgmtName = "" // not currently wired on linux
- OneapiMgmtName = "libze_intel_gpu.so*"
- )
- func GetCPUMem() (memInfo, error) {
- var mem memInfo
- var total, available, free, buffers, cached, freeSwap uint64
- f, err := os.Open("/proc/meminfo")
- if err != nil {
- return mem, err
- }
- defer f.Close()
- s := bufio.NewScanner(f)
- for s.Scan() {
- line := s.Text()
- switch {
- case strings.HasPrefix(line, "MemTotal:"):
- _, err = fmt.Sscanf(line, "MemTotal:%d", &total)
- case strings.HasPrefix(line, "MemAvailable:"):
- _, err = fmt.Sscanf(line, "MemAvailable:%d", &available)
- case strings.HasPrefix(line, "MemFree:"):
- _, err = fmt.Sscanf(line, "MemFree:%d", &free)
- case strings.HasPrefix(line, "Buffers:"):
- _, err = fmt.Sscanf(line, "Buffers:%d", &buffers)
- case strings.HasPrefix(line, "Cached:"):
- _, err = fmt.Sscanf(line, "Cached:%d", &cached)
- case strings.HasPrefix(line, "SwapFree:"):
- _, err = fmt.Sscanf(line, "SwapFree:%d", &freeSwap)
- default:
- continue
- }
- if err != nil {
- return mem, err
- }
- }
- mem.TotalMemory = total * format.KibiByte
- mem.FreeSwap = freeSwap * format.KibiByte
- if available > 0 {
- mem.FreeMemory = available * format.KibiByte
- } else {
- mem.FreeMemory = (free + buffers + cached) * format.KibiByte
- }
- return mem, nil
- }
- const CpuInfoFilename = "/proc/cpuinfo"
- type linuxCpuInfo struct {
- ID string `cpuinfo:"processor"`
- VendorID string `cpuinfo:"vendor_id"`
- ModelName string `cpuinfo:"model name"`
- PhysicalID string `cpuinfo:"physical id"`
- Siblings string `cpuinfo:"siblings"`
- CoreID string `cpuinfo:"core id"`
- }
- func GetCPUDetails() ([]CPU, error) {
- file, err := os.Open(CpuInfoFilename)
- if err != nil {
- return nil, err
- }
- reColumns := regexp.MustCompile("\t+: ")
- scanner := bufio.NewScanner(file)
- cpuInfos := []linuxCpuInfo{}
- cpu := &linuxCpuInfo{}
- for scanner.Scan() {
- line := scanner.Text()
- if sl := reColumns.Split(line, 2); len(sl) > 1 {
- t := reflect.TypeOf(cpu).Elem()
- s := reflect.ValueOf(cpu).Elem()
- for i := range t.NumField() {
- field := t.Field(i)
- tag := field.Tag.Get("cpuinfo")
- if tag == sl[0] {
- s.FieldByName(field.Name).SetString(sl[1])
- break
- }
- }
- } else if strings.TrimSpace(line) == "" && cpu.ID != "" {
- cpuInfos = append(cpuInfos, *cpu)
- cpu = &linuxCpuInfo{}
- }
- }
- // Process the sockets/cores/threads
- socketByID := map[string]*CPU{}
- coreBySocket := map[string]map[string]struct{}{}
- threadsByCoreBySocket := map[string]map[string]int{}
- for _, c := range cpuInfos {
- if _, found := socketByID[c.PhysicalID]; !found {
- socketByID[c.PhysicalID] = &CPU{
- ID: c.PhysicalID,
- VendorID: c.VendorID,
- ModelName: c.ModelName,
- }
- coreBySocket[c.PhysicalID] = map[string]struct{}{}
- threadsByCoreBySocket[c.PhysicalID] = map[string]int{}
- }
- if c.CoreID != "" {
- coreBySocket[c.PhysicalID][c.PhysicalID+":"+c.CoreID] = struct{}{}
- threadsByCoreBySocket[c.PhysicalID][c.PhysicalID+":"+c.CoreID]++
- } else {
- coreBySocket[c.PhysicalID][c.PhysicalID+":"+c.ID] = struct{}{}
- threadsByCoreBySocket[c.PhysicalID][c.PhysicalID+":"+c.ID]++
- }
- }
- // Tally up the values from the tracking maps
- for id, s := range socketByID {
- s.CoreCount = len(coreBySocket[id])
- s.ThreadCount = 0
- for _, tc := range threadsByCoreBySocket[id] {
- s.ThreadCount += tc
- }
- // This only works if HT is enabled, consider a more reliable model, maybe cache size comparisons?
- efficiencyCoreCount := 0
- for _, threads := range threadsByCoreBySocket[id] {
- if threads == 1 {
- efficiencyCoreCount++
- }
- }
- if efficiencyCoreCount == s.CoreCount {
- // 1:1 mapping means they're not actually efficiency cores, but regular cores
- s.EfficiencyCoreCount = 0
- } else {
- s.EfficiencyCoreCount = efficiencyCoreCount
- }
- }
- result := []CPU{}
- for _, c := range socketByID {
- result = append(result, *c)
- }
- return result, nil
- }
|