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  }