-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathbenchmarks.go
148 lines (135 loc) · 3.33 KB
/
benchmarks.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
136
137
138
139
140
141
142
143
144
145
146
147
148
package eval
import (
"fmt"
"os"
"os/exec"
"path"
"regexp"
"strconv"
)
type Benchmark struct {
command []string
// Config has configuration related to the benchmark workload under test
// "bench" is a map with benchmark options
Config KeyValue
regex *regexp.Regexp
}
func (b Benchmark) Name() string {
return b.Config["name"].(string)
}
// goArgs converts key-value pairs to options using Go's flag syntax for
// arguments, where KeyValue{"key": "value"} would be passed as -key=value.
func goArgs(kvs []KeyValuePair) []string {
var args []string
for _, kv := range kvs {
args = append(args, fmt.Sprintf("-%s=%v", kv.Key, kv.Val))
}
return args
}
func (b Benchmark) Command() []string {
var args []string
args = append(args, b.command...)
opts := b.Config["bench"].(KeyValue)
args = append(args, goArgs(opts.Pairs())...)
return args
}
// parseLineResult matches against a line to identify a benchmark and value
//
// interpreting the value is left to the caller, based on the benchmark
func (b Benchmark) parseLineResult(line string) (bench string, val float64,
ok bool) {
matches := b.regex.FindStringSubmatch(line)
if matches == nil {
ok = false
return
}
benchIdx := b.regex.SubexpIndex("bench")
bench = matches[benchIdx]
valIdx := b.regex.SubexpIndex("val")
var err error
val, err = strconv.ParseFloat(matches[valIdx], 10)
if err != nil {
panic(fmt.Sprintf("unexpected number %v", matches[valIdx]))
}
ok = true
return
}
// parseLine translates one line of output to maybe one observation
func (b Benchmark) lineToObservation(line string) (o Observation, ok bool) {
bench, val, ok := b.parseLineResult(line)
if !ok {
return Observation{}, false
}
conf := b.Config.Clone()
conf["bench"].(KeyValue)["name"] = bench
return Observation{
Config: conf,
Values: KeyValue{"val": val},
}, true
}
func (b Benchmark) ParseOutput(lines []string) []Observation {
var obs []Observation
for _, line := range lines {
o, ok := b.lineToObservation(line)
if ok {
obs = append(obs, o)
}
}
return obs
}
func benchFromRegex(command []string, name string,
opts KeyValue, r string) Benchmark {
return Benchmark{
command: command,
Config: KeyValue{"bench": opts, "name": name},
regex: regexp.MustCompile(r),
}
}
func LargefileBench(fileSizeMb int) Benchmark {
return benchFromRegex(
[]string{"${GO_NFSD_PATH}/fs-largefile"},
"largefile",
KeyValue{"file-size": float64(fileSizeMb)},
`fs-(?P<bench>largefile):.* throughput (?P<val>[0-9.]*) MB/s`,
)
}
func SmallfileBench(benchtime string, threads int) Benchmark {
return benchFromRegex(
[]string{"${GO_NFSD_PATH}/fs-smallfile"},
"smallfile",
KeyValue{
"benchtime": benchtime,
"start": float64(threads),
"threads": float64(threads),
},
`fs-(?P<bench>smallfile): [0-9]+ (?P<val>[0-9.]*) file/sec`,
)
}
func AppBench() Benchmark {
return benchFromRegex(
[]string{path.Join("${GO_NFSD_PATH}", "bench", "app-bench.sh"),
"${XV6_PATH}",
"/mnt/nfs"},
"app",
KeyValue{},
`(?P<bench>app)-bench (?P<val>[0-9.]*) app/s`,
)
}
func PrepareBenchmarks() {
dir, err := os.Getwd()
if err != nil {
panic(err)
}
os.Chdir(goNfsdPath())
err = exec.Command("go", "build",
"./cmd/fs-largefile").Run()
if err != nil {
panic(err)
}
err = exec.Command("go", "build",
"./cmd/fs-smallfile").Run()
if err != nil {
panic(err)
}
os.Chdir(dir)
}