cpu.go 1.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. package internal
  2. import (
  3. "fmt"
  4. "os"
  5. "strings"
  6. )
  7. // PossibleCPUs returns the max number of CPUs a system may possibly have
  8. // Logical CPU numbers must be of the form 0-n
  9. var PossibleCPUs = Memoize(func() (int, error) {
  10. return parseCPUsFromFile("/sys/devices/system/cpu/possible")
  11. })
  12. func parseCPUsFromFile(path string) (int, error) {
  13. spec, err := os.ReadFile(path)
  14. if err != nil {
  15. return 0, err
  16. }
  17. n, err := parseCPUs(string(spec))
  18. if err != nil {
  19. return 0, fmt.Errorf("can't parse %s: %v", path, err)
  20. }
  21. return n, nil
  22. }
  23. // parseCPUs parses the number of cpus from a string produced
  24. // by bitmap_list_string() in the Linux kernel.
  25. // Multiple ranges are rejected, since they can't be unified
  26. // into a single number.
  27. // This is the format of /sys/devices/system/cpu/possible, it
  28. // is not suitable for /sys/devices/system/cpu/online, etc.
  29. func parseCPUs(spec string) (int, error) {
  30. if strings.Trim(spec, "\n") == "0" {
  31. return 1, nil
  32. }
  33. var low, high int
  34. n, err := fmt.Sscanf(spec, "%d-%d\n", &low, &high)
  35. if n != 2 || err != nil {
  36. return 0, fmt.Errorf("invalid format: %s", spec)
  37. }
  38. if low != 0 {
  39. return 0, fmt.Errorf("CPU spec doesn't start at zero: %s", spec)
  40. }
  41. // cpus is 0 indexed
  42. return high + 1, nil
  43. }