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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
#pragma once
#include <library/cpp/json/json_value.h>
#include <library/cpp/json/writer/json.h>
#include <library/cpp/threading/future/async.h>
#include <util/generic/algorithm.h>
#include <util/generic/hash.h>
#include <util/generic/utility.h>
#include <util/generic/vector.h>
#include <util/generic/yexception.h>
#include <util/stream/format.h>
#include <util/string/builder.h>
#include <util/thread/pool.h>
#include <util/system/mutex.h>
namespace NSimpleHistogram {
template <typename T>
class THistogram {
public:
explicit THistogram(TVector<T>&& values)
: Values_(std::move(values))
{
}
size_t TotalCount() const {
return Values_.size();
}
T ValueAtPercentile(double percentile) const {
Y_ASSERT(!Values_.empty());
Y_ASSERT(percentile >= 0.0 && percentile <= 1.0);
const size_t index = static_cast<size_t>(percentile * Values_.size());
return Values_[Min(Values_.size() - 1, index)];
}
private:
TVector<T> Values_;
};
template <typename T>
class THistogramCalcer {
public:
size_t TotalCount() const {
return Values_.size();
}
void RecordValue(T value) {
Values_.push_back(value);
}
THistogram<T> Calc() {
if (!IsSorted(Values_.begin(), Values_.end())) {
Sort(Values_.begin(), Values_.end());
}
return THistogram<T>(std::move(Values_));
}
private:
TVector<T> Values_;
};
template <typename T>
class TMultiHistogramCalcer {
public:
void RecordValue(TStringBuf name, T value) {
Calcers_[name].RecordValue(value);
}
THashMap<TString, THistogram<T>> Calc() {
THashMap<TString, THistogram<T>> result;
for (auto& calcer : Calcers_) {
result.emplace(calcer.first, calcer.second.Calc());
}
return result;
}
private:
THashMap<TString, THistogramCalcer<T>> Calcers_;
};
template <typename T>
class TThreadSafeMultiHistogramCalcer {
public:
void RecordValue(TStringBuf name, T value) {
TGuard<TMutex> guard(Mutex_);
Calcer_.RecordValue(name, value);
}
THashMap<TString, THistogram<T>> Calc() {
return Calcer_.Calc();
}
private:
TMutex Mutex_;
TMultiHistogramCalcer<T> Calcer_;
};
template <typename T>
NJson::TJsonValue ToJson(const THistogram<T>& hist, const TVector<double>& percentiles) {
NJson::TJsonValue json;
for (double percentile : percentiles) {
TStringBuilder name;
name << "Q" << Prec(percentile * 100, PREC_POINT_DIGITS_STRIP_ZEROES, 2);
json[name] = hist.ValueAtPercentile(percentile);
}
json["RecordCount"] = hist.TotalCount();
return json;
}
template <typename T>
NJson::TJsonValue ToJson(const THashMap<TString, THistogram<T>>& hists, const TVector<double>& percentiles) {
NJson::TJsonValue json;
for (const auto& p : hists) {
json[p.first] = ToJson(p.second, percentiles);
}
return json;
}
template <typename T>
TString ToJsonStr(const THashMap<TString, THistogram<T>>& hists, const TVector<double>& percentiles, bool format = true) {
NJson::TJsonValue json = ToJson(hists, percentiles);
NJsonWriter::TBuf buf;
if (format) {
buf.SetIndentSpaces(4);
}
return buf.WriteJsonValue(&json, true).Str();
}
}
|