You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

131 lines
3.4 KiB

  1. // Copyright 2014 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // Package parse provides support for parsing benchmark results as
  5. // generated by 'go test -bench'.
  6. package parse // import "golang.org/x/tools/benchmark/parse"
  7. import (
  8. "bufio"
  9. "bytes"
  10. "fmt"
  11. "io"
  12. "strconv"
  13. "strings"
  14. )
  15. // Flags used by Benchmark.Measured to indicate
  16. // which measurements a Benchmark contains.
  17. const (
  18. NsPerOp = 1 << iota
  19. MBPerS
  20. AllocedBytesPerOp
  21. AllocsPerOp
  22. )
  23. // Benchmark is one run of a single benchmark.
  24. type Benchmark struct {
  25. Name string // benchmark name
  26. N int // number of iterations
  27. NsPerOp float64 // nanoseconds per iteration
  28. AllocedBytesPerOp uint64 // bytes allocated per iteration
  29. AllocsPerOp uint64 // allocs per iteration
  30. MBPerS float64 // MB processed per second
  31. Measured int // which measurements were recorded
  32. Ord int // ordinal position within a benchmark run
  33. }
  34. // ParseLine extracts a Benchmark from a single line of testing.B
  35. // output.
  36. func ParseLine(line string) (*Benchmark, error) {
  37. fields := strings.Fields(line)
  38. // Two required, positional fields: Name and iterations.
  39. if len(fields) < 2 {
  40. return nil, fmt.Errorf("two fields required, have %d", len(fields))
  41. }
  42. if !strings.HasPrefix(fields[0], "Benchmark") {
  43. return nil, fmt.Errorf(`first field does not start with "Benchmark"`)
  44. }
  45. n, err := strconv.Atoi(fields[1])
  46. if err != nil {
  47. return nil, err
  48. }
  49. b := &Benchmark{Name: fields[0], N: n}
  50. // Parse any remaining pairs of fields; we've parsed one pair already.
  51. for i := 1; i < len(fields)/2; i++ {
  52. b.parseMeasurement(fields[i*2], fields[i*2+1])
  53. }
  54. return b, nil
  55. }
  56. func (b *Benchmark) parseMeasurement(quant string, unit string) {
  57. switch unit {
  58. case "ns/op":
  59. if f, err := strconv.ParseFloat(quant, 64); err == nil {
  60. b.NsPerOp = f
  61. b.Measured |= NsPerOp
  62. }
  63. case "MB/s":
  64. if f, err := strconv.ParseFloat(quant, 64); err == nil {
  65. b.MBPerS = f
  66. b.Measured |= MBPerS
  67. }
  68. case "B/op":
  69. if i, err := strconv.ParseUint(quant, 10, 64); err == nil {
  70. b.AllocedBytesPerOp = i
  71. b.Measured |= AllocedBytesPerOp
  72. }
  73. case "allocs/op":
  74. if i, err := strconv.ParseUint(quant, 10, 64); err == nil {
  75. b.AllocsPerOp = i
  76. b.Measured |= AllocsPerOp
  77. }
  78. }
  79. }
  80. func (b *Benchmark) String() string {
  81. buf := new(bytes.Buffer)
  82. fmt.Fprintf(buf, "%s %d", b.Name, b.N)
  83. if (b.Measured & NsPerOp) != 0 {
  84. fmt.Fprintf(buf, " %.2f ns/op", b.NsPerOp)
  85. }
  86. if (b.Measured & MBPerS) != 0 {
  87. fmt.Fprintf(buf, " %.2f MB/s", b.MBPerS)
  88. }
  89. if (b.Measured & AllocedBytesPerOp) != 0 {
  90. fmt.Fprintf(buf, " %d B/op", b.AllocedBytesPerOp)
  91. }
  92. if (b.Measured & AllocsPerOp) != 0 {
  93. fmt.Fprintf(buf, " %d allocs/op", b.AllocsPerOp)
  94. }
  95. return buf.String()
  96. }
  97. // Set is a collection of benchmarks from one
  98. // testing.B run, keyed by name to facilitate comparison.
  99. type Set map[string][]*Benchmark
  100. // ParseSet extracts a Set from testing.B output.
  101. // ParseSet preserves the order of benchmarks that have identical
  102. // names.
  103. func ParseSet(r io.Reader) (Set, error) {
  104. bb := make(Set)
  105. scan := bufio.NewScanner(r)
  106. ord := 0
  107. for scan.Scan() {
  108. if b, err := ParseLine(scan.Text()); err == nil {
  109. b.Ord = ord
  110. ord++
  111. bb[b.Name] = append(bb[b.Name], b)
  112. }
  113. }
  114. if err := scan.Err(); err != nil {
  115. return nil, err
  116. }
  117. return bb, nil
  118. }