/* * * Copyright 2017 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ /* To format the benchmark result: go run benchmark/benchresult/main.go resultfile To see the performance change based on a old result: go run benchmark/benchresult/main.go resultfile_old resultfile It will print the comparison result of intersection benchmarks between two files. */ package main import ( "encoding/gob" "fmt" "log" "os" "strconv" "strings" "time" "google.golang.org/grpc/benchmark/stats" ) func createMap(fileName string, m map[string]stats.BenchResults) { f, err := os.Open(fileName) if err != nil { log.Fatalf("Read file %s error: %s\n", fileName, err) } defer f.Close() var data []stats.BenchResults decoder := gob.NewDecoder(f) if err = decoder.Decode(&data); err != nil { log.Fatalf("Decode file %s error: %s\n", fileName, err) } for _, d := range data { m[d.RunMode+"-"+d.Features.String()] = d } } func intChange(title string, val1, val2 int64) string { return fmt.Sprintf("%10s %12s %12s %8.2f%%\n", title, strconv.FormatInt(val1, 10), strconv.FormatInt(val2, 10), float64(val2-val1)*100/float64(val1)) } func timeChange(title int, val1, val2 time.Duration) string { return fmt.Sprintf("%10s %12s %12s %8.2f%%\n", strconv.Itoa(title)+" latency", val1.String(), val2.String(), float64(val2-val1)*100/float64(val1)) } func compareTwoMap(m1, m2 map[string]stats.BenchResults) { for k2, v2 := range m2 { if v1, ok := m1[k2]; ok { changes := k2 + "\n" changes += fmt.Sprintf("%10s %12s %12s %8s\n", "Title", "Before", "After", "Percentage") changes += intChange("Bytes/op", v1.AllocedBytesPerOp, v2.AllocedBytesPerOp) changes += intChange("Allocs/op", v1.AllocsPerOp, v2.AllocsPerOp) changes += timeChange(v1.Latency[1].Percent, v1.Latency[1].Value, v2.Latency[1].Value) changes += timeChange(v1.Latency[2].Percent, v1.Latency[2].Value, v2.Latency[2].Value) fmt.Printf("%s\n", changes) } } } func compareBenchmark(file1, file2 string) { var BenchValueFile1 map[string]stats.BenchResults var BenchValueFile2 map[string]stats.BenchResults BenchValueFile1 = make(map[string]stats.BenchResults) BenchValueFile2 = make(map[string]stats.BenchResults) createMap(file1, BenchValueFile1) createMap(file2, BenchValueFile2) compareTwoMap(BenchValueFile1, BenchValueFile2) } func printline(benchName, ltc50, ltc90, allocByte, allocsOp interface{}) { fmt.Printf("%-80v%12v%12v%12v%12v\n", benchName, ltc50, ltc90, allocByte, allocsOp) } func formatBenchmark(fileName string) { f, err := os.Open(fileName) if err != nil { log.Fatalf("Read file %s error: %s\n", fileName, err) } defer f.Close() var data []stats.BenchResults decoder := gob.NewDecoder(f) if err = decoder.Decode(&data); err != nil { log.Fatalf("Decode file %s error: %s\n", fileName, err) } if len(data) == 0 { log.Fatalf("No data in file %s\n", fileName) } printPos := data[0].SharedPosion fmt.Println("\nShared features:\n" + strings.Repeat("-", 20)) fmt.Print(stats.PartialPrintString(printPos, data[0].Features, true)) fmt.Println(strings.Repeat("-", 35)) for i := 0; i < len(data[0].SharedPosion); i++ { printPos[i] = !printPos[i] } printline("Name", "latency-50", "latency-90", "Alloc (B)", "Alloc (#)") for _, d := range data { name := d.RunMode + stats.PartialPrintString(printPos, d.Features, false) printline(name, d.Latency[1].Value.String(), d.Latency[2].Value.String(), d.AllocedBytesPerOp, d.AllocsPerOp) } } func main() { if len(os.Args) == 2 { formatBenchmark(os.Args[1]) } else { compareBenchmark(os.Args[1], os.Args[2]) } }