-
Notifications
You must be signed in to change notification settings - Fork 96
/
Copy pathmain.go
135 lines (130 loc) · 3.97 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT
// Package main implements benchmarks for the STUN package
package main
import (
"context"
"crypto/rand"
"errors"
"flag"
"log"
mathRand "math/rand"
"os"
"os/signal"
"runtime"
"runtime/pprof"
"sync/atomic"
"time"
"github.com/pion/stun/v3"
)
var (
workers = flag.Int("w", runtime.GOMAXPROCS(0), "concurrent workers") //nolint:gochecknoglobals
uriStr = flag.String("uri", "stun:localhost:3478", "URI of STUN server") //nolint:gochecknoglobals
duration = flag.Duration("d", time.Minute, "benchmark duration") //nolint:gochecknoglobals
cpuProfile = flag.String("cpuprofile", "", "file output of pprof cpu profile") //nolint:gochecknoglobals
memProfile = flag.String("memprofile", "", "file output of pprof memory profile") //nolint:gochecknoglobals
realRand = flag.Bool("crypt", false, "use crypto/rand as random source") //nolint:gochecknoglobals
)
func main() { //nolint:gocognit
flag.Parse()
uri, err := stun.ParseURI(*uriStr)
if err != nil {
log.Fatalf("Failed to parse URI '%s': %s", *uriStr, err)
}
signals := make(chan os.Signal, 1)
signal.Notify(signals, os.Interrupt)
start := time.Now()
var (
request int64
requestOK int64
requestErr int64
)
if *cpuProfile != "" {
f, createErr := os.Create(*cpuProfile)
if createErr != nil {
log.Fatalf("Failed to create CPU profile output file: %s", createErr)
}
if pprofErr := pprof.StartCPUProfile(f); pprofErr != nil {
log.Fatalf("Failed to start pprof CPU profiling: %s", pprofErr)
}
defer func() {
pprof.StopCPUProfile()
if closeErr := f.Close(); closeErr != nil {
log.Printf("Failed to close CPU profile output file: %s", closeErr)
} else {
log.Printf("Saved cpu profile to: %s", *cpuProfile)
}
}()
}
if *memProfile != "" {
f, createErr := os.Create(*memProfile)
if createErr != nil {
log.Panicf("Failed to create memory profile output file: %s", createErr)
}
defer func() {
if pprofErr := pprof.Lookup("heap").WriteTo(f, 1); pprofErr != nil {
log.Fatalf("Failed to write pprof memory profiling: %s", pprofErr)
}
if closeErr := f.Close(); closeErr != nil {
log.Printf("Failed to close memory profile output file: %s", closeErr)
} else {
log.Printf("Saved memory profile to %s", *memProfile)
}
}()
}
ctx, cancel := context.WithTimeout(context.Background(), *duration)
go func() {
for sig := range signals {
log.Printf("Stopping on %s", sig)
cancel()
}
}()
if *realRand {
log.Print("Using crypto/rand as random source for transaction id")
}
for i := 0; i < *workers; i++ {
c, clientErr := stun.DialURI(uri, &stun.DialConfig{})
if clientErr != nil {
log.Panicf("Failed to create client: %s", clientErr)
}
go func() {
req := stun.New()
for {
if *realRand {
if _, err := rand.Read(req.TransactionID[:]); err != nil { //nolint:gosec
log.Fatalf("Failed to generate transaction ID: %s", err)
}
} else {
mathRand.Read(req.TransactionID[:]) //nolint:gosec
}
req.Type = stun.BindingRequest
req.WriteHeader()
atomic.AddInt64(&request, 1)
if doErr := c.Do(req, func(event stun.Event) {
if event.Error != nil {
if !errors.Is(event.Error, stun.ErrTransactionTimeOut) {
log.Printf("Failed STUN transaction: %s", event.Error)
}
atomic.AddInt64(&requestErr, 1)
return
}
atomic.AddInt64(&requestOK, 1)
}); doErr != nil {
if !errors.Is(doErr, stun.ErrTransactionExists) {
log.Printf("Failed STUN transaction: %s", doErr)
}
atomic.AddInt64(&requestErr, 1)
}
}
}()
}
log.Print("Workers started")
<-ctx.Done()
stop := time.Now()
rps := int(float64(atomic.LoadInt64(&requestOK)) / stop.Sub(start).Seconds())
log.Printf("RPS: %v", rps)
if reqErr := atomic.LoadInt64(&requestErr); requestErr != 0 {
log.Printf("Errors: %d", reqErr)
}
log.Printf("Total: %d", atomic.LoadInt64(&request))
}