report.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. // Copyright 2014 Google Inc. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // the file is borrowed from github.com/rakyll/boom/boomer/print.go
  15. package cmd
  16. import (
  17. "fmt"
  18. "sort"
  19. "strings"
  20. "time"
  21. )
  22. const (
  23. barChar = "∎"
  24. )
  25. type result struct {
  26. errStr string
  27. duration time.Duration
  28. }
  29. type report struct {
  30. avgTotal float64
  31. fastest float64
  32. slowest float64
  33. average float64
  34. rps float64
  35. results chan *result
  36. total time.Duration
  37. errorDist map[string]int
  38. lats []float64
  39. }
  40. func printReport(size int, results chan *result, total time.Duration) {
  41. r := &report{
  42. results: results,
  43. total: total,
  44. errorDist: make(map[string]int),
  45. }
  46. r.finalize()
  47. r.print()
  48. }
  49. func printRate(size int, results chan *result, total time.Duration) {
  50. r := &report{
  51. results: results,
  52. total: total,
  53. errorDist: make(map[string]int),
  54. }
  55. r.finalize()
  56. fmt.Printf(" Requests/sec:\t%4.4f\n", r.rps)
  57. }
  58. func (r *report) finalize() {
  59. for {
  60. select {
  61. case res := <-r.results:
  62. if res.errStr != "" {
  63. r.errorDist[res.errStr]++
  64. } else {
  65. r.lats = append(r.lats, res.duration.Seconds())
  66. r.avgTotal += res.duration.Seconds()
  67. }
  68. default:
  69. r.rps = float64(len(r.lats)) / r.total.Seconds()
  70. r.average = r.avgTotal / float64(len(r.lats))
  71. return
  72. }
  73. }
  74. }
  75. func (r *report) print() {
  76. sort.Float64s(r.lats)
  77. if len(r.lats) > 0 {
  78. r.fastest = r.lats[0]
  79. r.slowest = r.lats[len(r.lats)-1]
  80. fmt.Printf("\nSummary:\n")
  81. fmt.Printf(" Total:\t%4.4f secs.\n", r.total.Seconds())
  82. fmt.Printf(" Slowest:\t%4.4f secs.\n", r.slowest)
  83. fmt.Printf(" Fastest:\t%4.4f secs.\n", r.fastest)
  84. fmt.Printf(" Average:\t%4.4f secs.\n", r.average)
  85. fmt.Printf(" Requests/sec:\t%4.4f\n", r.rps)
  86. r.printHistogram()
  87. r.printLatencies()
  88. }
  89. if len(r.errorDist) > 0 {
  90. r.printErrors()
  91. }
  92. }
  93. // Prints percentile latencies.
  94. func (r *report) printLatencies() {
  95. pctls := []int{10, 25, 50, 75, 90, 95, 99}
  96. data := make([]float64, len(pctls))
  97. j := 0
  98. for i := 0; i < len(r.lats) && j < len(pctls); i++ {
  99. current := i * 100 / len(r.lats)
  100. if current >= pctls[j] {
  101. data[j] = r.lats[i]
  102. j++
  103. }
  104. }
  105. fmt.Printf("\nLatency distribution:\n")
  106. for i := 0; i < len(pctls); i++ {
  107. if data[i] > 0 {
  108. fmt.Printf(" %v%% in %4.4f secs.\n", pctls[i], data[i])
  109. }
  110. }
  111. }
  112. func (r *report) printHistogram() {
  113. bc := 10
  114. buckets := make([]float64, bc+1)
  115. counts := make([]int, bc+1)
  116. bs := (r.slowest - r.fastest) / float64(bc)
  117. for i := 0; i < bc; i++ {
  118. buckets[i] = r.fastest + bs*float64(i)
  119. }
  120. buckets[bc] = r.slowest
  121. var bi int
  122. var max int
  123. for i := 0; i < len(r.lats); {
  124. if r.lats[i] <= buckets[bi] {
  125. i++
  126. counts[bi]++
  127. if max < counts[bi] {
  128. max = counts[bi]
  129. }
  130. } else if bi < len(buckets)-1 {
  131. bi++
  132. }
  133. }
  134. fmt.Printf("\nResponse time histogram:\n")
  135. for i := 0; i < len(buckets); i++ {
  136. // Normalize bar lengths.
  137. var barLen int
  138. if max > 0 {
  139. barLen = counts[i] * 40 / max
  140. }
  141. fmt.Printf(" %4.3f [%v]\t|%v\n", buckets[i], counts[i], strings.Repeat(barChar, barLen))
  142. }
  143. }
  144. func (r *report) printErrors() {
  145. fmt.Printf("\nError distribution:\n")
  146. for err, num := range r.errorDist {
  147. fmt.Printf(" [%d]\t%s\n", num, err)
  148. }
  149. }