github.com/bir3/gocompiler@v0.9.2202/src/internal/trace/traceviewer/histogram.go (about) 1 // Copyright 2023 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 traceviewer 6 7 import ( 8 "fmt" 9 "html/template" 10 "math" 11 "strings" 12 "time" 13 ) 14 15 // TimeHistogram is an high-dynamic-range histogram for durations. 16 type TimeHistogram struct { 17 Count int 18 Buckets []int 19 MinBucket, MaxBucket int 20 } 21 22 // Five buckets for every power of 10. 23 var logDiv = math.Log(math.Pow(10, 1.0/5)) 24 25 // Add adds a single sample to the histogram. 26 func (h *TimeHistogram) Add(d time.Duration) { 27 var bucket int 28 if d > 0 { 29 bucket = int(math.Log(float64(d)) / logDiv) 30 } 31 if len(h.Buckets) <= bucket { 32 h.Buckets = append(h.Buckets, make([]int, bucket-len(h.Buckets)+1)...) 33 h.Buckets = h.Buckets[:cap(h.Buckets)] 34 } 35 h.Buckets[bucket]++ 36 if bucket < h.MinBucket || h.MaxBucket == 0 { 37 h.MinBucket = bucket 38 } 39 if bucket > h.MaxBucket { 40 h.MaxBucket = bucket 41 } 42 h.Count++ 43 } 44 45 // BucketMin returns the minimum duration value for a provided bucket. 46 func (h *TimeHistogram) BucketMin(bucket int) time.Duration { 47 return time.Duration(math.Exp(float64(bucket) * logDiv)) 48 } 49 50 // ToHTML renders the histogram as HTML. 51 func (h *TimeHistogram) ToHTML(urlmaker func(min, max time.Duration) string) template.HTML { 52 if h == nil || h.Count == 0 { 53 return template.HTML("") 54 } 55 56 const barWidth = 400 57 58 maxCount := 0 59 for _, count := range h.Buckets { 60 if count > maxCount { 61 maxCount = count 62 } 63 } 64 65 w := new(strings.Builder) 66 fmt.Fprintf(w, `<table>`) 67 for i := h.MinBucket; i <= h.MaxBucket; i++ { 68 // Tick label. 69 if h.Buckets[i] > 0 { 70 fmt.Fprintf(w, `<tr><td class="histoTime" align="right"><a href=%s>%s</a></td>`, urlmaker(h.BucketMin(i), h.BucketMin(i+1)), h.BucketMin(i)) 71 } else { 72 fmt.Fprintf(w, `<tr><td class="histoTime" align="right">%s</td>`, h.BucketMin(i)) 73 } 74 // Bucket bar. 75 width := h.Buckets[i] * barWidth / maxCount 76 fmt.Fprintf(w, `<td><div style="width:%dpx;background:blue;position:relative"> </div></td>`, width) 77 // Bucket count. 78 fmt.Fprintf(w, `<td align="right"><div style="position:relative">%d</div></td>`, h.Buckets[i]) 79 fmt.Fprintf(w, "</tr>\n") 80 81 } 82 // Final tick label. 83 fmt.Fprintf(w, `<tr><td align="right">%s</td></tr>`, h.BucketMin(h.MaxBucket+1)) 84 fmt.Fprintf(w, `</table>`) 85 return template.HTML(w.String()) 86 }