1 /*
2 * Stats.h
3 *
4 * This source file is part of the FoundationDB open source project
5 *
6 * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21 #ifndef FLOW_STATS_H
22 #define FLOW_STATS_H
23 #pragma once
24
25 // Yet another performance statistics interface
26 /*
27
28 struct MyCounters {
29 CounterCollection cc;
30 Counter foo, bar, baz;
31 MyCounters() : foo("foo", cc), bar("bar", cc), baz("baz", cc) {}
32 };
33
34 */
35
36 #include <cstdint>
37 #include <cstddef>
38 #include "flow/flow.h"
39 #include "flow/TDMetric.actor.h"
40
41 struct TimedRequest {
42 double requestTime;
43
TimedRequestTimedRequest44 TimedRequest() {
45 requestTime = timer();
46 }
47 };
48
49 struct ICounter {
50 // All counters have a name and value
51 virtual std::string const& getName() const = 0;
52 virtual int64_t getValue() const = 0;
53
54 // Counters may also have rate and roughness
55 virtual bool hasRate() const = 0;
56 virtual double getRate() const = 0;
57 virtual bool hasRoughness() const = 0;
58 virtual double getRoughness() const = 0;
59
60 virtual void resetInterval() = 0;
61
removeICounter62 virtual void remove() {}
63 };
64
65 struct CounterCollection {
nameCounterCollection66 CounterCollection(std::string name, std::string id = std::string()) : name(name), id(id) {}
67 std::vector<struct ICounter*> counters, counters_to_remove;
~CounterCollectionCounterCollection68 ~CounterCollection() { for (auto c : counters_to_remove) c->remove(); }
69 std::string name;
70 std::string id;
71 };
72
73 struct Counter : ICounter, NonCopyable {
74 public:
75 typedef int64_t Value;
76
77 Counter(std::string const& name, CounterCollection& collection);
78
79 void operator += (Value delta);
80 void operator ++ () { *this += 1; }
81 void clear();
82 void resetInterval();
83
getNameCounter84 std::string const& getName() const { return name; }
85
getIntervalDeltaCounter86 Value getIntervalDelta() const { return interval_delta; }
getValueCounter87 Value getValue() const { return interval_start_value + interval_delta; }
88 double getRate() const; // dValue / dt
89 double getRoughness() const; // value deltas come in "clumps" of this many ( 1 = periodic, 2 = poisson, 10 = periodic clumps of 10 (nearly) simultaneous delta )
hasRateCounter90 bool hasRate() const { return true; }
hasRoughnessCounter91 bool hasRoughness() const { return true; }
92
93 private:
94 std::string name;
95 double interval_start, last_event, interval_sq_time;
96 Value interval_delta, interval_start_value;
97 Int64MetricHandle metric;
98 };
99
100 template <class F>
101 struct SpecialCounter : ICounter, FastAllocated<SpecialCounter<F>>, NonCopyable {
SpecialCounterSpecialCounter102 SpecialCounter(CounterCollection& collection, std::string const& name, F && f) : name(name), f(f) { collection.counters.push_back(this); collection.counters_to_remove.push_back(this); }
removeSpecialCounter103 virtual void remove() { delete this; }
104
getNameSpecialCounter105 virtual std::string const& getName() const { return name; }
getValueSpecialCounter106 virtual int64_t getValue() const { return f(); }
107
resetIntervalSpecialCounter108 virtual void resetInterval() {}
109
hasRateSpecialCounter110 virtual bool hasRate() const { return false; }
getRateSpecialCounter111 virtual double getRate() const { throw internal_error(); }
hasRoughnessSpecialCounter112 virtual bool hasRoughness() const { return false; }
getRoughnessSpecialCounter113 virtual double getRoughness() const { throw internal_error(); }
114
115 std::string name;
116 F f;
117 };
118 template <class F>
specialCounter(CounterCollection & collection,std::string const & name,F && f)119 static void specialCounter(CounterCollection& collection, std::string const& name, F && f) { new SpecialCounter<F>(collection, name, std::move(f)); }
120
121 Future<Void> traceCounters(std::string const& traceEventName, UID const& traceEventID, double const& interval, CounterCollection* const& counters, std::string const& trackLatestName = std::string());
122
123 class LatencyBands {
124 public:
LatencyBands(std::string name,UID id,double loggingInterval)125 LatencyBands(std::string name, UID id, double loggingInterval) : name(name), id(id), loggingInterval(loggingInterval), cc(nullptr), filteredCount(nullptr) {}
126
addThreshold(double value)127 void addThreshold(double value) {
128 if(value > 0 && bands.count(value) == 0) {
129 if(bands.size() == 0) {
130 ASSERT(!cc && !filteredCount);
131 cc = new CounterCollection(name, id.toString());
132 logger = traceCounters(name, id, loggingInterval, cc, id.toString() + "/" + name);
133 filteredCount = new Counter("Filtered", *cc);
134 insertBand(std::numeric_limits<double>::infinity());
135 }
136
137 insertBand(value);
138 }
139 }
140
141 void addMeasurement(double measurement, bool filtered=false) {
142 if(filtered && filteredCount) {
143 ++(*filteredCount);
144 }
145 else if(bands.size() > 0) {
146 auto itr = bands.upper_bound(measurement);
147 ASSERT(itr != bands.end());
148 ++(*itr->second);
149 }
150 }
151
clearBands()152 void clearBands() {
153 logger = Void();
154
155 for(auto itr : bands) {
156 delete itr.second;
157 }
158
159 bands.clear();
160
161 delete filteredCount;
162 delete cc;
163
164 filteredCount = nullptr;
165 cc = nullptr;
166 }
167
~LatencyBands()168 ~LatencyBands() {
169 clearBands();
170 }
171
172 private:
173 std::map<double, Counter*> bands;
174 Counter *filteredCount;
175
176 std::string name;
177 UID id;
178 double loggingInterval;
179
180 CounterCollection *cc;
181 Future<Void> logger;
182
insertBand(double value)183 void insertBand(double value) {
184 bands.insert(std::make_pair(value, new Counter(format("Band%f", value), *cc)));
185 }
186 };
187 #endif
188