go.ligato.io/vpp-agent/v3@v3.5.0/examples/kvscheduler/mock_plugins/scenario/perf.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 scenario
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"log"
    21  	"net"
    22  	"strconv"
    23  	"time"
    24  
    25  	"encoding/binary"
    26  
    27  	"go.ligato.io/vpp-agent/v3/client"
    28  
    29  	interfaces "go.ligato.io/vpp-agent/v3/examples/kvscheduler/mock_plugins/ifplugin/model"
    30  	l2 "go.ligato.io/vpp-agent/v3/examples/kvscheduler/mock_plugins/l2plugin/model"
    31  	"go.ligato.io/vpp-agent/v3/plugins/kvscheduler"
    32  )
    33  
    34  const iterations = 1000
    35  const groupSize = 100
    36  
    37  func profile(c client.ConfigClient, runTxn func(iter int, withOrch bool), description ...string) {
    38  	var (
    39  		total time.Duration
    40  		group time.Duration
    41  	)
    42  
    43  	for _, withOrch := range []bool{false, true} {
    44  		emptyResync(c)
    45  		total = 0
    46  
    47  		// describe perf test
    48  		withOrchStr := "With"
    49  		if !withOrch {
    50  			withOrchStr += "out"
    51  		}
    52  		msg := []string{fmt.Sprintf("%dx Change config (%s Orchestrator)", iterations, withOrchStr)}
    53  		msg = append(msg, description...)
    54  		printMessage(msg...)
    55  
    56  		for i := 0; i < iterations; i++ {
    57  			t := time.Now()
    58  			runTxn(i, withOrch)
    59  			elapsed := time.Since(t)
    60  			total += elapsed
    61  			group += elapsed
    62  
    63  			if (i+1)%groupSize == 0 {
    64  				fmt.Printf(DebugMsgColor, fmt.Sprintf("Txns %d-%d: %v",
    65  					i-groupSize+1, i, group))
    66  				group = 0
    67  			}
    68  		}
    69  		fmt.Printf(DebugMsgColor, fmt.Sprintf("=> Total elapsed time: %v", total))
    70  	}
    71  }
    72  
    73  func emptyResync(c client.ConfigClient) {
    74  	printMessage("Empty Resync")
    75  	err := c.ResyncConfig()
    76  	if err != nil {
    77  		log.Fatalln(err)
    78  	}
    79  }
    80  
    81  func PerfTest() {
    82  	c := client.LocalClient
    83  	listKnownModels(c)
    84  
    85  	// perf test #1
    86  	addTap := func(iter int, withOrch bool) {
    87  		tap := &interfaces.Interface{
    88  			Name:    "tap-" + strconv.Itoa(iter),
    89  			Type:    interfaces.Interface_TAP,
    90  			Enabled: true,
    91  		}
    92  		if withOrch {
    93  			req := c.ChangeRequest()
    94  			req.Update(tap)
    95  			if err := req.Send(context.Background()); err != nil {
    96  				log.Fatalln(err)
    97  			}
    98  		} else {
    99  			txn := kvscheduler.DefaultPlugin.StartNBTransaction()
   100  			txn.SetValue(interfaces.InterfaceKey(tap.GetName()), tap)
   101  			_, err := txn.Commit(context.Background())
   102  			if err != nil {
   103  				log.Fatalln(err)
   104  			}
   105  		}
   106  	}
   107  	profile(c, addTap,
   108  		"  - add new TAP interface")
   109  
   110  	// perf test #3
   111  	var bdIfaces []string
   112  	addTapWithFIB := func(iter int, withOrch bool) {
   113  		tap := &interfaces.Interface{
   114  			Name:    "tap-" + strconv.Itoa(iter),
   115  			Type:    interfaces.Interface_TAP,
   116  			Enabled: true,
   117  		}
   118  
   119  		// bd
   120  		if iter == 0 {
   121  			bdIfaces = []string{}
   122  		}
   123  		bdIfaces = append(bdIfaces, tap.GetName())
   124  		bd := &l2.BridgeDomain{
   125  			Name:       "bd1",
   126  			Interfaces: make([]*l2.BridgeDomain_Interface, 0, len(bdIfaces)),
   127  		}
   128  		for _, iface := range bdIfaces {
   129  			bd.Interfaces = append(bd.Interfaces, &l2.BridgeDomain_Interface{
   130  				Name: iface,
   131  			})
   132  		}
   133  
   134  		// fib
   135  		var hwAddr [6]byte
   136  		binary.BigEndian.PutUint32(hwAddr[2:], uint32(iter))
   137  		fib := &l2.FIBEntry{
   138  			PhysAddress:       net.HardwareAddr(hwAddr[:]).String(),
   139  			BridgeDomain:      bd.GetName(),
   140  			Action:            l2.FIBEntry_FORWARD,
   141  			OutgoingInterface: tap.GetName(),
   142  		}
   143  
   144  		if withOrch {
   145  			req := c.ChangeRequest()
   146  			req.Update(tap, bd, fib)
   147  			if err := req.Send(context.Background()); err != nil {
   148  				log.Fatalln(err)
   149  			}
   150  		} else {
   151  			txn := kvscheduler.DefaultPlugin.StartNBTransaction()
   152  			txn.SetValue(interfaces.InterfaceKey(tap.GetName()), tap)
   153  			txn.SetValue(l2.BridgeDomainKey(bd.GetName()), bd)
   154  			txn.SetValue(l2.FIBKey(fib.BridgeDomain, fib.PhysAddress), fib)
   155  			_, err := txn.Commit(context.Background())
   156  			if err != nil {
   157  				log.Fatalln(err)
   158  			}
   159  		}
   160  	}
   161  	profile(c, addTapWithFIB,
   162  		"  - add new TAP interface",
   163  		"  - insert the new TAP interface into the bridge domain",
   164  		"  - add FIB routing traffic for a certain MAC via the new interface",
   165  	)
   166  }