aboutsummaryrefslogtreecommitdiffstats
path: root/vbench/src/vbench/vbench/latency_analyzer.cpp
blob: c2892bbbaf80278c1392fe1913023dec8eb9abda (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "latency_analyzer.h"
#include <cmath>

namespace vbench {

double
LatencyAnalyzer::getN(size_t n) const
{
    size_t acc = 0;
    for (size_t i = 0; i < _hist.size(); ++i) {
        acc += _hist[i];
        if (acc > n) {
            return (((double)i) / 1000.0);
        }
    }
    return _max;
}

double
LatencyAnalyzer::getPercentile(double per) const
{
    double target = std::max((((double)(_cnt - 1)) * (per / 100.0)), 0.0);
    size_t before = (size_t)std::floor(target);
    size_t  after = (size_t)std::ceil(target);
    double factor = std::ceil(target) - target;
    return (factor * getN(before) + (1.0 - factor) * getN(after));
}

string
LatencyAnalyzer::Stats::toString() const
{
    string str = "Latency {\n";
    str += strfmt("  min: %g\n", min);
    str += strfmt("  avg: %g\n", avg);
    str += strfmt("  max: %g\n", max);
    str += strfmt("  50%%: %g\n", per50);
    str += strfmt("  95%%: %g\n", per95);
    str += strfmt("  99%%: %g\n", per99);
    str += "}\n";
    return str;
}

LatencyAnalyzer::LatencyAnalyzer(Handler<Request> &next)
    : _next(next),
      _cnt(0),
      _min(0.0),
      _max(0.0),
      _total(0.0),
      _hist(10000, 0)
{
}

LatencyAnalyzer::~LatencyAnalyzer() = default;

void
LatencyAnalyzer::handle(Request::UP request)
{
    if (request->status() == Request::STATUS_OK) {
        addLatency(request->latency());
    }
    _next.handle(std::move(request));
}

void
LatencyAnalyzer::report()
{
    fprintf(stdout, "%s\n", getStats().toString().c_str());
}

void
LatencyAnalyzer::addLatency(double latency)
{
    if (_cnt == 0 || latency < _min) {
        _min = latency;
    }
    if (_cnt == 0 || latency > _max) {
        _max = latency;
    }
    ++_cnt;
    _total += latency;
    size_t idx = (size_t)(latency * 1000.0 + 0.5);
    if (idx < _hist.size()) {
        ++_hist[idx];
    }
}

LatencyAnalyzer::Stats
LatencyAnalyzer::getStats() const
{
    Stats stats;
    stats.min = _min;
    if (_cnt > 0) {
        stats.avg = (_total / (double)_cnt);
    }
    stats.max = _max;
    stats.per50 = getPercentile(50.0);
    stats.per95 = getPercentile(95.0);
    stats.per99 = getPercentile(99.0);
    return stats;
}

} // namespace vbench