Skip to content

Commit f58a526

Browse files
committed
Add benchparse tool
1 parent fc11ed1 commit f58a526

File tree

5 files changed

+319
-47
lines changed

5 files changed

+319
-47
lines changed

benchparse/main.go

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"fmt"
6+
"io"
7+
"os"
8+
"sort"
9+
"strconv"
10+
"strings"
11+
12+
"golang.org/x/perf/benchstat"
13+
)
14+
15+
func main() {
16+
if len(os.Args) < 2 {
17+
panic("need to specify input file")
18+
}
19+
fIn, err := os.Open(os.Args[1])
20+
if err != nil {
21+
panic(err)
22+
}
23+
24+
c := benchstat.Collection{}
25+
if err := c.AddFile("config1", fIn); err != nil {
26+
panic(err)
27+
}
28+
tables := c.Tables()
29+
30+
reports, err := genReports(tables)
31+
if err != nil {
32+
panic(err)
33+
}
34+
if err := processReports(reports); err != nil {
35+
panic(err)
36+
}
37+
38+
fOut, err := os.Create("out.csv")
39+
if err != nil {
40+
panic(err)
41+
}
42+
defer fOut.Close()
43+
if err := writeReports(reports, fOut); err != nil {
44+
panic(err)
45+
}
46+
}
47+
48+
// All metrics for all benchmarks for one HAMT configuration
49+
type HAMTReport struct {
50+
ID string
51+
Benchmarks map[string]Benchmark
52+
}
53+
54+
func (hr *HAMTReport) Write(datawriter *bufio.Writer) error {
55+
// Write title
56+
if _, err := datawriter.WriteString(hr.ID + "\n"); err != nil {
57+
return err
58+
}
59+
60+
// Write benchmarks
61+
for _, benchmark := range hr.Benchmarks {
62+
if err := benchmark.Write(datawriter); err != nil {
63+
return err
64+
}
65+
}
66+
return nil
67+
}
68+
69+
type Benchmark struct {
70+
Name string
71+
Metrics map[string]struct{}
72+
Sweep map[int]map[string]float64 // map[Bitwidth]MetricsMap
73+
}
74+
75+
func (b *Benchmark) Write(datawriter *bufio.Writer) error {
76+
// Get sorted keys
77+
metrics := make([]string, 0)
78+
for metric := range b.Metrics {
79+
metrics = append(metrics, metric)
80+
}
81+
sort.Strings(metrics)
82+
83+
bws := make([]int, 0)
84+
for bw := range b.Sweep {
85+
bws = append(bws, bw)
86+
}
87+
sort.Ints(bws)
88+
89+
// Write headers
90+
headers := []string{"Benchmark", "Bitwidth"}
91+
headers = append(headers, metrics...)
92+
if _, err := datawriter.WriteString(strings.Join(headers, ",")); err != nil {
93+
return err
94+
}
95+
if _, err := datawriter.WriteString("\n"); err != nil {
96+
return err
97+
}
98+
99+
// Write sweeps
100+
for _, bw := range bws {
101+
if _, err := datawriter.WriteString(b.Name); err != nil {
102+
return err
103+
}
104+
if _, err := datawriter.WriteString("," + strconv.Itoa(bw)); err != nil {
105+
return err
106+
}
107+
for _, metric := range metrics {
108+
m, found := b.Sweep[bw][metric]
109+
if !found {
110+
// empty column
111+
if _, err := datawriter.WriteString(","); err != nil {
112+
return err
113+
}
114+
continue
115+
}
116+
if _, err := datawriter.WriteString(fmt.Sprintf(",%.3f", m)); err != nil {
117+
return err
118+
}
119+
}
120+
if _, err := datawriter.WriteString("\n"); err != nil {
121+
return err
122+
}
123+
}
124+
125+
return nil
126+
}
127+
128+
func writeReports(reports map[string]*HAMTReport, w io.Writer) error {
129+
datawriter := bufio.NewWriter(w)
130+
for _, report := range reports {
131+
if err := report.Write(datawriter); err != nil {
132+
return err
133+
}
134+
if _, err := datawriter.WriteString("\n\n"); err != nil {
135+
return err
136+
}
137+
}
138+
return datawriter.Flush()
139+
}
140+
141+
func genReports(tables []*benchstat.Table) (map[string]*HAMTReport, error) {
142+
reports := make(map[string]*HAMTReport)
143+
for _, table := range tables {
144+
for _, row := range table.Rows {
145+
if len(row.Metrics) == 0 {
146+
continue
147+
}
148+
if len(row.Metrics) >= 2 {
149+
panic("don't know how to handle lots of metrics")
150+
}
151+
good, bname, hamtID, bw := parseBench(row.Benchmark)
152+
if !good {
153+
continue
154+
}
155+
fmt.Printf("bname: %s, hamtID: %s, bw: %d\n", bname, hamtID, bw)
156+
157+
if _, found := reports[hamtID]; !found {
158+
reports[hamtID] = &HAMTReport{
159+
ID: hamtID,
160+
Benchmarks: make(map[string]Benchmark),
161+
}
162+
}
163+
if _, found := reports[hamtID].Benchmarks[bname]; !found {
164+
reports[hamtID].Benchmarks[bname] = Benchmark{
165+
Name: bname,
166+
Metrics: make(map[string]struct{}),
167+
Sweep: make(map[int]map[string]float64),
168+
}
169+
}
170+
if _, found := reports[hamtID].Benchmarks[bname].Sweep[bw]; !found {
171+
reports[hamtID].Benchmarks[bname].Sweep[bw] = make(map[string]float64)
172+
}
173+
reports[hamtID].Benchmarks[bname].Metrics[table.Metric] = struct{}{}
174+
reports[hamtID].Benchmarks[bname].Sweep[bw][table.Metric] = row.Metrics[0].Mean
175+
}
176+
}
177+
return reports, nil
178+
}
179+
180+
const GasCostGet = 114617
181+
const GasCostPut = 353640
182+
const GasCostPerBytePut = 1300
183+
184+
const EffectiveTimeGet = 11462
185+
const EffectiveTimePut = 35364
186+
187+
const getsKey = "getEvts"
188+
const putsKey = "putsEvts"
189+
const bytesPutKey = "bytesPut"
190+
const timeKey = "time/op"
191+
192+
// Add GasCost, Time/1000, and EffectiveRuntime
193+
func processReports(reports map[string]*HAMTReport) error {
194+
for _, report := range reports {
195+
for _, bench := range report.Benchmarks {
196+
bench.Metrics["gasCost"] = struct{}{}
197+
bench.Metrics["time/1000"] = struct{}{}
198+
bench.Metrics["effectiveRuntime"] = struct{}{}
199+
200+
for _, row := range bench.Sweep {
201+
row["gasCost"] = row[getsKey]*GasCostGet + row[putsKey]*GasCostPut + row[bytesPutKey]*GasCostPerBytePut
202+
row["time/1000"] = row[timeKey] / float64(1000)
203+
row["effectiveRuntime"] = row["time/1000"] + row[getsKey]*EffectiveTimeGet + row[putsKey]*EffectiveTimePut
204+
}
205+
}
206+
}
207+
return nil
208+
}
209+
210+
// Unedited hamt benchmark strings are ugly but consistent
211+
// BenchmarkName/hamtID_--_bw=Bitwidth-8
212+
// This can be simplified once we clean up generation
213+
func parseBench(bstatBench string) (bool, string, string, int) {
214+
slashSeps := strings.Split(bstatBench, "/")
215+
if len(slashSeps) != 2 {
216+
return false, "", "", 0
217+
}
218+
bname := slashSeps[0]
219+
220+
uScoreSeps := strings.Split(slashSeps[1], "_")
221+
if len(uScoreSeps) != 3 {
222+
return false, "", "", 0
223+
}
224+
hamtID := uScoreSeps[0]
225+
226+
bitwidthStr := strings.TrimPrefix(uScoreSeps[2], "bw=")
227+
bitwidthStr = strings.TrimSuffix(bitwidthStr, "-8")
228+
bw, err := strconv.Atoi(bitwidthStr)
229+
if err != nil {
230+
panic(err)
231+
}
232+
return true, bname, hamtID, bw
233+
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ require (
77
github.com/ipfs/go-ipld-format v0.0.2 // indirect
88
github.com/spaolacci/murmur3 v1.1.0
99
github.com/whyrusleeping/cbor-gen v0.0.0-20200806213330-63aa96ca5488
10+
golang.org/x/perf v0.0.0-20200918155509-d949658356f9
1011
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543
1112
)
1213

go.sum

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
1+
cloud.google.com/go v0.0.0-20170206221025-ce650573d812/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
2+
github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20190129172621-c8b1d7a94ddf/go.mod h1:aJ4qN3TfrelA6NZ6AXsXRfmEVaYin3EDbSPJrKS8OXo=
3+
github.com/aclements/go-gg v0.0.0-20170118225347-6dbb4e4fefb0/go.mod h1:55qNq4vcpkIuHowELi5C8e+1yUHtoLoOUR9QU5j7Tes=
4+
github.com/aclements/go-moremath v0.0.0-20161014184102-0ff62e0875ff/go.mod h1:idZL3yvz4kzx1dsBOAC+oYv6L92P1oFEhUXUB1A/lwQ=
5+
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
6+
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
7+
github.com/gonum/blas v0.0.0-20181208220705-f22b278b28ac/go.mod h1:P32wAyui1PQ58Oce/KYkOqQv8cVw1zAapXOl+dRFGbc=
8+
github.com/gonum/floats v0.0.0-20181209220543-c233463c7e82/go.mod h1:PxC8OnwL11+aosOB5+iEPoV3picfs8tUpkVd0pDo+Kg=
9+
github.com/gonum/internal v0.0.0-20181124074243-f884aa714029/go.mod h1:Pu4dmpkhSyOzRwuXkOgAvijx4o+4YMUJJo9OvPYMkks=
10+
github.com/gonum/lapack v0.0.0-20181123203213-e4cdc5a0bff9/go.mod h1:XA3DeT6rxh2EAE789SSiSJNqxPaC0aE9J8NTOI0Jo/A=
11+
github.com/gonum/matrix v0.0.0-20181209220409-c518dec07be9/go.mod h1:0EXg4mc1CNP0HCqCz+K4ts155PXIlUywf0wqN+GfPZw=
112
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
13+
github.com/googleapis/gax-go v0.0.0-20161107002406-da06d194a00e/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
214
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
315
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
416
github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyFSs7UnsU=
@@ -23,6 +35,7 @@ github.com/ipfs/go-ipld-format v0.0.2 h1:OVAGlyYT6JPZ0pEfGntFPS40lfrDmaDbQwNHEY2
2335
github.com/ipfs/go-ipld-format v0.0.2/go.mod h1:4B6+FM2u9OJ9zCV+kSbgFAZlOrv1Hqbf0INGQgiKf9k=
2436
github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE=
2537
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
38+
github.com/mattn/go-sqlite3 v0.0.0-20161215041557-2d44decb4941/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
2639
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g=
2740
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
2841
github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ=
@@ -70,8 +83,14 @@ golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnf
7083
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
7184
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU=
7285
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
86+
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
87+
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
7388
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
7489
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
90+
golang.org/x/oauth2 v0.0.0-20170207211851-4464e7848382/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
91+
golang.org/x/perf v0.0.0-20200918155509-d949658356f9 h1:yVBHF5pcQLKR9B+y+dOJ6y68nqJBDWaZ9DhB1Ohg0qE=
92+
golang.org/x/perf v0.0.0-20200918155509-d949658356f9/go.mod h1:FrqOtQDO3iMDVUtw5nNTDFpR1HUCGh00M3kj2wiSzLQ=
93+
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
7594
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
7695
golang.org/x/sys v0.0.0-20190219092855-153ac476189d h1:Z0Ahzd7HltpJtjAHHxX8QFP3j1yYgiuvjbjRzDj/KH0=
7796
golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -80,3 +99,6 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
8099
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
81100
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
82101
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
102+
google.golang.org/api v0.0.0-20170206182103-3d017632ea10/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
103+
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
104+
google.golang.org/grpc v0.0.0-20170208002647-2a6bf6142e96/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=

0 commit comments

Comments
 (0)