Skip to content

Commit 49ae13c

Browse files
aiborlmb
authored andcommitted
map: avoid allocations during PerCPUMap batch lookups
Extend the optimization from b89a4cb ("map: avoid allocations during batch lookup of common types") to BatchLookup with PerCPUMaps This means that types without implicit padding will not incur allocations. See 4609dc7 ("map: zero-allocation operations for common types") for a detailed description of the behavior. ``` goos: linux goarch: amd64 pkg: github.com/cilium/ebpf cpu: AMD Ryzen 5 5600G with Radeon Graphics │ old.txt │ new.txt │ │ sec/op │ sec/op vs base │ Iterate/PerCPUHash/BatchLookup-8 551.3µ ± 1% 129.7µ ± 1% -76.47% (p=0.000 n=10) Iterate/PerCPUHash/BatchLookupAndDelete-8 568.2µ ± 1% 148.4µ ± 1% -73.88% (p=0.000 n=10) geomean 559.7µ 138.7µ -75.21% │ old.txt │ new.txt │ │ B/op │ B/op vs base │ Iterate/PerCPUHash/BatchLookup-8 89709.0 ± 0% 136.0 ± 0% -99.85% (p=0.000 n=10) Iterate/PerCPUHash/BatchLookupAndDelete-8 89799.0 ± 0% 224.0 ± 1% -99.75% (p=0.000 n=10) geomean 87.65Ki 174.5 -99.81% │ old.txt │ new.txt │ │ allocs/op │ allocs/op vs base │ Iterate/PerCPUHash/BatchLookup-8 1006.000 ± 0% 5.000 ± 0% -99.50% (p=0.000 n=10) Iterate/PerCPUHash/BatchLookupAndDelete-8 1006.000 ± 0% 5.000 ± 0% -99.50% (p=0.000 n=10) geomean 1.006k 5.000 -99.50% ``` Signed-off-by: Tobias Böhm <[email protected]>
1 parent 092197e commit 49ae13c

File tree

2 files changed

+39
-18
lines changed

2 files changed

+39
-18
lines changed

map.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1220,17 +1220,18 @@ func (m *Map) batchLookupPerCPU(cmd sys.Cmd, cursor *MapBatchCursor, keysOut, va
12201220
return 0, fmt.Errorf("keys: %w", err)
12211221
}
12221222

1223-
valueBuf := make([]byte, count*int(m.fullValueSize))
1224-
valuePtr := sys.UnsafeSlicePointer(valueBuf)
1223+
valueBuf := sysenc.SyscallOutput(valuesOut, count*int(m.fullValueSize))
12251224

1226-
n, sysErr := m.batchLookupCmd(cmd, cursor, count, keysOut, valuePtr, opts)
1225+
n, sysErr := m.batchLookupCmd(cmd, cursor, count, keysOut, valueBuf.Pointer(), opts)
12271226
if sysErr != nil && !errors.Is(sysErr, unix.ENOENT) {
12281227
return 0, sysErr
12291228
}
12301229

1231-
err = unmarshalBatchPerCPUValue(valuesOut, count, int(m.valueSize), valueBuf)
1232-
if err != nil {
1233-
return 0, err
1230+
if bytesBuf := valueBuf.Bytes(); bytesBuf != nil {
1231+
err = unmarshalBatchPerCPUValue(valuesOut, count, int(m.valueSize), bytesBuf)
1232+
if err != nil {
1233+
return 0, err
1234+
}
12341235
}
12351236

12361237
return n, sysErr

map_test.go

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -967,21 +967,41 @@ func TestMapIteratorAllocations(t *testing.T) {
967967
func TestMapBatchLookupAllocations(t *testing.T) {
968968
testutils.SkipIfNotSupported(t, haveBatchAPI())
969969

970-
arr := createMap(t, Array, 10)
970+
for _, typ := range []MapType{Array, PerCPUArray} {
971+
if typ == PerCPUArray {
972+
// https://lore.kernel.org/bpf/[email protected]/
973+
testutils.SkipOnOldKernel(t, "5.13", "batched ops support for percpu array")
974+
}
971975

972-
var cursor MapBatchCursor
973-
tmp := make([]uint32, 2)
974-
input := any(tmp)
976+
t.Run(typ.String(), func(t *testing.T) {
977+
m := mustNewMap(t, &MapSpec{
978+
Name: "test",
979+
Type: typ,
980+
KeySize: 4,
981+
ValueSize: 8, // PerCPU values must be 8 byte aligned.
982+
MaxEntries: 10,
983+
}, nil)
975984

976-
// AllocsPerRun warms up the function for us.
977-
allocs := testing.AllocsPerRun(1, func() {
978-
_, err := arr.BatchLookup(&cursor, input, input, nil)
979-
if err != nil {
980-
t.Fatal(err)
981-
}
982-
})
985+
possibleCPU := 1
986+
if m.Type().hasPerCPUValue() {
987+
possibleCPU = MustPossibleCPU()
988+
}
989+
990+
var cursor MapBatchCursor
991+
keys := any(make([]uint32, 2))
992+
values := any(make([]uint64, 2*possibleCPU))
983993

984-
qt.Assert(t, qt.Equals(allocs, 0))
994+
// AllocsPerRun warms up the function for us.
995+
allocs := testing.AllocsPerRun(1, func() {
996+
_, err := m.BatchLookup(&cursor, keys, values, nil)
997+
if err != nil {
998+
t.Fatal(err)
999+
}
1000+
})
1001+
1002+
qt.Assert(t, qt.Equals(allocs, 0))
1003+
})
1004+
}
9851005
}
9861006

9871007
type customTestUnmarshaler []uint8

0 commit comments

Comments
 (0)