mirror of
https://github.com/tailscale/tailscale.git
synced 2025-10-24 09:39:39 +00:00
net/art: implement the Table type, a multi-level art route table.
Updates #7781 │ sec/op │ TableInsertion/ipv4/10 1.562µ ± 2% TableInsertion/ipv4/100 2.398µ ± 5% TableInsertion/ipv4/1000 2.097µ ± 3% TableInsertion/ipv4/10000 2.756µ ± 4% TableInsertion/ipv4/100000 2.473µ ± 13% TableInsertion/ipv6/10 7.649µ ± 2% TableInsertion/ipv6/100 12.09µ ± 3% TableInsertion/ipv6/1000 14.84µ ± 5% TableInsertion/ipv6/10000 14.72µ ± 8% TableInsertion/ipv6/100000 13.23µ ± 41% TableDelete/ipv4/10 378.4n ± 5% TableDelete/ipv4/100 366.9n ± 3% TableDelete/ipv4/1000 418.6n ± 3% TableDelete/ipv4/10000 609.2n ± 11% TableDelete/ipv4/100000 679.2n ± 28% TableDelete/ipv6/10 504.2n ± 4% TableDelete/ipv6/100 959.5n ± 12% TableDelete/ipv6/1000 1.436µ ± 6% TableDelete/ipv6/10000 1.772µ ± 15% TableDelete/ipv6/100000 1.172µ ± 113% TableGet/ipv4/10 32.14n ± 11% TableGet/ipv4/100 38.58n ± 2% TableGet/ipv4/1000 45.03n ± 2% TableGet/ipv4/10000 52.90n ± 7% TableGet/ipv4/100000 135.2n ± 11% TableGet/ipv6/10 41.55n ± 1% TableGet/ipv6/100 44.78n ± 2% TableGet/ipv6/1000 49.03n ± 2% TableGet/ipv6/10000 65.38n ± 5% TableGet/ipv6/100000 525.0n ± 39% │ avg-B/op │ TableInsertion/ipv4/10 25.18Ki ± 0% TableInsertion/ipv4/100 17.63Ki ± 0% TableInsertion/ipv4/1000 14.14Ki ± 0% TableInsertion/ipv4/10000 12.92Ki ± 0% TableInsertion/ipv4/100000 11.13Ki ± 0% TableInsertion/ipv6/10 76.87Ki ± 0% TableInsertion/ipv6/100 98.33Ki ± 0% TableInsertion/ipv6/1000 91.44Ki ± 0% TableInsertion/ipv6/10000 90.39Ki ± 0% TableInsertion/ipv6/100000 87.19Ki ± 0% TableDelete/ipv4/10 3.230 ± 0% TableDelete/ipv4/100 4.020 ± 0% TableDelete/ipv4/1000 3.990 ± 0% TableDelete/ipv4/10000 4.000 ± 0% TableDelete/ipv4/100000 4.000 ± 0% TableDelete/ipv6/10 16.00 ± 0% TableDelete/ipv6/100 16.00 ± 0% TableDelete/ipv6/1000 16.00 ± 0% TableDelete/ipv6/10000 16.00 ± 0% TableDelete/ipv6/100000 16.00 ± 0% │ avg-allocs/op │ TableInsertion/ipv4/10 2.900 ± 0% TableInsertion/ipv4/100 2.330 ± 0% TableInsertion/ipv4/1000 2.070 ± 0% TableInsertion/ipv4/10000 1.980 ± 0% TableInsertion/ipv4/100000 1.840 ± 0% TableInsertion/ipv6/10 6.800 ± 0% TableInsertion/ipv6/100 8.420 ± 0% TableInsertion/ipv6/1000 7.900 ± 0% TableInsertion/ipv6/10000 7.820 ± 0% TableInsertion/ipv6/100000 7.580 ± 0% TableDelete/ipv4/10 1.000 ± 0% TableDelete/ipv4/100 1.000 ± 0% TableDelete/ipv4/1000 1.000 ± 0% TableDelete/ipv4/10000 1.000 ± 0% TableDelete/ipv4/100000 1.000 ± 0% TableDelete/ipv6/10 1.000 ± 0% TableDelete/ipv6/100 1.000 ± 0% TableDelete/ipv6/1000 1.000 ± 0% TableDelete/ipv6/10000 1.000 ± 0% TableDelete/ipv6/100000 1.000 ± 0% │ routes/s │ TableInsertion/ipv4/10 640.3k ± 2% TableInsertion/ipv4/100 417.1k ± 5% TableInsertion/ipv4/1000 477.0k ± 3% TableInsertion/ipv4/10000 362.8k ± 5% TableInsertion/ipv4/100000 404.5k ± 15% TableInsertion/ipv6/10 130.7k ± 1% TableInsertion/ipv6/100 82.69k ± 3% TableInsertion/ipv6/1000 67.37k ± 5% TableInsertion/ipv6/10000 67.93k ± 9% TableInsertion/ipv6/100000 75.63k ± 29% TableDelete/ipv4/10 2.642M ± 6% TableDelete/ipv4/100 2.726M ± 3% TableDelete/ipv4/1000 2.389M ± 3% TableDelete/ipv4/10000 1.641M ± 12% TableDelete/ipv4/100000 1.472M ± 27% TableDelete/ipv6/10 1.984M ± 4% TableDelete/ipv6/100 1.042M ± 11% TableDelete/ipv6/1000 696.5k ± 6% TableDelete/ipv6/10000 564.4k ± 13% TableDelete/ipv6/100000 853.6k ± 53% │ addrs/s │ TableGet/ipv4/10 31.11M ± 10% TableGet/ipv4/100 25.92M ± 2% TableGet/ipv4/1000 22.21M ± 2% TableGet/ipv4/10000 18.91M ± 8% TableGet/ipv4/100000 7.397M ± 12% TableGet/ipv6/10 24.07M ± 1% TableGet/ipv6/100 22.33M ± 2% TableGet/ipv6/1000 20.40M ± 2% TableGet/ipv6/10000 15.30M ± 5% TableGet/ipv6/100000 1.905M ± 28% │ B/op │ TableGet/ipv4/10 4.000 ± 0% TableGet/ipv4/100 4.000 ± 0% TableGet/ipv4/1000 4.000 ± 0% TableGet/ipv4/10000 4.000 ± 0% TableGet/ipv4/100000 4.000 ± 0% TableGet/ipv6/10 16.00 ± 0% TableGet/ipv6/100 16.00 ± 0% TableGet/ipv6/1000 16.00 ± 0% TableGet/ipv6/10000 16.00 ± 0% TableGet/ipv6/100000 16.00 ± 0% │ allocs/op │ TableGet/ipv4/10 1.000 ± 0% TableGet/ipv4/100 1.000 ± 0% TableGet/ipv4/1000 1.000 ± 0% TableGet/ipv4/10000 1.000 ± 0% TableGet/ipv4/100000 1.000 ± 0% TableGet/ipv6/10 1.000 ± 0% TableGet/ipv6/100 1.000 ± 0% TableGet/ipv6/1000 1.000 ± 0% TableGet/ipv6/10000 1.000 ± 0% TableGet/ipv6/100000 1.000 ± 0% Signed-off-by: David Anderson <danderson@tailscale.com>
This commit is contained in:
committed by
Dave Anderson
parent
edb02b63f8
commit
a7c910e361
@@ -16,6 +16,7 @@ import (
|
||||
)
|
||||
|
||||
func TestInversePrefix(t *testing.T) {
|
||||
t.Parallel()
|
||||
for i := 0; i < 256; i++ {
|
||||
for len := 0; len < 9; len++ {
|
||||
addr := i & (0xFF << (8 - len))
|
||||
@@ -29,6 +30,7 @@ func TestInversePrefix(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHostIndex(t *testing.T) {
|
||||
t.Parallel()
|
||||
for i := 0; i < 256; i++ {
|
||||
got := hostIndex(uint8(i))
|
||||
want := prefixIndex(uint8(i), 8)
|
||||
@@ -39,6 +41,7 @@ func TestHostIndex(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStrideTableInsert(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Verify that strideTable's lookup results after a bunch of inserts exactly
|
||||
// match those of a naive implementation that just scans all prefixes on
|
||||
// every lookup. The naive implementation is very slow, but its behavior is
|
||||
@@ -66,6 +69,7 @@ func TestStrideTableInsert(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStrideTableInsertShuffled(t *testing.T) {
|
||||
t.Parallel()
|
||||
// The order in which routes are inserted into a route table does not
|
||||
// influence the final shape of the table, as long as the same set of
|
||||
// prefixes is being inserted. This test verifies that strideTable behaves
|
||||
@@ -111,6 +115,7 @@ func TestStrideTableInsertShuffled(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStrideTableDelete(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Compare route deletion to our reference slowTable.
|
||||
pfxs := shufflePrefixes(allPrefixes())[:100]
|
||||
slow := slowTable[int]{pfxs}
|
||||
@@ -145,6 +150,7 @@ func TestStrideTableDelete(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStrideTableDeleteShuffle(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Same as TestStrideTableInsertShuffle, the order in which prefixes are
|
||||
// deleted should not impact the final shape of the route table.
|
||||
|
||||
@@ -191,17 +197,17 @@ func TestStrideTableDeleteShuffle(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
var benchRouteCount = []int{10, 50, 100, 200}
|
||||
var strideRouteCount = []int{10, 50, 100, 200}
|
||||
|
||||
// forCountAndOrdering runs the benchmark fn with different sets of routes.
|
||||
//
|
||||
// fn is called once for each combination of {num_routes, order}, where
|
||||
// num_routes is the values in benchRouteCount, and order is the order of the
|
||||
// num_routes is the values in strideRouteCount, and order is the order of the
|
||||
// routes in the list: random, largest prefix first (/0 to /8), and smallest
|
||||
// prefix first (/8 to /0).
|
||||
func forCountAndOrdering(b *testing.B, fn func(b *testing.B, routes []slowEntry[int])) {
|
||||
func forStrideCountAndOrdering(b *testing.B, fn func(b *testing.B, routes []slowEntry[int])) {
|
||||
routes := shufflePrefixes(allPrefixes())
|
||||
for _, nroutes := range benchRouteCount {
|
||||
for _, nroutes := range strideRouteCount {
|
||||
b.Run(fmt.Sprint(nroutes), func(b *testing.B) {
|
||||
routes := append([]slowEntry[int](nil), routes[:nroutes]...)
|
||||
b.Run("random_order", func(b *testing.B) {
|
||||
@@ -233,7 +239,7 @@ func forCountAndOrdering(b *testing.B, fn func(b *testing.B, routes []slowEntry[
|
||||
}
|
||||
|
||||
func BenchmarkStrideTableInsertion(b *testing.B) {
|
||||
forCountAndOrdering(b, func(b *testing.B, routes []slowEntry[int]) {
|
||||
forStrideCountAndOrdering(b, func(b *testing.B, routes []slowEntry[int]) {
|
||||
val := 0
|
||||
for i := 0; i < b.N; i++ {
|
||||
var rt strideTable[int]
|
||||
@@ -250,7 +256,7 @@ func BenchmarkStrideTableInsertion(b *testing.B) {
|
||||
}
|
||||
|
||||
func BenchmarkStrideTableDeletion(b *testing.B) {
|
||||
forCountAndOrdering(b, func(b *testing.B, routes []slowEntry[int]) {
|
||||
forStrideCountAndOrdering(b, func(b *testing.B, routes []slowEntry[int]) {
|
||||
val := 0
|
||||
var rt strideTable[int]
|
||||
for _, route := range routes {
|
||||
|
||||
Reference in New Issue
Block a user