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