1// +build go1.1 2 3package quantile_test 4 5import ( 6 "bufio" 7 "fmt" 8 "log" 9 "os" 10 "strconv" 11 "time" 12 13 "github.com/beorn7/perks/quantile" 14) 15 16func Example_simple() { 17 ch := make(chan float64) 18 go sendFloats(ch) 19 20 // Compute the 50th, 90th, and 99th percentile. 21 q := quantile.NewTargeted(map[float64]float64{ 22 0.50: 0.005, 23 0.90: 0.001, 24 0.99: 0.0001, 25 }) 26 for v := range ch { 27 q.Insert(v) 28 } 29 30 fmt.Println("perc50:", q.Query(0.50)) 31 fmt.Println("perc90:", q.Query(0.90)) 32 fmt.Println("perc99:", q.Query(0.99)) 33 fmt.Println("count:", q.Count()) 34 // Output: 35 // perc50: 5 36 // perc90: 16 37 // perc99: 223 38 // count: 2388 39} 40 41func Example_mergeMultipleStreams() { 42 // Scenario: 43 // We have multiple database shards. On each shard, there is a process 44 // collecting query response times from the database logs and inserting 45 // them into a Stream (created via NewTargeted(0.90)), much like the 46 // Simple example. These processes expose a network interface for us to 47 // ask them to serialize and send us the results of their 48 // Stream.Samples so we may Merge and Query them. 49 // 50 // NOTES: 51 // * These sample sets are small, allowing us to get them 52 // across the network much faster than sending the entire list of data 53 // points. 54 // 55 // * For this to work correctly, we must supply the same quantiles 56 // a priori the process collecting the samples supplied to NewTargeted, 57 // even if we do not plan to query them all here. 58 ch := make(chan quantile.Samples) 59 getDBQuerySamples(ch) 60 q := quantile.NewTargeted(map[float64]float64{0.90: 0.001}) 61 for samples := range ch { 62 q.Merge(samples) 63 } 64 fmt.Println("perc90:", q.Query(0.90)) 65} 66 67func Example_window() { 68 // Scenario: We want the 90th, 95th, and 99th percentiles for each 69 // minute. 70 71 ch := make(chan float64) 72 go sendStreamValues(ch) 73 74 tick := time.NewTicker(1 * time.Minute) 75 q := quantile.NewTargeted(map[float64]float64{ 76 0.90: 0.001, 77 0.95: 0.0005, 78 0.99: 0.0001, 79 }) 80 for { 81 select { 82 case t := <-tick.C: 83 flushToDB(t, q.Samples()) 84 q.Reset() 85 case v := <-ch: 86 q.Insert(v) 87 } 88 } 89} 90 91func sendStreamValues(ch chan float64) { 92 // Use your imagination 93} 94 95func flushToDB(t time.Time, samples quantile.Samples) { 96 // Use your imagination 97} 98 99// This is a stub for the above example. In reality this would hit the remote 100// servers via http or something like it. 101func getDBQuerySamples(ch chan quantile.Samples) {} 102 103func sendFloats(ch chan<- float64) { 104 f, err := os.Open("exampledata.txt") 105 if err != nil { 106 log.Fatal(err) 107 } 108 sc := bufio.NewScanner(f) 109 for sc.Scan() { 110 b := sc.Bytes() 111 v, err := strconv.ParseFloat(string(b), 64) 112 if err != nil { 113 log.Fatal(err) 114 } 115 ch <- v 116 } 117 if sc.Err() != nil { 118 log.Fatal(sc.Err()) 119 } 120 close(ch) 121} 122