Jelajahi Sumber

Fix wrong CPU count after CPU hot-plugging

This fix tries to address issues raised in #23768 where the CPU count
is not updated after cpu ho-plugging.

This fix follows the suggestion from #23768 and replace go's `runtime.NumCPU()`
with `sysconf(_SC_NPROCESSORS_ONLN)` so that correct CPU count could
be obtained even after CPU hot-plugging.

This fix is tested manually, as is suggested in #23768.

This fix fixes #23768.

The NumCPU() in Linux is based on @wmark 's implementation.

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
Yong Tang 9 tahun lalu
induk
melakukan
8b2383f5c1
3 mengubah file dengan 68 tambahan dan 1 penghapusan
  1. 1 1
      daemon/info.go
  2. 12 0
      pkg/sysinfo/numcpu.go
  3. 55 0
      pkg/sysinfo/numcpu_linux.go

+ 1 - 1
daemon/info.go

@@ -104,7 +104,7 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
 		OSType:             platform.OSType,
 		OSType:             platform.OSType,
 		Architecture:       platform.Architecture,
 		Architecture:       platform.Architecture,
 		RegistryConfig:     daemon.RegistryService.ServiceConfig(),
 		RegistryConfig:     daemon.RegistryService.ServiceConfig(),
-		NCPU:               runtime.NumCPU(),
+		NCPU:               sysinfo.NumCPU(),
 		MemTotal:           meminfo.MemTotal,
 		MemTotal:           meminfo.MemTotal,
 		DockerRootDir:      daemon.configStore.Root,
 		DockerRootDir:      daemon.configStore.Root,
 		Labels:             daemon.configStore.Labels,
 		Labels:             daemon.configStore.Labels,

+ 12 - 0
pkg/sysinfo/numcpu.go

@@ -0,0 +1,12 @@
+// +build !linux
+
+package sysinfo
+
+import (
+	"runtime"
+)
+
+// NumCPU returns the number of CPUs
+func NumCPU() int {
+	return runtime.NumCPU()
+}

+ 55 - 0
pkg/sysinfo/numcpu_linux.go

@@ -0,0 +1,55 @@
+// +build linux
+
+package sysinfo
+
+import (
+	"runtime"
+	"syscall"
+	"unsafe"
+
+	"golang.org/x/sys/unix"
+)
+
+// Returns bit count of 1
+func popcnt(x uint64) (n byte) {
+	x -= (x >> 1) & 0x5555555555555555
+	x = (x>>2)&0x3333333333333333 + x&0x3333333333333333
+	x += x >> 4
+	x &= 0x0f0f0f0f0f0f0f0f
+	x *= 0x0101010101010101
+	return byte(x >> 56)
+}
+
+// numCPU queries the system for the count of threads available
+// for use to this process.
+//
+// Issues two syscalls.
+// Returns 0 on errors. Use |runtime.NumCPU| in that case.
+func numCPU() int {
+	// Gets the affinity mask for a process: The very one invoking this function.
+	pid, _, _ := syscall.RawSyscall(unix.SYS_GETPID, 0, 0, 0)
+
+	var mask [1024 / 64]uintptr
+	_, _, err := syscall.RawSyscall(unix.SYS_SCHED_GETAFFINITY, pid, uintptr(len(mask)*8), uintptr(unsafe.Pointer(&mask[0])))
+	if err != 0 {
+		return 0
+	}
+
+	// For every available thread a bit is set in the mask.
+	ncpu := 0
+	for _, e := range mask {
+		if e == 0 {
+			continue
+		}
+		ncpu += int(popcnt(uint64(e)))
+	}
+	return ncpu
+}
+
+// NumCPU returns the number of CPUs which are currently online
+func NumCPU() int {
+	if ncpu := numCPU(); ncpu > 0 {
+		return ncpu
+	}
+	return runtime.NumCPU()
+}