Repository: cilium/ebpf
Pull request #1219 (2023-11-13 00:21:14)

Move PossibleCPUs to a public API
Prequel to #1192 

Note: Also added `MustPossibleCPUs()` as a wrapper.

Considered switching to `sync.OnceValues()`, but instead referenced `internal.Memoize()`

alxn: Note I didn't change `possibleCPUs :=` -  that will ripple out more.

Patch:
diff --git a/internal/cpu.go b/cpu.go
similarity index 71%
rename from internal/cpu.go
rename to cpu.go
index 9e908b6..1397d6d 100644
--- a/internal/cpu.go
+++ b/cpu.go
@@ -1,17 +1,33 @@
-package internal
+package ebpf
 
 import (
 	"fmt"
 	"os"
 	"strings"
+
+	"github.com/cilium/ebpf/internal"
 )
 
-// PossibleCPUs returns the max number of CPUs a system may possibly have
-// Logical CPU numbers must be of the form 0-n
-var PossibleCPUs = Memoize(func() (int, error) {
+var possibleCPU = internal.Memoize(func() (int, error) {
 	return parseCPUsFromFile("/sys/devices/system/cpu/possible")
 })
 
+// PossibleCPU returns the max number of CPUs a system may possibly have
+// Logical CPU numbers must be of the form 0-n
+func PossibleCPU() (int, error) {
+	return possibleCPU()
+}
+
+// MustPossibleCPU is a helper that wraps a call to PossibleCPU and panics if
+// the error is non-nil.
+func MustPossibleCPU() int {
+	cpus, err := PossibleCPU()
+	if err != nil {
+		panic(err)
+	}
+	return cpus
+}
+
 func parseCPUsFromFile(path string) (int, error) {
 	spec, err := os.ReadFile(path)
 	if err != nil {
diff --git a/map.go b/map.go
index ce945ac..fec0adf 100644
--- a/map.go
+++ b/map.go
@@ -133,7 +133,7 @@ func (spec *MapSpec) fixupMagicFields() (*MapSpec, error) {
 		spec.KeySize = 4
 		spec.ValueSize = 4
 
-		n, err := internal.PossibleCPUs()
+		n, err := PossibleCPU()
 		if err != nil {
 			return nil, fmt.Errorf("fixup perf event array: %w", err)
 		}
@@ -515,7 +515,7 @@ func newMap(fd *sys.FD, name string, typ MapType, keySize, valueSize, maxEntries
 		return m, nil
 	}
 
-	possibleCPUs, err := internal.PossibleCPUs()
+	possibleCPUs, err := PossibleCPU()
 	if err != nil {
 		return nil, err
 	}
diff --git a/marshalers.go b/marshalers.go
index e89a12f..00911ad 100644
--- a/marshalers.go
+++ b/marshalers.go
@@ -53,7 +53,7 @@ func marshalPerCPUValue(slice any, elemLength int) (sys.Pointer, error) {
 		return sys.Pointer{}, errors.New("per-CPU value requires slice")
 	}
 
-	possibleCPUs, err := internal.PossibleCPUs()
+	possibleCPUs, err := PossibleCPU()
 	if err != nil {
 		return sys.Pointer{}, err
 	}
@@ -91,7 +91,7 @@ func unmarshalPerCPUValue(slicePtr any, elemLength int, buf []byte) error {
 		return fmt.Errorf("per-cpu value requires pointer to slice")
 	}
 
-	possibleCPUs, err := internal.PossibleCPUs()
+	possibleCPUs, err := PossibleCPU()
 	if err != nil {
 		return err
 	}


Test patch:
diff --git a/internal/cpu_test.go b/cpu_test.go
similarity index 96%
rename from internal/cpu_test.go
rename to cpu_test.go
index 7ecee74..fa5cdcf 100644
--- a/internal/cpu_test.go
+++ b/cpu_test.go
@@ -1,4 +1,4 @@
-package internal
+package ebpf
 
 import (
 	"testing"
diff --git a/map_test.go b/map_test.go
index 7bd7194..3d71f4b 100644
--- a/map_test.go
+++ b/map_test.go
@@ -1314,10 +1314,7 @@ func TestIterateMapInMap(t *testing.T) {
 func TestPerCPUMarshaling(t *testing.T) {
 	for _, typ := range []MapType{PerCPUHash, PerCPUArray, LRUCPUHash} {
 		t.Run(typ.String(), func(t *testing.T) {
-			numCPU, err := internal.PossibleCPUs()
-			if err != nil {
-				t.Fatal(err)
-			}
+			numCPU := MustPossibleCPU()
 			if numCPU < 2 {
 				t.Skip("Test requires at least two CPUs")
 			}
@@ -1372,10 +1369,7 @@ type bpfCgroupStorageKey struct {
 }
 
 func TestCgroupPerCPUStorageMarshaling(t *testing.T) {
-	numCPU, err := internal.PossibleCPUs()
-	if err != nil {
-		t.Fatal(err)
-	}
+	numCPU := MustPossibleCPU()
 	if numCPU < 2 {
 		t.Skip("Test requires at least two CPUs")
 	}