go.ligato.io/vpp-agent/v3@v3.5.0/plugins/kvscheduler/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 kvscheduler_test
    16  
    17  import (
    18  	"context"
    19  	"flag"
    20  	"fmt"
    21  	"strconv"
    22  	"testing"
    23  
    24  	"go.ligato.io/cn-infra/v2/logging"
    25  	_ "go.ligato.io/cn-infra/v2/logging/logrus" // for setting default registry
    26  
    27  	mock_ifplugin "go.ligato.io/vpp-agent/v3/examples/kvscheduler/mock_plugins/ifplugin"
    28  	"go.ligato.io/vpp-agent/v3/examples/kvscheduler/mock_plugins/ifplugin/model"
    29  	mock_l2plugin "go.ligato.io/vpp-agent/v3/examples/kvscheduler/mock_plugins/l2plugin"
    30  	"go.ligato.io/vpp-agent/v3/examples/kvscheduler/mock_plugins/l2plugin/model"
    31  	"go.ligato.io/vpp-agent/v3/pkg/models"
    32  	. "go.ligato.io/vpp-agent/v3/plugins/kvscheduler"
    33  	. "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/api"
    34  )
    35  
    36  /*
    37  ------------------------
    38   KVScheduler benchmarks
    39  ------------------------
    40  - starts scheduler together with mocked ifplugin and l2plugin
    41  - configures 1/10/100/1000 number of interfaces with bridge domain
    42  
    43  How to run:
    44    - build test binary	`go test -c`
    45    - run all benchmarks:	`./kvscheduler.test -test.run=XXX -test.bench=.`
    46    - with CPU profile:	`./kvscheduler.test -test.run=XXX -test.bench=. -test.cpuprofile=cpu.out`
    47      - analyze profile: `go tool pprof cpu.out`
    48    - with mem profile:	`./kvscheduler.test -test.run=XXX -test.bench=. -memprofile mem.out`
    49      - analyze profile: `go tool pprof -alloc_space mem.out`
    50    - with trace profile:	`./kvscheduler.test -test.run=XXX -test.bench=. -trace trace.out`
    51      - analyze profile: `go tool trace -http=:6060 trace.out`
    52  
    53  */
    54  
    55  func BenchmarkScale(b *testing.B) {
    56  	benchmarkScale(b, true)
    57  }
    58  
    59  func BenchmarkScaleWithoutSimulation(b *testing.B) {
    60  	benchmarkScale(b, false)
    61  }
    62  
    63  func benchmarkScale(b *testing.B, withSimulation bool) {
    64  	for _, n := range [...]int{1, 10, 100, 1000} {
    65  		b.Run(strconv.Itoa(n), func(b *testing.B) {
    66  			b.ResetTimer()
    67  			for i := 0; i < b.N; i++ {
    68  				err := runScale(n, withSimulation)
    69  				if err != nil {
    70  					b.Fatal(err)
    71  				}
    72  			}
    73  		})
    74  	}
    75  }
    76  
    77  // result should be saved to global variable to prevent compiler optimization
    78  var seqNum uint64
    79  
    80  func runScale(n int, withSimulation bool) error {
    81  	c := setupScale()
    82  	defer teardownScale(c)
    83  
    84  	// run non-resync transaction against empty SB
    85  	txn := c.scheduler.StartNBTransaction()
    86  
    87  	// create single bridge domain
    88  	valBd := &mock_l2.BridgeDomain{
    89  		Name: fmt.Sprintf("bd-%d", 1),
    90  	}
    91  	// create n interfaces for bridge domain
    92  	for i := 0; i < n; i++ {
    93  		valIface := &mock_interfaces.Interface{
    94  			Name: fmt.Sprintf("iface-%d", i),
    95  			Type: mock_interfaces.Interface_LOOPBACK,
    96  		}
    97  		valBd.Interfaces = append(valBd.Interfaces, &mock_l2.BridgeDomain_Interface{
    98  			Name: valIface.Name,
    99  		})
   100  		txn.SetValue(models.Key(valIface), valIface)
   101  	}
   102  	txn.SetValue(models.Key(valBd), valBd)
   103  
   104  	testCtx := context.Background()
   105  	if withSimulation {
   106  		testCtx = WithSimulation(testCtx)
   107  	}
   108  	seq, err := txn.Commit(WithDescription(testCtx, "benchmarking scale"))
   109  	if err != nil {
   110  		return err
   111  	}
   112  
   113  	seqNum = seq
   114  
   115  	return err
   116  }
   117  
   118  func setupScale() *runCtx {
   119  	// prepare run context
   120  	c := newRunCtx()
   121  	if err := c.Init(); err != nil {
   122  		panic(err)
   123  	}
   124  	return c
   125  }
   126  
   127  func teardownScale(c *runCtx) {
   128  	if err := c.Close(); err != nil {
   129  		panic(err)
   130  	}
   131  }
   132  
   133  type runCtx struct {
   134  	scheduler *Scheduler
   135  	IfPlugin  *mock_ifplugin.IfPlugin
   136  	L2Plugin  *mock_l2plugin.L2Plugin
   137  }
   138  
   139  func newRunCtx() *runCtx {
   140  	c := &runCtx{}
   141  	c.scheduler = NewPlugin(UseDeps(func(deps *Deps) {
   142  		deps.HTTPHandlers = nil
   143  	}))
   144  	c.IfPlugin = mock_ifplugin.NewPlugin(mock_ifplugin.UseDeps(
   145  		func(deps *mock_ifplugin.Deps) {
   146  			deps.KVScheduler = c.scheduler
   147  		}))
   148  	c.L2Plugin = mock_l2plugin.NewPlugin(mock_l2plugin.UseDeps(
   149  		func(deps *mock_l2plugin.Deps) {
   150  			deps.KVScheduler = c.scheduler
   151  		}))
   152  	return c
   153  }
   154  
   155  func (c *runCtx) Init() error {
   156  	if err := c.scheduler.Init(); err != nil {
   157  		return err
   158  	}
   159  	if err := c.IfPlugin.Init(); err != nil {
   160  		return err
   161  	}
   162  	if err := c.L2Plugin.Init(); err != nil {
   163  		return err
   164  	}
   165  	return nil
   166  }
   167  
   168  func (c *runCtx) Close() error {
   169  	if err := c.L2Plugin.Close(); err != nil {
   170  		return err
   171  	}
   172  	if err := c.IfPlugin.Close(); err != nil {
   173  		return err
   174  	}
   175  	if err := c.scheduler.Close(); err != nil {
   176  		return err
   177  	}
   178  	logging.DefaultRegistry.ClearRegistry()
   179  	return nil
   180  }
   181  
   182  var scaleFlag = flag.Int("scale", 10, "number of items for scale test")
   183  
   184  func TestScale(t *testing.T) {
   185  	if err := runScale(*scaleFlag, true); err != nil {
   186  		t.Fatal(err)
   187  	}
   188  }