diff --git a/README.md b/README.md index 25db2bc..a9c4dd4 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,10 @@ [![GitHub Action Status](https://github.com/tklauser/numcpus/workflows/Tests/badge.svg)](https://github.com/tklauser/numcpus/actions?query=workflow%3ATests) [![Go Report Card](https://goreportcard.com/badge/github.com/tklauser/numcpus)](https://goreportcard.com/report/github.com/tklauser/numcpus) -Package numcpus provides information about the number of CPU. +Package numcpus provides information about the number of CPU in a system. -It gets the number of CPUs (online, offline, present, possible or kernel -maximum) on a Linux, Darwin, FreeBSD, NetBSD, OpenBSD, DragonflyBSD or +It gets the number of CPUs (online, offline, present, possible, configured or +kernel maximum) on a Linux, Darwin, FreeBSD, NetBSD, OpenBSD, DragonflyBSD or Solaris/Illumos system. On Linux, the information is retrieved by reading the corresponding CPU @@ -45,5 +45,5 @@ func main() { ## References -* [Linux kernel sysfs documenation for CPU attributes](https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-devices-system-cpu) +* [Linux kernel sysfs documentation for CPU attributes](https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-devices-system-cpu) * [Linux kernel CPU topology documentation](https://www.kernel.org/doc/Documentation/cputopology.txt) diff --git a/numcpus.go b/numcpus.go index 1023e40..aab0bdd 100644 --- a/numcpus.go +++ b/numcpus.go @@ -30,6 +30,13 @@ import "errors" // ErrNotSupported is the error returned when the function is not supported. var ErrNotSupported = errors.New("function not supported") +// GetConfigured returns the number of CPUs configured on the system. This +// function should return the same value as `getconf _SC_NPROCESSORS_CONF` on a +// unix system. +func GetConfigured() (int, error) { + return getConfigured() +} + // GetKernelMax returns the maximum number of CPUs allowed by the kernel // configuration. This function is only supported on Linux systems. func GetKernelMax() (int, error) { diff --git a/numcpus_bsd.go b/numcpus_bsd.go index dddf928..12bcc34 100644 --- a/numcpus_bsd.go +++ b/numcpus_bsd.go @@ -23,6 +23,11 @@ import ( "golang.org/x/sys/unix" ) +func getConfigured() (int, error) { + n, err := unix.SysctlUint32("hw.ncpu") + return int(n), err +} + func getKernelMax() (int, error) { return 0, ErrNotSupported } diff --git a/numcpus_linux.go b/numcpus_linux.go index 554d2bf..a8d96d6 100644 --- a/numcpus_linux.go +++ b/numcpus_linux.go @@ -16,6 +16,7 @@ package numcpus import ( "io/ioutil" + "os" "path/filepath" "strconv" "strings" @@ -55,6 +56,28 @@ func parseCPURange(cpus string) (int, error) { return n, nil } +func getConfigured() (int, error) { + d, err := os.Open(sysfsCPUBasePath) + if err != nil { + return 0, err + } + defer d.Close() + fis, err := d.Readdir(-1) + if err != nil { + return 0, err + } + count := 0 + for _, fi := range fis { + if name := fi.Name(); fi.IsDir() && strings.HasPrefix(name, "cpu") { + _, err := strconv.ParseInt(name[3:], 10, 64) + if err == nil { + count++ + } + } + } + return count, nil +} + func getKernelMax() (int, error) { buf, err := ioutil.ReadFile(filepath.Join(sysfsCPUBasePath, "kernel_max")) if err != nil { diff --git a/numcpus_solaris.go b/numcpus_solaris.go index 92c7d77..a264323 100644 --- a/numcpus_solaris.go +++ b/numcpus_solaris.go @@ -26,6 +26,11 @@ const ( _SC_NPROCESSORS_MAX = 516 ) +func getConfigured() (int, error) { + n, err := unix.Sysconf(_SC_NPROCESSORS_CONF) + return int(n), err +} + func getKernelMax() (int, error) { n, err := unix.Sysconf(_SC_NPROCESSORS_MAX) return int(n), err diff --git a/numcpus_test.go b/numcpus_test.go index 93a8f87..d3794c2 100644 --- a/numcpus_test.go +++ b/numcpus_test.go @@ -51,6 +51,18 @@ func testGetconf(t *testing.T, got int, name, getconfWhich string) { } } +func TestGetConfigured(t *testing.T) { + n, err := numcpus.GetConfigured() + if errors.Is(err, numcpus.ErrNotSupported) { + t.Skipf("GetConfigured not supported on %s", runtime.GOOS) + } else if err != nil { + t.Fatalf("GetConfigured: %v", err) + } + t.Logf("Configured = %v", n) + + testGetconf(t, n, "GetConfigured", "_NPROCESSORS_CONF") +} + func TestGetKernelMax(t *testing.T) { n, err := numcpus.GetKernelMax() if errors.Is(err, numcpus.ErrNotSupported) { diff --git a/numcpus_unsupported.go b/numcpus_unsupported.go index 1bec9d7..ef79066 100644 --- a/numcpus_unsupported.go +++ b/numcpus_unsupported.go @@ -17,6 +17,10 @@ package numcpus +func getConfigured() (int, error) { + return 0, ErrNotSupported +} + func getKernelMax() (int, error) { return 0, ErrNotSupported }