go.ligato.io/vpp-agent/v3@v3.5.0/plugins/kvscheduler/internal/graph/bench_test.go (about) 1 // Copyright (c) 2019 Cisco and/or its affiliates. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at: 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package graph 16 17 import ( 18 "fmt" 19 "strconv" 20 "testing" 21 22 . "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/internal/test" 23 ) 24 25 /* 26 ------------------------ 27 KVGraph benchmarks 28 ------------------------ 29 30 How to run: 31 - build test binary `go test -c` 32 - run all benchmarks: `./graph.test -test.run=XXX -test.bench=.` 33 - with CPU profile: `./graph.test -test.run=XXX -test.bench=. -test.cpuprofile=cpu.out` 34 - analyze profile: `go tool pprof cpu.out` 35 - with mem profile: `./graph.test -test.run=XXX -test.bench=. -test.memprofile mem.out` 36 - analyze profile: `go tool pprof -alloc_space mem.out` 37 - with trace profile: `./graph.test -test.run=XXX -test.bench=. -test.trace trace.out` 38 - analyze profile: `go tool trace -http=:6060 trace.out` 39 40 */ 41 42 const ( 43 historyAgeLimit = 5 44 permanentInitPeriod = 1 45 ) 46 47 var scale = [...]int{1, 10, 100, 1000, 10000} 48 49 type scaleCtx struct { 50 keys map[int]string 51 targets map[int]string 52 targetPrefixes map[int]string 53 } 54 55 func init() { 56 benchEl = newEdgeLookup(nil) 57 } 58 59 func BenchmarkScaleWithoutRec(b *testing.B) { 60 benchmarkScale(b, Opts{ 61 RecordOldRevs: false, 62 }, false, true) 63 } 64 65 func BenchmarkScaleWithoutRecInPlace(b *testing.B) { 66 benchmarkScale(b, Opts{ 67 RecordOldRevs: false, 68 }, true, true) 69 } 70 71 func BenchmarkScaleWithoutRecInPlaceWithoutDel(b *testing.B) { 72 benchmarkScale(b, Opts{ 73 RecordOldRevs: false, 74 }, true, false) 75 } 76 77 func BenchmarkScaleWithRec(b *testing.B) { 78 benchmarkScale(b, Opts{ 79 RecordOldRevs: true, 80 RecordAgeLimit: historyAgeLimit, 81 PermanentInitPeriod: permanentInitPeriod, 82 }, false, true) 83 } 84 85 func BenchmarkScaleWithRecInPlace(b *testing.B) { 86 benchmarkScale(b, Opts{ 87 RecordOldRevs: true, 88 RecordAgeLimit: historyAgeLimit, 89 PermanentInitPeriod: permanentInitPeriod, 90 }, true, true) 91 } 92 93 func BenchmarkScaleWithRecInPlaceWithoutDel(b *testing.B) { 94 benchmarkScale(b, Opts{ 95 RecordOldRevs: true, 96 RecordAgeLimit: historyAgeLimit, 97 PermanentInitPeriod: permanentInitPeriod, 98 }, true, false) 99 } 100 101 func benchmarkScale(b *testing.B, gOpts Opts, wInPlace, withDeletes bool) { 102 for _, n := range scale { 103 b.Run(strconv.Itoa(n), func(b *testing.B) { 104 ctx := setupScale(n) 105 b.ResetTimer() 106 for i := 0; i < b.N; i++ { 107 runScale(ctx, n, gOpts, wInPlace, withDeletes) 108 } 109 }) 110 } 111 } 112 113 func setupScale(n int) scaleCtx { 114 c := scaleCtx{ 115 keys: make(map[int]string), 116 targets: make(map[int]string), 117 targetPrefixes: make(map[int]string), 118 } 119 for i := 0; i < n; i++ { 120 key := fmt.Sprintf("prefix-%d/node-%d", i/10, i%10) 121 targetPrefix := fmt.Sprintf("prefix-%d/", (i/10)-1) 122 target := fmt.Sprintf("%snode-%d", targetPrefix, i%10) 123 c.keys[i] = key 124 c.targets[i] = target 125 c.targetPrefixes[i] = targetPrefix 126 } 127 return c 128 } 129 130 func runScale(c scaleCtx, n int, gOpts Opts, wInPlace bool, withDeletes bool) { 131 g := NewGraph(gOpts) // re-uses benchEl 132 133 // create n nodes 134 w := g.Write(wInPlace, gOpts.RecordOldRevs) 135 for i := 0; i < n; i++ { 136 node := w.SetNode(c.keys[i]) 137 node.SetFlags(ColorFlag(Green), TemporaryFlag()) 138 node.DelFlags(TemporaryFlagIndex) 139 node.SetMetadata(i) 140 node.SetTargets([]RelationTargetDef{ 141 { // static key 142 Relation: "relation1", 143 Label: "label", 144 Key: c.targets[i], 145 }, 146 { // key prefix + key selector 147 Relation: "relation2", 148 Label: "label", 149 Selector: TargetSelector{ 150 KeyPrefixes: []string{c.targetPrefixes[i]}, 151 KeySelector: func(key string) bool { 152 return key == c.targets[i] 153 }, 154 }, 155 }, 156 }) 157 } 158 159 // save + release write handle 160 if !wInPlace { 161 w.Save() 162 } 163 w.Release() 164 165 // read all the nodes 166 r := g.Read() 167 for i := 0; i < n; i++ { 168 key := fmt.Sprintf("prefix-%d/node-%d", i/10, i%10) 169 node := r.GetNode(key) 170 node.GetFlag(ColorFlagIndex) 171 node.GetTargets("relation1") 172 node.GetTargets("relation2") 173 node.GetMetadata() 174 node.GetSources("relation1") 175 node.GetSources("relation2") 176 } 177 r.Release() 178 179 if withDeletes { 180 // remove all nodes 181 w = g.Write(wInPlace, gOpts.RecordOldRevs) 182 for i := 0; i < n; i++ { 183 w.DeleteNode(c.keys[i]) 184 } 185 186 // save + release write handle 187 if !wInPlace { 188 w.Save() 189 } 190 w.Release() 191 } 192 }