numcpu_linux.go 1.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. // +build linux
  2. package sysinfo
  3. import (
  4. "runtime"
  5. "syscall"
  6. "unsafe"
  7. "golang.org/x/sys/unix"
  8. )
  9. // Returns bit count of 1
  10. func popcnt(x uint64) (n byte) {
  11. x -= (x >> 1) & 0x5555555555555555
  12. x = (x>>2)&0x3333333333333333 + x&0x3333333333333333
  13. x += x >> 4
  14. x &= 0x0f0f0f0f0f0f0f0f
  15. x *= 0x0101010101010101
  16. return byte(x >> 56)
  17. }
  18. // numCPU queries the system for the count of threads available
  19. // for use to this process.
  20. //
  21. // Issues two syscalls.
  22. // Returns 0 on errors. Use |runtime.NumCPU| in that case.
  23. func numCPU() int {
  24. // Gets the affinity mask for a process: The very one invoking this function.
  25. pid, _, _ := syscall.RawSyscall(unix.SYS_GETPID, 0, 0, 0)
  26. var mask [1024 / 64]uintptr
  27. _, _, err := syscall.RawSyscall(unix.SYS_SCHED_GETAFFINITY, pid, uintptr(len(mask)*8), uintptr(unsafe.Pointer(&mask[0])))
  28. if err != 0 {
  29. return 0
  30. }
  31. // For every available thread a bit is set in the mask.
  32. ncpu := 0
  33. for _, e := range mask {
  34. if e == 0 {
  35. continue
  36. }
  37. ncpu += int(popcnt(uint64(e)))
  38. }
  39. return ncpu
  40. }
  41. // NumCPU returns the number of CPUs which are currently online
  42. func NumCPU() int {
  43. if ncpu := numCPU(); ncpu > 0 {
  44. return ncpu
  45. }
  46. return runtime.NumCPU()
  47. }