From 4adca98d1fbf837ed7340f08ce53f4cf9daa6b71 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 14 Jul 2020 13:27:41 -0700 Subject: [PATCH] device: add BenchmarkAllowedIPsInsertRemove To show that RemoveByPeer is slow. Currently: (pprof) top Showing nodes accounting for 2.99s, 96.14% of 3.11s total Dropped 35 nodes (cum <= 0.02s) Showing top 10 nodes out of 36 flat flat% sum% cum cum% 2.72s 87.46% 87.46% 2.72s 87.46% golang.zx2c4.com/wireguard/device.(*trieEntry).removeByPeer 0.10s 3.22% 90.68% 0.10s 3.22% runtime.memclrNoHeapPointers 0.05s 1.61% 92.28% 0.06s 1.93% runtime.scanobject 0.03s 0.96% 93.25% 0.05s 1.61% runtime.casgstatus 0.02s 0.64% 93.89% 0.02s 0.64% runtime.(*gcBitsArena).tryAlloc (inline) 0.02s 0.64% 94.53% 0.02s 0.64% runtime.heapBitsSetType 0.02s 0.64% 95.18% 0.04s 1.29% runtime.sweepone 0.01s 0.32% 95.50% 0.02s 0.64% golang.zx2c4.com/wireguard/device.commonBits 0.01s 0.32% 95.82% 0.03s 0.96% runtime.(*mheap).allocSpan 0.01s 0.32% 96.14% 0.24s 7.72% runtime.mallocgc Signed-off-by: Brad Fitzpatrick --- device/allowedips_test.go | 46 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/device/allowedips_test.go b/device/allowedips_test.go index 005df4899..8f95faf98 100644 --- a/device/allowedips_test.go +++ b/device/allowedips_test.go @@ -258,3 +258,49 @@ func TestTrieIPv6(t *testing.T) { assertEQ(h, 0x24046800, 0x40040800, 0x10101010, 0x10101010) assertEQ(a, 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef) } + +// Repeatedly insert and remove IPv4 /32s from AllowedIPs. +func BenchmarkAllowedIPsInsertRemove(b *testing.B) { + // First, make 64k peers, all with unique IPs, in a seeded pseudo-random order. + const num = 256 * 256 + var peers [num]*Peer + var ips [num]net.IP + for i := range peers { + peers[i] = new(Peer) + ips[i] = net.IPv4(100, 64, byte(i>>8), byte(i)).To4() + } + rand.Seed(1) + rand.Shuffle(num, func(i, j int) { ips[i], ips[j] = ips[j], ips[i] }) + + // Then repeatedly add one and remove one that was insert 32k inserts back. + b.ResetTimer() + var a AllowedIPs + for i := 0; i < b.N; i++ { + a.Insert(ips[i%num], 32, peers[i%num]) + a.RemoveByPeer(peers[(i+num/2)%num]) + } + + // Finally, some stats & validity checks. + nodes, numPeer := 0, 0 + peersSeen := map[*Peer]bool{} + foreachEntry(a.IPv4, func(n *trieEntry) { + nodes++ + if n.peer != nil { + numPeer++ + peersSeen[n.peer] = true + } + }) + b.Logf("for N=%v: nodes=%v, peers=%v, unique_peers=%v", b.N, nodes, numPeer, len(peersSeen)) + if numPeer != len(peersSeen) { + b.Errorf("walked %d nodes with peers != %d unique peers seen", numPeer, len(peersSeen)) + } +} + +func foreachEntry(n *trieEntry, f func(*trieEntry)) { + if n == nil { + return + } + f(n) + foreachEntry(n.child[0], f) + foreachEntry(n.child[1], f) +}