affinity_linux.go

  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
  5// CPU affinity functions
  6
  7package unix
  8
  9import (
 10	"unsafe"
 11)
 12
 13const cpuSetSize = _CPU_SETSIZE / _NCPUBITS
 14
 15// CPUSet represents a CPU affinity mask.
 16type CPUSet [cpuSetSize]cpuMask
 17
 18func schedAffinity(trap uintptr, pid int, set *CPUSet) error {
 19	_, _, e := RawSyscall(trap, uintptr(pid), uintptr(unsafe.Sizeof(*set)), uintptr(unsafe.Pointer(set)))
 20	if e != 0 {
 21		return errnoErr(e)
 22	}
 23	return nil
 24}
 25
 26// SchedGetaffinity gets the CPU affinity mask of the thread specified by pid.
 27// If pid is 0 the calling thread is used.
 28func SchedGetaffinity(pid int, set *CPUSet) error {
 29	return schedAffinity(SYS_SCHED_GETAFFINITY, pid, set)
 30}
 31
 32// SchedSetaffinity sets the CPU affinity mask of the thread specified by pid.
 33// If pid is 0 the calling thread is used.
 34func SchedSetaffinity(pid int, set *CPUSet) error {
 35	return schedAffinity(SYS_SCHED_SETAFFINITY, pid, set)
 36}
 37
 38// Zero clears the set s, so that it contains no CPUs.
 39func (s *CPUSet) Zero() {
 40	for i := range s {
 41		s[i] = 0
 42	}
 43}
 44
 45func cpuBitsIndex(cpu int) int {
 46	return cpu / _NCPUBITS
 47}
 48
 49func cpuBitsMask(cpu int) cpuMask {
 50	return cpuMask(1 << (uint(cpu) % _NCPUBITS))
 51}
 52
 53// Set adds cpu to the set s.
 54func (s *CPUSet) Set(cpu int) {
 55	i := cpuBitsIndex(cpu)
 56	if i < len(s) {
 57		s[i] |= cpuBitsMask(cpu)
 58	}
 59}
 60
 61// Clear removes cpu from the set s.
 62func (s *CPUSet) Clear(cpu int) {
 63	i := cpuBitsIndex(cpu)
 64	if i < len(s) {
 65		s[i] &^= cpuBitsMask(cpu)
 66	}
 67}
 68
 69// IsSet reports whether cpu is in the set s.
 70func (s *CPUSet) IsSet(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
 78// Count returns the number of CPUs in the set s.
 79func (s *CPUSet) Count() int {
 80	c := 0
 81	for _, b := range s {
 82		c += onesCount64(uint64(b))
 83	}
 84	return c
 85}
 86
 87// onesCount64 is a copy of Go 1.9's math/bits.OnesCount64.
 88// Once this package can require Go 1.9, we can delete this
 89// and update the caller to use bits.OnesCount64.
 90func onesCount64(x uint64) int {
 91	const m0 = 0x5555555555555555 // 01010101 ...
 92	const m1 = 0x3333333333333333 // 00110011 ...
 93	const m2 = 0x0f0f0f0f0f0f0f0f // 00001111 ...
 94	const m3 = 0x00ff00ff00ff00ff // etc.
 95	const m4 = 0x0000ffff0000ffff
 96
 97	// Implementation: Parallel summing of adjacent bits.
 98	// See "Hacker's Delight", Chap. 5: Counting Bits.
 99	// The following pattern shows the general approach:
100	//
101	//   x = x>>1&(m0&m) + x&(m0&m)
102	//   x = x>>2&(m1&m) + x&(m1&m)
103	//   x = x>>4&(m2&m) + x&(m2&m)
104	//   x = x>>8&(m3&m) + x&(m3&m)
105	//   x = x>>16&(m4&m) + x&(m4&m)
106	//   x = x>>32&(m5&m) + x&(m5&m)
107	//   return int(x)
108	//
109	// Masking (& operations) can be left away when there's no
110	// danger that a field's sum will carry over into the next
111	// field: Since the result cannot be > 64, 8 bits is enough
112	// and we can ignore the masks for the shifts by 8 and up.
113	// Per "Hacker's Delight", the first line can be simplified
114	// more, but it saves at best one instruction, so we leave
115	// it alone for clarity.
116	const m = 1<<64 - 1
117	x = x>>1&(m0&m) + x&(m0&m)
118	x = x>>2&(m1&m) + x&(m1&m)
119	x = (x>>4 + x) & (m2 & m)
120	x += x >> 8
121	x += x >> 16
122	x += x >> 32
123	return int(x) & (1<<7 - 1)
124}