affinity_linux.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. // Copyright 2018 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // CPU affinity functions
  5. package unix
  6. import (
  7. "math/bits"
  8. "unsafe"
  9. )
  10. const cpuSetSize = _CPU_SETSIZE / _NCPUBITS
  11. // CPUSet represents a bit mask of CPUs, to be used with [SchedGetaffinity], [SchedSetaffinity],
  12. // and [SetMemPolicy].
  13. //
  14. // Note this type can only represent CPU IDs 0 through 1023.
  15. // Use [CPUSetDynamic]/[NewCPUSet] instead to avoid this limit.
  16. type CPUSet [cpuSetSize]cpuMask
  17. // CPUSetDynamic represents a bit mask of CPUs, to be used with [SchedGetaffinityDynamic],
  18. // [SchedSetaffinityDynamic], and [SetMemPolicyDynamic]. Use [NewCPUSet] to allocate.
  19. type CPUSetDynamic []cpuMask
  20. func schedAffinity(trap uintptr, pid int, size uintptr, ptr unsafe.Pointer) error {
  21. _, _, e := RawSyscall(trap, uintptr(pid), uintptr(size), uintptr(ptr))
  22. if e != 0 {
  23. return errnoErr(e)
  24. }
  25. return nil
  26. }
  27. // SchedGetaffinity gets the CPU affinity mask of the thread specified by pid.
  28. // If pid is 0 the calling thread is used.
  29. func SchedGetaffinity(pid int, set *CPUSet) error {
  30. return schedAffinity(SYS_SCHED_GETAFFINITY, pid, unsafe.Sizeof(*set), unsafe.Pointer(set))
  31. }
  32. // SchedSetaffinity sets the CPU affinity mask of the thread specified by pid.
  33. // If pid is 0 the calling thread is used.
  34. func SchedSetaffinity(pid int, set *CPUSet) error {
  35. return schedAffinity(SYS_SCHED_SETAFFINITY, pid, unsafe.Sizeof(*set), unsafe.Pointer(set))
  36. }
  37. // Zero clears the set s, so that it contains no CPUs.
  38. func (s *CPUSet) Zero() {
  39. clear(s[:])
  40. }
  41. // Fill adds all possible CPU bits to the set s. On Linux, [SchedSetaffinity]
  42. // will silently ignore any invalid CPU bits in [CPUSet] so this is an
  43. // efficient way of resetting the CPU affinity of a process.
  44. func (s *CPUSet) Fill() {
  45. cpuMaskFill(s[:])
  46. }
  47. func cpuBitsIndex(cpu int) int {
  48. return cpu / _NCPUBITS
  49. }
  50. func cpuBitsMask(cpu int) cpuMask {
  51. return cpuMask(1 << (uint(cpu) % _NCPUBITS))
  52. }
  53. func cpuMaskFill(s []cpuMask) {
  54. for i := range s {
  55. s[i] = ^cpuMask(0)
  56. }
  57. }
  58. func cpuMaskSet(s []cpuMask, cpu int) {
  59. i := cpuBitsIndex(cpu)
  60. if i < len(s) {
  61. s[i] |= cpuBitsMask(cpu)
  62. }
  63. }
  64. func cpuMaskClear(s []cpuMask, cpu int) {
  65. i := cpuBitsIndex(cpu)
  66. if i < len(s) {
  67. s[i] &^= cpuBitsMask(cpu)
  68. }
  69. }
  70. func cpuMaskIsSet(s []cpuMask, cpu int) bool {
  71. i := cpuBitsIndex(cpu)
  72. if i < len(s) {
  73. return s[i]&cpuBitsMask(cpu) != 0
  74. }
  75. return false
  76. }
  77. func cpuMaskCount(s []cpuMask) int {
  78. c := 0
  79. for _, b := range s {
  80. c += bits.OnesCount64(uint64(b))
  81. }
  82. return c
  83. }
  84. // Set adds cpu to the set s. If cpu is out of bounds for s, no action is taken.
  85. func (s *CPUSet) Set(cpu int) {
  86. cpuMaskSet(s[:], cpu)
  87. }
  88. // Clear removes cpu from the set s. If cpu is out of bounds for s, no action is taken.
  89. func (s *CPUSet) Clear(cpu int) {
  90. cpuMaskClear(s[:], cpu)
  91. }
  92. // IsSet reports whether cpu is in the set s.
  93. func (s *CPUSet) IsSet(cpu int) bool {
  94. return cpuMaskIsSet(s[:], cpu)
  95. }
  96. // Count returns the number of CPUs in the set s.
  97. func (s *CPUSet) Count() int {
  98. return cpuMaskCount(s[:])
  99. }
  100. // NewCPUSet creates a CPU affinity mask capable of representing CPU IDs
  101. // up to maxCPU (exclusive).
  102. func NewCPUSet(maxCPU int) CPUSetDynamic {
  103. numMasks := (maxCPU + _NCPUBITS - 1) / _NCPUBITS
  104. if numMasks == 0 {
  105. numMasks = 1
  106. }
  107. return make(CPUSetDynamic, numMasks)
  108. }
  109. // Zero clears the set s, so that it contains no CPUs.
  110. func (s CPUSetDynamic) Zero() {
  111. clear(s)
  112. }
  113. // Fill adds all possible CPU bits to the set s. On Linux, [SchedSetaffinityDynamic]
  114. // will silently ignore any invalid CPU bits in [CPUSetDynamic] so this is an
  115. // efficient way of resetting the CPU affinity of a process.
  116. func (s CPUSetDynamic) Fill() {
  117. cpuMaskFill(s)
  118. }
  119. // Set adds cpu to the set s. If cpu is out of bounds for s, no action is taken.
  120. func (s CPUSetDynamic) Set(cpu int) {
  121. cpuMaskSet(s, cpu)
  122. }
  123. // Clear removes cpu from the set s. If cpu is out of bounds for s, no action is taken.
  124. func (s CPUSetDynamic) Clear(cpu int) {
  125. cpuMaskClear(s, cpu)
  126. }
  127. // IsSet reports whether cpu is in the set s.
  128. func (s CPUSetDynamic) IsSet(cpu int) bool {
  129. return cpuMaskIsSet(s, cpu)
  130. }
  131. // Count returns the number of CPUs in the set s.
  132. func (s CPUSetDynamic) Count() int {
  133. return cpuMaskCount(s)
  134. }
  135. func (s CPUSetDynamic) size() uintptr {
  136. return uintptr(len(s)) * unsafe.Sizeof(cpuMask(0))
  137. }
  138. func (s CPUSetDynamic) pointer() unsafe.Pointer {
  139. if len(s) == 0 {
  140. return nil
  141. }
  142. return unsafe.Pointer(&s[0])
  143. }
  144. // SchedGetaffinityDynamic gets the CPU affinity mask of the thread specified by pid.
  145. // If pid is 0 the calling thread is used.
  146. //
  147. // If the set is smaller than the size of the affinity mask used by the kernel,
  148. // [EINVAL] is returned.
  149. func SchedGetaffinityDynamic(pid int, set CPUSetDynamic) error {
  150. return schedAffinity(SYS_SCHED_GETAFFINITY, pid, set.size(), set.pointer())
  151. }
  152. // SchedSetaffinityDynamic sets the CPU affinity mask of the thread specified by pid.
  153. // If pid is 0 the calling thread is used.
  154. func SchedSetaffinityDynamic(pid int, set CPUSetDynamic) error {
  155. return schedAffinity(SYS_SCHED_SETAFFINITY, pid, set.size(), set.pointer())
  156. }