main.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. /*
  2. *
  3. * Copyright 2017 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. /*
  19. To format the benchmark result:
  20. go run benchmark/benchresult/main.go resultfile
  21. To see the performance change based on a old result:
  22. go run benchmark/benchresult/main.go resultfile_old resultfile
  23. It will print the comparison result of intersection benchmarks between two files.
  24. */
  25. package main
  26. import (
  27. "encoding/gob"
  28. "fmt"
  29. "log"
  30. "os"
  31. "strings"
  32. "time"
  33. "google.golang.org/grpc/benchmark/stats"
  34. )
  35. func createMap(fileName string) map[string]stats.BenchResults {
  36. f, err := os.Open(fileName)
  37. if err != nil {
  38. log.Fatalf("Read file %s error: %s\n", fileName, err)
  39. }
  40. defer f.Close()
  41. var data []stats.BenchResults
  42. decoder := gob.NewDecoder(f)
  43. if err = decoder.Decode(&data); err != nil {
  44. log.Fatalf("Decode file %s error: %s\n", fileName, err)
  45. }
  46. m := make(map[string]stats.BenchResults)
  47. for _, d := range data {
  48. m[d.RunMode+"-"+d.Features.String()] = d
  49. }
  50. return m
  51. }
  52. func intChange(title string, val1, val2 uint64) string {
  53. return fmt.Sprintf("%20s %12d %12d %8.2f%%\n", title, val1, val2, float64(int64(val2)-int64(val1))*100/float64(val1))
  54. }
  55. func floatChange(title string, val1, val2 float64) string {
  56. return fmt.Sprintf("%20s %12.2f %12.2f %8.2f%%\n", title, val1, val2, float64(int64(val2)-int64(val1))*100/float64(val1))
  57. }
  58. func timeChange(title string, val1, val2 time.Duration) string {
  59. return fmt.Sprintf("%20s %12s %12s %8.2f%%\n", title, val1.String(),
  60. val2.String(), float64(val2-val1)*100/float64(val1))
  61. }
  62. func strDiff(title, val1, val2 string) string {
  63. return fmt.Sprintf("%20s %12s %12s\n", title, val1, val2)
  64. }
  65. func compareTwoMap(m1, m2 map[string]stats.BenchResults) {
  66. for k2, v2 := range m2 {
  67. if v1, ok := m1[k2]; ok {
  68. changes := k2 + "\n"
  69. changes += fmt.Sprintf("%20s %12s %12s %8s\n", "Title", "Before", "After", "Percentage")
  70. changes += intChange("TotalOps", v1.Data.TotalOps, v2.Data.TotalOps)
  71. changes += intChange("SendOps", v1.Data.SendOps, v2.Data.SendOps)
  72. changes += intChange("RecvOps", v1.Data.RecvOps, v2.Data.RecvOps)
  73. changes += floatChange("Bytes/op", v1.Data.AllocedBytes, v2.Data.AllocedBytes)
  74. changes += floatChange("Allocs/op", v1.Data.Allocs, v2.Data.Allocs)
  75. changes += floatChange("ReqT/op", v1.Data.ReqT, v2.Data.ReqT)
  76. changes += floatChange("RespT/op", v1.Data.RespT, v2.Data.RespT)
  77. changes += timeChange("50th-Lat", v1.Data.Fiftieth, v2.Data.Fiftieth)
  78. changes += timeChange("90th-Lat", v1.Data.Ninetieth, v2.Data.Ninetieth)
  79. changes += timeChange("99th-Lat", v1.Data.NinetyNinth, v2.Data.NinetyNinth)
  80. changes += timeChange("Avg-Lat", v1.Data.Average, v2.Data.Average)
  81. changes += strDiff("GoVersion", v1.GoVersion, v2.GoVersion)
  82. changes += strDiff("GrpcVersion", v1.GrpcVersion, v2.GrpcVersion)
  83. fmt.Printf("%s\n", changes)
  84. }
  85. }
  86. }
  87. func compareBenchmark(file1, file2 string) {
  88. compareTwoMap(createMap(file1), createMap(file2))
  89. }
  90. func printHeader() {
  91. fmt.Printf("%-80s%12s%12s%12s%18s%18s%18s%18s%12s%12s%12s%12s\n",
  92. "Name", "TotalOps", "SendOps", "RecvOps", "Bytes/op (B)", "Allocs/op (#)",
  93. "RequestT", "ResponseT", "L-50", "L-90", "L-99", "L-Avg")
  94. }
  95. func printline(benchName string, d stats.RunData) {
  96. fmt.Printf("%-80s%12d%12d%12d%18.2f%18.2f%18.2f%18.2f%12v%12v%12v%12v\n",
  97. benchName, d.TotalOps, d.SendOps, d.RecvOps, d.AllocedBytes, d.Allocs,
  98. d.ReqT, d.RespT, d.Fiftieth, d.Ninetieth, d.NinetyNinth, d.Average)
  99. }
  100. func formatBenchmark(fileName string) {
  101. f, err := os.Open(fileName)
  102. if err != nil {
  103. log.Fatalf("Read file %s error: %s\n", fileName, err)
  104. }
  105. defer f.Close()
  106. var results []stats.BenchResults
  107. decoder := gob.NewDecoder(f)
  108. if err = decoder.Decode(&results); err != nil {
  109. log.Fatalf("Decode file %s error: %s\n", fileName, err)
  110. }
  111. if len(results) == 0 {
  112. log.Fatalf("No benchmark results in file %s\n", fileName)
  113. }
  114. fmt.Println("\nShared features:\n" + strings.Repeat("-", 20))
  115. fmt.Print(results[0].Features.SharedFeatures(results[0].SharedFeatures))
  116. fmt.Println(strings.Repeat("-", 35))
  117. wantFeatures := results[0].SharedFeatures
  118. for i := 0; i < len(results[0].SharedFeatures); i++ {
  119. wantFeatures[i] = !wantFeatures[i]
  120. }
  121. printHeader()
  122. for _, r := range results {
  123. printline(r.RunMode+r.Features.PrintableName(wantFeatures), r.Data)
  124. }
  125. }
  126. func main() {
  127. if len(os.Args) == 2 {
  128. formatBenchmark(os.Args[1])
  129. } else {
  130. compareBenchmark(os.Args[1], os.Args[2])
  131. }
  132. }