Skip to content

Commit

Permalink
Add new Go Benchmarks (#329)
Browse files Browse the repository at this point in the history
A few new benchmarks, which can be useful when validating improvements
to the implementation.

Signed-off-by: Antonin Bas <[email protected]>
  • Loading branch information
antoninbas authored and heanlan committed Dec 7, 2023
1 parent 4f4d653 commit 27b72b2
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 59 deletions.
114 changes: 69 additions & 45 deletions pkg/entities/set_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,62 +6,86 @@ import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

const (
testTemplateID = uint16(256)

testIPv4Addr1 = "10.0.0.1"
testIPv4Addr2 = "10.0.0.2"
testIPv6Addr1 = "2001:0:3238:dfe1:63::fefb"
testIPv6Addr2 = "2001:0:3238:dfe1:63::fefc"
)

func TestAddRecordIPv4Addresses(t *testing.T) {
// Test with template encodingSet
elements := make([]InfoElementWithValue, 0)
ie1 := NewIPAddressInfoElement(NewInfoElement("sourceIPv4Address", 8, 18, 0, 4), nil)
ie2 := NewIPAddressInfoElement(NewInfoElement("destinationIPv4Address", 12, 18, 0, 4), nil)
elements = append(elements, ie1, ie2)
encodingSet := NewSet(false)
err := encodingSet.PrepareSet(Template, testTemplateID)
assert.NoError(t, err)
encodingSet.AddRecord(elements, 256)
_, _, exist := encodingSet.GetRecords()[0].GetInfoElementWithValue("sourceIPv4Address")
assert.Equal(t, true, exist)
_, _, exist = encodingSet.GetRecords()[0].GetInfoElementWithValue("destinationIPv4Address")
assert.Equal(t, true, exist)
encodingSet.ResetSet()
// Test with data encodingSet
err = encodingSet.PrepareSet(Data, testTemplateID)
assert.NoError(t, err)
elements = make([]InfoElementWithValue, 0)
ie1 = NewIPAddressInfoElement(NewInfoElement("sourceIPv4Address", 8, 18, 0, 4), net.ParseIP("10.0.0.1").To4())
ie2 = NewIPAddressInfoElement(NewInfoElement("destinationIPv4Address", 12, 18, 0, 4), net.ParseIP("10.0.0.2").To4())
elements = append(elements, ie1, ie2)
err = encodingSet.AddRecord(elements, 256)
assert.NoError(t, err)
assert.Equal(t, []byte{0xa, 0x0, 0x0, 0x1, 0xa, 0x0, 0x0, 0x2}, encodingSet.GetRecords()[0].GetBuffer())
}
func testAddRecordIPAddresses(t testing.TB, isIPv6 bool) {
var sourceIE, destinationIE *InfoElement
if isIPv6 {
sourceIE = NewInfoElement("sourceIPv6Address", 27, 19, 0, 16)
destinationIE = NewInfoElement("destinationIPv6Address", 28, 19, 0, 16)
} else {
sourceIE = NewInfoElement("sourceIPv4Address", 8, 18, 0, 4)
destinationIE = NewInfoElement("destinationIPv4Address", 12, 18, 0, 4)
}

func TestAddRecordIPv6Addresses(t *testing.T) {
// Test with template record
elements := make([]InfoElementWithValue, 0)
ie1 := NewIPAddressInfoElement(NewInfoElement("sourceIPv6Address", 27, 19, 0, 16), nil)
ie2 := NewIPAddressInfoElement(NewInfoElement("destinationIPv6Address", 28, 19, 0, 16), nil)
elements = append(elements, ie1, ie2)
elements := []InfoElementWithValue{
NewIPAddressInfoElement(sourceIE, nil),
NewIPAddressInfoElement(destinationIE, nil),
}
newSet := NewSet(false)
err := newSet.PrepareSet(Template, testTemplateID)
assert.NoError(t, err)
newSet.AddRecord(elements, 256)
assert.Equal(t, []byte{0x1, 0x0, 0x0, 0x2, 0x0, 0x1b, 0x0, 0x10, 0x0, 0x1c, 0x0, 0x10}, newSet.GetRecords()[0].GetBuffer())
require.NoError(t, newSet.PrepareSet(Template, testTemplateID))
require.NoError(t, newSet.AddRecord(elements, 256))
records := newSet.GetRecords()
require.NotEmpty(t, records)
record := records[0]
if isIPv6 {
_, _, exist := record.GetInfoElementWithValue("sourceIPv6Address")
assert.Equal(t, true, exist)
_, _, exist = record.GetInfoElementWithValue("destinationIPv6Address")
assert.Equal(t, true, exist)
} else {
_, _, exist := record.GetInfoElementWithValue("sourceIPv4Address")
assert.Equal(t, true, exist)
_, _, exist = record.GetInfoElementWithValue("destinationIPv4Address")
assert.Equal(t, true, exist)
}
newSet.ResetSet()

// Test with data record
err = newSet.PrepareSet(Data, testTemplateID)
assert.NoError(t, err)
elements = make([]InfoElementWithValue, 0)
ie1 = NewIPAddressInfoElement(NewInfoElement("sourceIPv6Address", 27, 19, 0, 16), net.ParseIP("2001:0:3238:DFE1:63::FEFB"))
ie2 = NewIPAddressInfoElement(NewInfoElement("destinationIPv6Address", 28, 19, 0, 16), net.ParseIP("2001:0:3238:DFE1:63::FEFC"))
elements = append(elements, ie1, ie2)
newSet.AddRecord(elements, 256)
srcIP := []byte(net.ParseIP("2001:0:3238:DFE1:63::FEFB"))
dstIP := []byte(net.ParseIP("2001:0:3238:DFE1:63::FEFC"))
assert.Equal(t, append(srcIP, dstIP...), newSet.GetRecords()[0].GetBuffer())
require.NoError(t, newSet.PrepareSet(Data, testTemplateID))
var ip1, ip2 net.IP
if isIPv6 {
ip1 = net.ParseIP(testIPv6Addr1)
ip2 = net.ParseIP(testIPv6Addr2)
} else {
ip1 = net.ParseIP(testIPv4Addr1).To4()
ip2 = net.ParseIP(testIPv4Addr2).To4()
}
elements = []InfoElementWithValue{
NewIPAddressInfoElement(sourceIE, ip1),
NewIPAddressInfoElement(destinationIE, ip2),
}
require.NoError(t, newSet.AddRecord(elements, 256))
expectedBuf := make([]byte, 0, len(ip1)+len(ip2))
expectedBuf = append(expectedBuf, ip1...)
expectedBuf = append(expectedBuf, ip2...)
assert.Equal(t, expectedBuf, newSet.GetRecords()[0].GetBuffer())
}

func TestAddRecordIPAddresses(t *testing.T) {
t.Run("ipv4", func(t *testing.T) { testAddRecordIPAddresses(t, false) })
t.Run("ipv6", func(t *testing.T) { testAddRecordIPAddresses(t, true) })
}

func BenchmarkAddRecordIPAddresses(b *testing.B) {
bench := func(b *testing.B, isIPv6 bool) {
for i := 0; i < b.N; i++ {
testAddRecordIPAddresses(b, isIPv6)
}
}
b.Run("ipv4", func(b *testing.B) { bench(b, false) })
b.Run("ipv6", func(b *testing.B) { bench(b, true) })
}

func TestGetSetType(t *testing.T) {
Expand Down
30 changes: 28 additions & 2 deletions pkg/intermediate/aggregate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/vmware/go-ipfix/pkg/entities"
"github.com/vmware/go-ipfix/pkg/registry"
Expand Down Expand Up @@ -147,7 +148,7 @@ func createMsgwithTemplateSet(isIPv6 bool) *entities.Message {
}

// TODO:Cleanup this function using a loop, to make it easy to add elements for testing.
func createDataMsgForSrc(t *testing.T, isIPv6 bool, isIntraNode bool, isUpdatedRecord bool, isToExternal bool, isEgressDeny bool) *entities.Message {
func createDataMsgForSrc(t testing.TB, isIPv6 bool, isIntraNode bool, isUpdatedRecord bool, isToExternal bool, isEgressDeny bool) *entities.Message {
set := entities.NewSet(true)
set.PrepareSet(entities.Data, testTemplateID)
elements := make([]entities.InfoElementWithValue, 0)
Expand Down Expand Up @@ -261,7 +262,7 @@ func createDataMsgForSrc(t *testing.T, isIPv6 bool, isIntraNode bool, isUpdatedR
return message
}

func createDataMsgForDst(t *testing.T, isIPv6 bool, isIntraNode bool, isUpdatedRecord bool, isIngressReject bool, isIngressDrop bool) *entities.Message {
func createDataMsgForDst(t testing.TB, isIPv6 bool, isIntraNode bool, isUpdatedRecord bool, isIngressReject bool, isIngressDrop bool) *entities.Message {
set := entities.NewSet(true)
set.PrepareSet(entities.Data, testTemplateID)
elements := make([]entities.InfoElementWithValue, 0)
Expand Down Expand Up @@ -511,6 +512,31 @@ func TestAggregationProcess(t *testing.T) {
assert.Equalf(t, aggRecord.Record, dataMsg.GetSet().GetRecords()[0], "records should be equal")
}

func BenchmarkAggregateMsgByFlowKey(b *testing.B) {
bench := func(b *testing.B, isIPv6 bool) {
messageChan := make(chan *entities.Message)
input := AggregationInput{
MessageChan: messageChan,
WorkerNum: 1, // not relevant for this benchmark (not calling Start)
CorrelateFields: fields,
}
for i := 0; i < b.N; i++ {
b.StopTimer()
ap, err := InitAggregationProcess(input)
require.NoError(b, err)
msg1 := createDataMsgForSrc(b, isIPv6, false, false, false, false)
msg2 := createDataMsgForDst(b, isIPv6, false, false, false, false)
b.StartTimer()
require.NoError(b, ap.AggregateMsgByFlowKey(msg1))
require.NoError(b, ap.AggregateMsgByFlowKey(msg2))
assert.EqualValues(b, 1, ap.GetNumFlows())
}
}

b.Run("ipv4", func(b *testing.B) { bench(b, false) })
b.Run("ipv6", func(b *testing.B) { bench(b, true) })
}

func TestCorrelateRecordsForInterNodeFlow(t *testing.T) {
messageChan := make(chan *entities.Message)
input := AggregationInput{
Expand Down
63 changes: 62 additions & 1 deletion pkg/test/collector_perf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import (

const (
numOfExporters = 100
numOfRecords = 600
numOfRecords = 1000
)

/*
Expand Down Expand Up @@ -106,6 +106,67 @@ func BenchmarkMultipleExportersToCollector(b *testing.B) {
waitForCollectorStatus(b, cp, false)
}

func BenchmarkCollector(b *testing.B) {
bench := func(b *testing.B, isIPv6 bool) {
disableLogToStderr()
ctrl := gomock.NewController(b)
defer ctrl.Finish()
collectorInput := collector.CollectorInput{
Address: "127.0.0.1:0",
Protocol: "tcp",
TemplateTTL: 0,
}
cp, err := collector.InitCollectingProcess(collectorInput)
if err != nil {
b.Fatalf("cannot start collecting process on %s: %v", cp.GetAddress().String(), err)
}
go cp.Start()
waitForCollectorStatus(b, cp, true)
exporterInput := exporter.ExporterInput{
CollectorAddress: cp.GetAddress().String(),
CollectorProtocol: cp.GetAddress().Network(),
ObservationDomainID: 0,
}
exporter, err := exporter.InitExportingProcess(exporterInput)
if err != nil {
b.Errorf("cannot start exporting process: %v", err)
}
templateID := exporter.NewTemplateID()
exporter.SendSet(createTemplateSet(templateID, isIPv6))
dataSet := createDataSet(templateID, true, isIPv6, false)

b.ResetTimer()

for i := 0; i < b.N; i++ {
b.StopTimer()
ch := make(chan struct{})
go func() {
count := 0
for range cp.GetMsgChan() {
count++
if count == numOfRecords {
close(ch)
return
}
}
}()
b.StartTimer()
for j := 0; j < numOfRecords; j++ {
exporter.SendSet(dataSet)
}
<-ch
}

b.StopTimer()
exporter.CloseConnToCollector()
cp.Stop()
waitForCollectorStatus(b, cp, false)
}

b.Run("ipv4", func(b *testing.B) { bench(b, false) })
b.Run("ipv6", func(b *testing.B) { bench(b, true) })
}

func disableLogToStderr() {
klogFlagSet := flag.NewFlagSet("klog", flag.ContinueOnError)
klog.InitFlags(klogFlagSet)
Expand Down
37 changes: 26 additions & 11 deletions pkg/test/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,15 @@ var (
"reversePacketDeltaCount",
"reverseOctetTotalCount",
}
// same for IPv4 and IPv6
numFields = len(commonFields) + len(ianaIPv4Fields) + len(antreaCommonFields) + len(antreaIPv4) + len(reverseFields)
)

// will be initialized in init() after loading the registry
var templatePacketIPv4, dataPacket1IPv4, dataPacket2IPv4, templatePacketIPv6, dataPacket1IPv6, dataPacket2IPv6 []byte

type testRecord struct {
isIPv6 bool
srcIP net.IP
dstIP net.IP
srcPort uint16
Expand All @@ -95,9 +98,12 @@ type testRecord struct {
tcpState string
}

type testRecordOptions func(*testRecord)

// getTestRecord outputs required testRecords with hardcoded values.
func getTestRecord(isSrcNode, isIPv6 bool) testRecord {
func getTestRecord(isSrcNode, isIPv6 bool, options ...testRecordOptions) *testRecord {
record := testRecord{
isIPv6: isIPv6,
srcPort: uint16(1234),
dstPort: uint16(5678),
proto: uint8(6),
Expand All @@ -112,6 +118,9 @@ func getTestRecord(isSrcNode, isIPv6 bool) testRecord {
record.srcIP = net.ParseIP("2001:0:3238:DFE1:63::FEFB")
record.dstIP = net.ParseIP("2001:0:3238:DFE1:63::FEFC")
}
for _, option := range options {
option(&record)
}
record.flowStart = uint32(1257893000)
if !isSrcNode {
record.flowEnd = uint32(1257896000)
Expand Down Expand Up @@ -146,13 +155,13 @@ func getTestRecord(isSrcNode, isIPv6 bool) testRecord {
record.dstClusterIP = net.ParseIP("2001:0:3238:BBBB:63::AAAA")
}
}
return record
return &record
}

func createTemplateSet(templateID uint16, isIPv6 bool) entities.Set {
templateSet := entities.NewSet(false)
templateSet.PrepareSet(entities.Template, templateID)
elements := make([]entities.InfoElementWithValue, 0)
elements := make([]entities.InfoElementWithValue, 0, numFields)
ianaFields := ianaIPv4Fields
if isIPv6 {
ianaFields = ianaIPv6Fields
Expand Down Expand Up @@ -183,22 +192,28 @@ func createTemplateSet(templateID uint16, isIPv6 bool) entities.Set {
return templateSet
}

func createDataSet(templateID uint16, isSrcNode, isIPv6 bool, isMultipleRecord bool) entities.Set {
func createDataSetForTestRecord(templateID uint16, testRec *testRecord, count int) entities.Set {
dataSet := entities.NewSet(false)
dataSet.PrepareSet(entities.Data, templateID)
elements := getDataRecordElements(isSrcNode, isIPv6)
dataSet.AddRecord(elements, templateID)
if isMultipleRecord {
for i := 0; i < count; i++ {
dataSet.PrepareSet(entities.Data, templateID)
elements = getDataRecordElements(isSrcNode, isIPv6)
elements := getDataRecordElements(testRec)
dataSet.AddRecord(elements, templateID)
}
return dataSet
}

func getDataRecordElements(isSrcNode, isIPv6 bool) []entities.InfoElementWithValue {
func createDataSet(templateID uint16, isSrcNode, isIPv6 bool, isMultipleRecord bool) entities.Set {
testRec := getTestRecord(isSrcNode, isIPv6)
elements := make([]entities.InfoElementWithValue, 0)
count := 1
if isMultipleRecord {
count = 2
}
return createDataSetForTestRecord(templateID, testRec, count)
}

func getDataRecordElements(testRec *testRecord) []entities.InfoElementWithValue {
isIPv6 := testRec.isIPv6
elements := make([]entities.InfoElementWithValue, 0, numFields)
ianaFields := ianaIPv4Fields
if isIPv6 {
ianaFields = ianaIPv6Fields
Expand Down

0 comments on commit 27b72b2

Please sign in to comment.