github.com/jgbaldwinbrown/perf@v0.1.1/benchstat/scaler.go (about) 1 // Copyright 2017 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 5 package benchstat 6 7 import ( 8 "fmt" 9 "strings" 10 ) 11 12 // A Scaler is a function that scales and formats a measurement. 13 // All measurements within a given table row are formatted 14 // using the same scaler, so that the units are consistent 15 // across the row. 16 type Scaler func(float64) string 17 18 // NewScaler returns a Scaler appropriate for formatting 19 // the measurement val, which has the given unit. 20 func NewScaler(val float64, unit string) Scaler { 21 if hasBaseUnit(unit, "ns/op") || hasBaseUnit(unit, "ns/GC") { 22 return timeScaler(val) 23 } 24 25 var format string 26 var scale float64 27 var suffix string 28 29 prescale := 1.0 30 if hasBaseUnit(unit, "MB/s") { 31 prescale = 1e6 32 } 33 34 switch x := val * prescale; { 35 case x >= 99500000000000: 36 format, scale, suffix = "%.0f", 1e12, "T" 37 case x >= 9950000000000: 38 format, scale, suffix = "%.1f", 1e12, "T" 39 case x >= 995000000000: 40 format, scale, suffix = "%.2f", 1e12, "T" 41 case x >= 99500000000: 42 format, scale, suffix = "%.0f", 1e9, "G" 43 case x >= 9950000000: 44 format, scale, suffix = "%.1f", 1e9, "G" 45 case x >= 995000000: 46 format, scale, suffix = "%.2f", 1e9, "G" 47 case x >= 99500000: 48 format, scale, suffix = "%.0f", 1e6, "M" 49 case x >= 9950000: 50 format, scale, suffix = "%.1f", 1e6, "M" 51 case x >= 995000: 52 format, scale, suffix = "%.2f", 1e6, "M" 53 case x >= 99500: 54 format, scale, suffix = "%.0f", 1e3, "k" 55 case x >= 9950: 56 format, scale, suffix = "%.1f", 1e3, "k" 57 case x >= 995: 58 format, scale, suffix = "%.2f", 1e3, "k" 59 case x >= 99.5: 60 format, scale, suffix = "%.0f", 1, "" 61 case x >= 9.95: 62 format, scale, suffix = "%.1f", 1, "" 63 default: 64 format, scale, suffix = "%.2f", 1, "" 65 } 66 67 if hasBaseUnit(unit, "B/op") || hasBaseUnit(unit, "bytes/op") || hasBaseUnit(unit, "bytes") { 68 suffix += "B" 69 } 70 if hasBaseUnit(unit, "MB/s") { 71 suffix += "B/s" 72 } 73 scale /= prescale 74 75 return func(val float64) string { 76 return fmt.Sprintf(format+suffix, val/scale) 77 } 78 } 79 80 func timeScaler(ns float64) Scaler { 81 var format string 82 var scale float64 83 switch x := ns / 1e9; { 84 case x >= 99.5: 85 format, scale = "%.0fs", 1 86 case x >= 9.95: 87 format, scale = "%.1fs", 1 88 case x >= 0.995: 89 format, scale = "%.2fs", 1 90 case x >= 0.0995: 91 format, scale = "%.0fms", 1000 92 case x >= 0.00995: 93 format, scale = "%.1fms", 1000 94 case x >= 0.000995: 95 format, scale = "%.2fms", 1000 96 case x >= 0.0000995: 97 format, scale = "%.0fµs", 1000*1000 98 case x >= 0.00000995: 99 format, scale = "%.1fµs", 1000*1000 100 case x >= 0.000000995: 101 format, scale = "%.2fµs", 1000*1000 102 case x >= 0.0000000995: 103 format, scale = "%.0fns", 1000*1000*1000 104 case x >= 0.00000000995: 105 format, scale = "%.1fns", 1000*1000*1000 106 default: 107 format, scale = "%.2fns", 1000*1000*1000 108 } 109 return func(ns float64) string { 110 return fmt.Sprintf(format, ns/1e9*scale) 111 } 112 } 113 114 // hasBaseUnit reports whether s has unit unit. 115 // For now, it reports whether s == unit or s ends in -unit. 116 func hasBaseUnit(s, unit string) bool { 117 return s == unit || strings.HasSuffix(s, "-"+unit) 118 }