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>
This commit is contained in:
Yong Tang 2016-06-25 07:26:00 -07:00
parent d4bff5e3aa
commit 8b2383f5c1
3 changed files with 68 additions and 1 deletions

View file

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

12
pkg/sysinfo/numcpu.go Normal file
View file

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

View file

@ -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()
}