Move serialize functions to variable-serializer.cpp
[hiphop-php.git] / hphp / util / service-data.h
blob8e316f723ff0bac7b2018c1199275874f0bb5a47
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2015 Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_SERVICE_DATA_H_
18 #define incl_HPHP_SERVICE_DATA_H_
20 #include <atomic>
21 #include <chrono>
22 #include <map>
23 #include <string>
24 #include <vector>
26 #include <folly/RWSpinLock.h>
27 #include <folly/Synchronized.h>
28 #include <folly/stats/Histogram.h>
29 #include <folly/stats/MultiLevelTimeSeries.h>
30 #include <folly/Optional.h>
32 namespace HPHP {
34 ///////////////////////////////////////////////////////////////////////////////
37 * A globally accessible statistics tracking facility. This can be used to keep
38 * track of internal runtime statistics in the form of flat counters, timeseries
39 * counters or histograms.
41 * ServiceData provides a globally accessible entry point to all the internal
42 * statistics. A 'statistic counter' of different types could be created by
43 * calling createCouter() createTimeseries() or createHistogram(). The caller
44 * can then add values at different time points to the statistic counters. The
45 * statistic can then be retrieved and reported via the exportAll() call on
46 * ServiceData.
48 * Thread safety:
49 * ==============
50 * All functions in ServiceData namespace are thread safe. It is safe
51 * (and recommended) to cache the object returned by create...() methods and
52 * repeatedly add data points to it. It is safe to call create...() with the
53 * same name from multiple threads. In this case, only one object will be
54 * created and passed back to different threads.
56 * All objects returned by returned by the various create...() calls are thread
57 * safe. It is okay to add data points to it from multiple threads concurrently.
58 * These objects are internally synchronized with spin locks.
60 * Example Usage:
61 * ==============
62 * // create a flat counter named foo.
63 * auto counter = ServiceData::createCouter("foo");
64 * counter->increment();
66 * // create timeseries data named bar with default setting (avg value for the
67 * // last 1 minute, 10 minute, hour and all time).
68 * auto timeseries = ServiceData::createTimeseries("bar");
69 * timeseries->addValue(3);
71 * // create a histogram with 10 buckets, min of 1, max of 100 and export the
72 * // 50th and 90th percentile value for reporting.
73 * auto histogram = ServiceData::createHistogram("blah", 10, 1, 100,
74 * {0.5, 0.9});
75 * histogram->addValue(10);
77 * // You can report the data like so.
78 * std::map<std::string, int64_t> statsMap;
79 * ServiceData::exportAll(statsMap);
81 * and statsMap will contain these keys:
83 * "foo"
84 * "bar.avg.60", "bar.avg.600", "bar.avg.3600", "bar.avg"
85 * "blah.hist.p50", "blah.hist.p90"
87 * Anti pattern:
88 * =============
89 * ServiceData::createCounter("foo")->increment(); // don't do this.
90 * Don't do this in performance critical code. You will incur the cost of a
91 * std::map look up whenever createCounter() is called. Rather, you should call
92 * ServiceData::createCounter("foo") just once, cache the returned pointer and
93 * repeatedly adding data points to it.
95 namespace ServiceData {
97 class ExportedCounter;
98 class ExportedHistogram;
99 class ExportedTimeSeries;
101 namespace detail {
102 template <class ClassWithPrivateDestructor>
103 class FriendDeleter;
106 enum class StatsType { AVG, SUM, RATE, COUNT, PCT };
109 * Create a flat counter named 'name'. Return an existing counter if it has
110 * already been created.
112 ExportedCounter* createCounter(const std::string& name);
115 * Create a timeseries counter named 'name'. Return an existing one if it
116 * has already been created.
118 * Timeseries data is implemented as a number of buckets (buckted by time).
119 * As data point is added and time rolls forward, new bucket is created and
120 * the earliest bucket expires.
122 * We keep multiple of timeseries data at different granularity and update
123 * them simultaneously. This allows us to commute statistics at different
124 * levels. For example, we can simultaneously compute the avg of some counter
125 * value over the last 5 minutes, 10 minutes and hour. This is a similar
126 * concept to the load counters from the unix 'uptime' command.
128 * 'exportTypes' specifies what kind of statistics to export for each level.
129 * More export types can be added after the timeseries is created.
131 * 'levels' specifies at which granularity should the stats be tracked. The
132 * time duration must be strictly increasing. Special value '0' means all
133 * time and should always come last.
135 * 'numBuckets' specifies how many buckets to keep at each level. More buckets
136 * will produce more precise data at the expense of memory.
138 ExportedTimeSeries* createTimeseries(
139 const std::string& name,
140 const std::vector<StatsType>& exportTypes =
141 std::vector<StatsType>{ StatsType::AVG },
142 const std::vector<std::chrono::seconds>& levels =
143 std::vector<std::chrono::seconds>{
144 std::chrono::seconds(60),
145 std::chrono::seconds(600),
146 std::chrono::seconds(3600),
147 std::chrono::seconds(0) /* all time */ },
148 int numBuckets = 60);
151 * Create a histogram counter named 'name'. Return an existing one if it has
152 * already been created.
154 * 'bucketSize' specifies how many buckets to track for the histogram.
155 * 'min' is the minimal value in the histogram.
156 * 'max' is the maximal value in the histogram.
157 * 'exportPercentile' specifies at what percentile values we should report the
158 * stat. A set of doubles between 0 and 1.0. For example, 0.5 means p50 and
159 * 0.99 means p99.
161 ExportedHistogram* createHistogram(
162 const std::string& name,
163 int64_t bucketSize,
164 int64_t min,
165 int64_t max,
166 const std::vector<double>& exportPercentile);
169 * Export all the statistics as simple key, value pairs.
171 void exportAll(std::map<std::string, int64_t>& statsMap);
174 * Export a specific counter by key name.
176 folly::Optional<int64_t> exportCounterByKey(std::string& key);
178 // Interface for a flat counter. All methods are thread safe.
179 class ExportedCounter {
180 public:
181 ExportedCounter() : m_value(0) {}
182 void increment() { m_value.fetch_add(1, std::memory_order_relaxed); }
183 void decrement() { m_value.fetch_sub(1, std::memory_order_relaxed); }
184 void setValue(int64_t value) {
185 m_value.store(value, std::memory_order_relaxed);
187 int64_t getValue() const { return m_value.load(std::memory_order_relaxed); }
189 private:
190 friend class detail::FriendDeleter<ExportedCounter>;
191 ~ExportedCounter() {}
193 std::atomic_int_fast64_t m_value;
196 // Interface for timeseries data. All methods are thread safe.
197 class ExportedTimeSeries {
198 public:
199 ExportedTimeSeries(int numBuckets,
200 const std::vector<std::chrono::seconds>& durations,
201 const std::vector<StatsType>& exportTypes);
203 void addValue(int64_t value);
204 void addValue(int64_t value, int64_t times);
205 void addValueAggregated(int64_t sum, int64_t nsamples);
207 int64_t getSum();
209 void exportAll(const std::string& prefix,
210 std::map<std::string, int64_t>& statsMap);
212 private:
213 friend class detail::FriendDeleter<ExportedTimeSeries>;
214 ~ExportedTimeSeries() {}
216 folly::Synchronized<folly::MultiLevelTimeSeries<int64_t>,
217 folly::RWSpinLock > m_timeseries;
218 const std::vector<ServiceData::StatsType> m_exportTypes;
221 // Interface for histogram data. All methods are thread safe.
222 class ExportedHistogram {
223 public:
224 ExportedHistogram(int64_t bucketSize, int64_t min, int64_t max,
225 const std::vector<double>& exportPercentiles);
226 void addValue(int64_t value);
227 void removeValue(int64_t value);
228 void exportAll(const std::string& prefix,
229 std::map<std::string, int64_t>& statsMap);
231 private:
232 friend class detail::FriendDeleter<ExportedHistogram>;
233 ~ExportedHistogram() {}
235 folly::Synchronized<folly::Histogram<int64_t>, folly::RWSpinLock> m_histogram;
236 const std::vector<double> m_exportPercentiles;
239 }; // namespace ServiceData
241 ///////////////////////////////////////////////////////////////////////////////
244 #include "hphp/util/service-data-inl.h"
246 #endif // incl_HPHP_SERVICE_DATA_H_