]>
Commit | Line | Data |
---|---|---|
ef890b79 | 1 | #pragma once |
ef890b79 | 2 | #include <boost/accumulators/accumulators.hpp> |
3 | #include <boost/accumulators/statistics.hpp> | |
4 | ||
5 | #include <vector> | |
6 | #include <fstream> | |
7 | #include <deque> | |
8 | #include <map> | |
9 | ||
10 | struct LogHistogramBin | |
11 | { | |
12 | double percentile; | |
13 | double latLimit; | |
14 | double latAverage; | |
15 | double latMedian; | |
16 | double latStddev; | |
17 | uint64_t count; | |
18 | double cumulLatAverage; | |
19 | double cumulLatMedian; | |
20 | }; | |
21 | ||
22 | template<typename T> | |
23 | std::vector<LogHistogramBin> createLogHistogram(const T& bins, | |
24 | std::deque<double> percentiles={0.001, 0.01, 0.1, 0.2, 0.5, 1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90, 94, 95, 96, 97, 97.5, 98, 98.5, 99, 99.5, 99.6, 99.9, 99.99, 99.999, 99.9999}) | |
25 | { | |
26 | uint64_t totcumul=0, sum=0; | |
27 | ||
28 | for(const auto& c: bins) { | |
29 | totcumul += c.second; | |
30 | } | |
31 | ||
32 | namespace ba=boost::accumulators; | |
33 | ba::accumulator_set<double, ba::features<ba::tag::mean, ba::tag::median, ba::tag::variance>, unsigned> acc; | |
34 | ||
35 | ba::accumulator_set<double, ba::features<ba::tag::mean, ba::tag::median, ba::tag::variance>, unsigned int> cumulstats; | |
36 | ||
37 | uint64_t bincount=0; | |
38 | std::vector<LogHistogramBin> ret; | |
39 | for(const auto& c: bins) { | |
40 | if(percentiles.empty()) | |
41 | break; | |
42 | sum += c.second; | |
43 | bincount += c.second; | |
44 | ||
45 | acc(c.first/1000.0, ba::weight=c.second); | |
46 | for(unsigned int i=0; i < c.second; ++i) | |
47 | cumulstats(c.first/1000.0, ba::weight=1); // "weighted" does not work for median | |
48 | if(sum > percentiles.front() * totcumul / 100.0) { | |
49 | ret.push_back({100.0-percentiles.front(), (double)c.first/1000.0, ba::mean(acc), ba::median(acc), sqrt(ba::variance(acc)), bincount, ba::mean(cumulstats), ba::median(cumulstats)}); | |
50 | ||
51 | percentiles.pop_front(); | |
52 | acc=decltype(acc)(); | |
53 | bincount=0; | |
54 | } | |
55 | } | |
56 | std::sort(ret.begin(), ret.end(), [](const LogHistogramBin& a, const LogHistogramBin& b) { | |
57 | return a.percentile < b.percentile; | |
58 | }); | |
59 | return ret; | |
60 | } | |
61 | ||
62 | template<typename T> | |
63 | void writeLogHistogramFile(const T& bins, std::ostream& out, std::deque<double> percentiles={0.001, 0.01, 0.1, 0.2, 0.5, 1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90, 94, 95, 96, 97, 97.5, 98, 98.5, 99, 99.5, 99.6, 99.9, 99.99, 99.999, 99.9999} ) | |
64 | { | |
65 | ||
66 | auto vec = createLogHistogram(bins, percentiles); | |
67 | out<< R"(# set logscale xy | |
68 | # set mxtics 10 | |
69 | # set mytics 10 | |
70 | # set grid xtics | |
71 | # set grid ytics | |
72 | # set xlabel "Slowest percentile" | |
73 | # set ylabel "Millisecond response time" | |
74 | # set terminal svg | |
75 | # set output 'log-histogram.svg' | |
76 | # plot 'log-histogram' using 1:2 with linespoints title 'Average latency per percentile', \ | |
77 | # 'log-histogram' using 1:6 with linespoints title 'Cumulative average latency', \ | |
78 | # 'log-histogram' using 1:7 with linespoints title 'Cumulative median latency')"<<"\n"; | |
79 | ||
80 | out<<"# slow-percentile usec-latency-mean usec-latency-max usec-latency-median usec-latency-stddev usec-latency-cumul usec-latency-median-cumul num-queries\n"; | |
81 | ||
82 | ||
83 | for(const auto& e : vec) { | |
84 | out<<e.percentile<<" "<<e.latAverage<<" "<<e.latLimit<<" "<<e.latMedian<<" "<<e.latStddev<<" "<<e.cumulLatAverage<<" "<<e.cumulLatMedian<<" "<<e.count<<"\n"; | |
85 | } | |
86 | out.flush(); | |
87 | } | |
88 | ||
89 | template<typename T> | |
90 | void writeFullHistogramFile(const T& bins, double binMsec, std::ofstream& out) | |
91 | { | |
92 | std::map<unsigned int, uint64_t> reducedBins; | |
93 | for(const auto& b : bins) { | |
94 | reducedBins[b.first/(1000.0*binMsec)]+=b.second; | |
95 | } | |
96 | out<<"# msec-bin-low count\n"; | |
97 | for(const auto& rb : reducedBins) { | |
98 | out<<rb.first*binMsec<<" "<<rb.second<<"\n"; | |
99 | } | |
100 | out.flush(); | |
101 | } |