Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions .github/workflows/decode-bench.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
name: Decode Benchmark

on:
workflow_dispatch:
pull_request:
branches: [ main ]
paths:
- ".github/workflows/decode-bench.yml"
- "decoders/netflow/**"
- "decoders/netflowlegacy/**"
- "decoders/sflow/**"
- "go.mod"
- "go.sum"

jobs:
benchmark:
name: Benchmark (Go ${{ matrix.go-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
go-version: ["1.24.1", "1.25.0", "1.26.1"]

steps:
- name: Check out code
uses: actions/checkout@v6

- name: Set up Go
uses: actions/setup-go@v6
with:
go-version: ${{ matrix.go-version }}
cache: true
cache-dependency-path: |
go.sum
go.mod

- name: Run decoder benchmarks
run: |
go test ./decoders/netflow ./decoders/netflowlegacy ./decoders/sflow \
-run '^$' \
-bench '^BenchmarkDecode' \
-benchmem \
-cpu 1 \
-count 10 | tee bench-${{ matrix.go-version }}.txt

- name: Upload benchmark output
uses: actions/upload-artifact@v4
with:
name: decode-bench-${{ matrix.go-version }}
path: bench-${{ matrix.go-version }}.txt
retention-days: 14

compare:
name: Benchstat
runs-on: ubuntu-latest
needs: benchmark

steps:
- name: Set up Go
uses: actions/setup-go@v6
with:
go-version: "1.26.1"
cache: true

- name: Install benchstat
run: |
go install golang.org/x/perf/cmd/benchstat@latest
echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH"

- name: Download benchmark artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
pattern: decode-bench-*
merge-multiple: true

- name: Compare benchmark results
shell: bash
run: |
mapfile -t files < <(find artifacts -maxdepth 1 -name 'bench-*.txt' | sort)
if [[ "${#files[@]}" -lt 2 ]]; then
echo "expected at least two benchmark files, found ${#files[@]}" >&2
exit 1
fi

benchstat "${files[@]}" | tee benchstat.txt

- name: Publish summary
run: |
{
echo "## Decode Benchstat"
echo
echo '```'
cat benchstat.txt
echo '```'
} >> "$GITHUB_STEP_SUMMARY"

- name: Upload benchstat output
uses: actions/upload-artifact@v4
with:
name: decode-benchstat
path: benchstat.txt
retention-days: 14
50 changes: 50 additions & 0 deletions decoders/netflow/bench_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package netflow

import (
"bytes"
"testing"
)

func BenchmarkDecodeNetFlowV9(b *testing.B) {
templates := CreateTemplateSystem()

template := []byte{
0x00, 0x09, 0x00, 0x01, 0xb3, 0xbf, 0xf6, 0x83, 0x61, 0x8a, 0xa3, 0xa8, 0x32, 0x01, 0xee, 0x98,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x64, 0x01, 0x04, 0x00, 0x17, 0x00, 0x02, 0x00, 0x04,
0x00, 0x01, 0x00, 0x04, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x04,
0x00, 0x0e, 0x00, 0x04, 0x00, 0x15, 0x00, 0x04, 0x00, 0x16, 0x00, 0x04, 0x00, 0x07, 0x00, 0x02,
0x00, 0x0b, 0x00, 0x02, 0x00, 0x10, 0x00, 0x04, 0x00, 0x11, 0x00, 0x04, 0x00, 0x12, 0x00, 0x04,
0x00, 0x09, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01,
0x00, 0x05, 0x00, 0x01, 0x00, 0x3d, 0x00, 0x01, 0x00, 0x59, 0x00, 0x01, 0x00, 0x30, 0x00, 0x02,
0x00, 0xea, 0x00, 0x04, 0x00, 0xeb, 0x00, 0x04,
}

templateBuf := bytes.NewBuffer(template)
var templatePacket NFv9Packet
if err := DecodeMessageVersion(templateBuf, templates, &templatePacket, nil); err != nil {
b.Fatalf("decode template: %v", err)
}

data := []byte{
0x00, 0x09, 0x00, 0x15, 0xb3, 0xbf, 0xf6, 0x83, 0x61, 0x8a, 0xa3, 0xa8, 0x32, 0x01, 0xee, 0x9c,
0x00, 0x00, 0x01, 0x00, 0x01, 0x04, 0x05, 0x5c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x05, 0xdc,
0xc6, 0x26, 0x78, 0xde, 0x58, 0x79, 0xd9, 0xd0, 0x00, 0x00, 0x01, 0x62, 0x00, 0x00, 0x01, 0x30,
0xb3, 0xbf, 0xe6, 0xf9, 0xb3, 0xbf, 0xe6, 0xf9, 0x01, 0xbb, 0x3b, 0x50, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xfc, 0xdf, 0x00, 0x00, 0x18, 0x0e, 0x06, 0x10, 0x00, 0x00, 0x40, 0x00,
0x01, 0x60, 0x00, 0x00, 0x02, 0x60, 0x00, 0x00,
}

b.ReportAllocs()
b.SetBytes(int64(len(data)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
buf := bytes.NewBuffer(data)
var packet NFv9Packet
if err := DecodeMessageVersion(buf, templates, &packet, nil); err != nil {
b.Fatalf("decode v9 packet: %v", err)
}
if len(packet.FlowSets) != 1 {
b.Fatalf("unexpected flowsets: %d", len(packet.FlowSets))
}
}
}
45 changes: 45 additions & 0 deletions decoders/netflowlegacy/bench_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package netflowlegacy

import (
"bytes"
"testing"
)

func BenchmarkDecodeNetFlowV5(b *testing.B) {
data := []byte{
0x00, 0x05, 0x00, 0x06, 0x00, 0x82, 0xc3, 0x48, 0x5b, 0xcd, 0xba, 0x1b, 0x05, 0x97, 0x6d, 0xc7,
0x00, 0x00, 0x64, 0x3d, 0x08, 0x08, 0x00, 0x00, 0x0a, 0x80, 0x02, 0x79, 0x0a, 0x80, 0x02, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x02, 0x4e,
0x00, 0x82, 0x9b, 0x8c, 0x00, 0x82, 0x9b, 0x90, 0x1f, 0x90, 0xb9, 0x18, 0x00, 0x1b, 0x06, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x80, 0x02, 0x77, 0x0a, 0x81, 0x02, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x94,
0x00, 0x82, 0x95, 0xa9, 0x00, 0x82, 0x9a, 0xfb, 0x1f, 0x90, 0xc1, 0x2c, 0x00, 0x12, 0x06, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x81, 0x02, 0x01, 0x0a, 0x80, 0x02, 0x77,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xc2,
0x00, 0x82, 0x95, 0xa9, 0x00, 0x82, 0x9a, 0xfc, 0xc1, 0x2c, 0x1f, 0x90, 0x00, 0x16, 0x06, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x80, 0x02, 0x01, 0x0a, 0x80, 0x02, 0x79,
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x01, 0xf1,
0x00, 0x82, 0x9b, 0x8c, 0x00, 0x82, 0x9b, 0x8f, 0xb9, 0x18, 0x1f, 0x90, 0x00, 0x1b, 0x06, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x80, 0x02, 0x01, 0x0a, 0x80, 0x02, 0x79,
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x02, 0x2e,
0x00, 0x82, 0x9b, 0x90, 0x00, 0x82, 0x9b, 0x9d, 0xb9, 0x1a, 0x1f, 0x90, 0x00, 0x1b, 0x06, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x80, 0x02, 0x79, 0x0a, 0x80, 0x02, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x0b, 0xac,
0x00, 0x82, 0x9b, 0x90, 0x00, 0x82, 0x9b, 0x9d, 0x1f, 0x90, 0xb9, 0x1a, 0x00, 0x1b, 0x06, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}

b.ReportAllocs()
b.SetBytes(int64(len(data)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
buf := bytes.NewBuffer(data)
var packet PacketNetFlowV5
if err := DecodeMessageVersion(buf, &packet); err != nil {
b.Fatalf("decode v5 packet: %v", err)
}
if len(packet.Records) != 6 {
b.Fatalf("unexpected records: %d", len(packet.Records))
}
}
}
36 changes: 36 additions & 0 deletions decoders/sflow/bench_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package sflow

import (
"bytes"
"testing"
)

func BenchmarkDecodeSFlow(b *testing.B) {
data := []byte{
0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0xac, 0x10, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x01, 0xaa, 0x67, 0xee, 0xaa, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x04, 0x13, 0x00, 0x00, 0x08, 0x00,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xaa, 0x00, 0x00, 0x04, 0x13,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x4e, 0x00, 0xff, 0x12, 0x34,
0x35, 0x1b, 0xff, 0xab, 0xcd, 0xef, 0xab, 0x64, 0x81, 0x00, 0x00, 0x20, 0x08, 0x00, 0x45, 0x00,
0x00, 0x3c, 0x5c, 0x07, 0x00, 0x00, 0x7c, 0x01, 0x48, 0xa0, 0xac, 0x10, 0x20, 0xfe, 0xac, 0x10,
0x20, 0xf1, 0x08, 0x00, 0x97, 0x61, 0xa9, 0x48, 0x0c, 0xb2, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
0x77, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x00, 0x00,
}

b.ReportAllocs()
b.SetBytes(int64(len(data)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
buf := bytes.NewBuffer(data)
var packet Packet
if err := DecodeMessageVersion(buf, &packet); err != nil {
b.Fatalf("decode sflow packet: %v", err)
}
if len(packet.Samples) != 1 {
b.Fatalf("unexpected samples: %d", len(packet.Samples))
}
}
}
Loading