latency_recorder.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. // Licensed to the Apache Software Foundation (ASF) under one
  2. // or more contributor license agreements. See the NOTICE file
  3. // distributed with this work for additional information
  4. // regarding copyright ownership. The ASF licenses this file
  5. // to you under the Apache License, Version 2.0 (the
  6. // "License"); you may not use this file except in compliance
  7. // with the License. You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing,
  12. // software distributed under the License is distributed on an
  13. // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  14. // KIND, either express or implied. See the License for the
  15. // specific language governing permissions and limitations
  16. // under the License.
  17. // Date: 2014/09/22 11:57:43
  18. #include <gflags/gflags.h>
  19. #include "butil/unique_ptr.h"
  20. #include "bvar/latency_recorder.h"
  21. namespace bvar {
  22. // Reloading following gflags does not change names of the corresponding bvars.
  23. // Avoid reloading in practice.
  24. DEFINE_int32(bvar_latency_p1, 80, "First latency percentile");
  25. DEFINE_int32(bvar_latency_p2, 90, "Second latency percentile");
  26. DEFINE_int32(bvar_latency_p3, 99, "Third latency percentile");
  27. static bool valid_percentile(const char*, int32_t v) {
  28. return v > 0 && v < 100;
  29. }
  30. const bool ALLOW_UNUSED dummy_bvar_latency_p1 = ::GFLAGS_NS::RegisterFlagValidator(
  31. &FLAGS_bvar_latency_p1, valid_percentile);
  32. const bool ALLOW_UNUSED dummy_bvar_latency_p2 = ::GFLAGS_NS::RegisterFlagValidator(
  33. &FLAGS_bvar_latency_p2, valid_percentile);
  34. const bool ALLOW_UNUSED dummy_bvar_latency_p3 = ::GFLAGS_NS::RegisterFlagValidator(
  35. &FLAGS_bvar_latency_p3, valid_percentile);
  36. namespace detail {
  37. typedef PercentileSamples<1022> CombinedPercentileSamples;
  38. CDF::CDF(PercentileWindow* w) : _w(w) {}
  39. CDF::~CDF() {
  40. hide();
  41. }
  42. void CDF::describe(std::ostream& os, bool) const {
  43. os << "\"click to view\"";
  44. }
  45. int CDF::describe_series(
  46. std::ostream& os, const SeriesOptions& options) const {
  47. if (_w == NULL) {
  48. return 1;
  49. }
  50. if (options.test_only) {
  51. return 0;
  52. }
  53. std::unique_ptr<CombinedPercentileSamples> cb(new CombinedPercentileSamples);
  54. std::vector<GlobalPercentileSamples> buckets;
  55. _w->get_samples(&buckets);
  56. for (size_t i = 0; i < buckets.size(); ++i) {
  57. cb->combine_of(buckets.begin(), buckets.end());
  58. }
  59. std::pair<int, int> values[20];
  60. size_t n = 0;
  61. for (int i = 1; i < 10; ++i) {
  62. values[n++] = std::make_pair(i*10, cb->get_number(i * 0.1));
  63. }
  64. for (int i = 91; i < 100; ++i) {
  65. values[n++] = std::make_pair(i, cb->get_number(i * 0.01));
  66. }
  67. values[n++] = std::make_pair(100, cb->get_number(0.999));
  68. values[n++] = std::make_pair(101, cb->get_number(0.9999));
  69. CHECK_EQ(n, arraysize(values));
  70. os << "{\"label\":\"cdf\",\"data\":[";
  71. for (size_t i = 0; i < n; ++i) {
  72. if (i) {
  73. os << ',';
  74. }
  75. os << '[' << values[i].first << ',' << values[i].second << ']';
  76. }
  77. os << "]}";
  78. return 0;
  79. }
  80. static int64_t get_window_recorder_qps(void* arg) {
  81. detail::Sample<Stat> s;
  82. static_cast<RecorderWindow*>(arg)->get_span(1, &s);
  83. // Use floating point to avoid overflow.
  84. if (s.time_us <= 0) {
  85. return 0;
  86. }
  87. return static_cast<int64_t>(round(s.data.num * 1000000.0 / s.time_us));
  88. }
  89. static int64_t get_recorder_count(void* arg) {
  90. return static_cast<IntRecorder*>(arg)->get_value().num;
  91. }
  92. // Caller is responsible for deleting the return value.
  93. static CombinedPercentileSamples* combine(PercentileWindow* w) {
  94. CombinedPercentileSamples* cb = new CombinedPercentileSamples;
  95. std::vector<GlobalPercentileSamples> buckets;
  96. w->get_samples(&buckets);
  97. cb->combine_of(buckets.begin(), buckets.end());
  98. return cb;
  99. }
  100. template <int64_t numerator, int64_t denominator>
  101. static int64_t get_percetile(void* arg) {
  102. return ((LatencyRecorder*)arg)->latency_percentile(
  103. (double)numerator / double(denominator));
  104. }
  105. static int64_t get_p1(void* arg) {
  106. LatencyRecorder* lr = static_cast<LatencyRecorder*>(arg);
  107. return lr->latency_percentile(FLAGS_bvar_latency_p1 / 100.0);
  108. }
  109. static int64_t get_p2(void* arg) {
  110. LatencyRecorder* lr = static_cast<LatencyRecorder*>(arg);
  111. return lr->latency_percentile(FLAGS_bvar_latency_p2 / 100.0);
  112. }
  113. static int64_t get_p3(void* arg) {
  114. LatencyRecorder* lr = static_cast<LatencyRecorder*>(arg);
  115. return lr->latency_percentile(FLAGS_bvar_latency_p3 / 100.0);
  116. }
  117. static Vector<int64_t, 4> get_latencies(void *arg) {
  118. std::unique_ptr<CombinedPercentileSamples> cb(
  119. combine((PercentileWindow*)arg));
  120. // NOTE: We don't show 99.99% since it's often significantly larger than
  121. // other values and make other curves on the plotted graph small and
  122. // hard to read.
  123. Vector<int64_t, 4> result;
  124. result[0] = cb->get_number(FLAGS_bvar_latency_p1 / 100.0);
  125. result[1] = cb->get_number(FLAGS_bvar_latency_p2 / 100.0);
  126. result[2] = cb->get_number(FLAGS_bvar_latency_p3 / 100.0);
  127. result[3] = cb->get_number(0.999);
  128. return result;
  129. }
  130. LatencyRecorderBase::LatencyRecorderBase(time_t window_size)
  131. : _max_latency(0)
  132. , _latency_window(&_latency, window_size)
  133. , _max_latency_window(&_max_latency, window_size)
  134. , _count(get_recorder_count, &_latency)
  135. , _qps(get_window_recorder_qps, &_latency_window)
  136. , _latency_percentile_window(&_latency_percentile, window_size)
  137. , _latency_p1(get_p1, this)
  138. , _latency_p2(get_p2, this)
  139. , _latency_p3(get_p3, this)
  140. , _latency_999(get_percetile<999, 1000>, this)
  141. , _latency_9999(get_percetile<9999, 10000>, this)
  142. , _latency_cdf(&_latency_percentile_window)
  143. , _latency_percentiles(get_latencies, &_latency_percentile_window)
  144. {}
  145. } // namespace detail
  146. Vector<int64_t, 4> LatencyRecorder::latency_percentiles() const {
  147. // const_cast here is just to adapt parameter type and safe.
  148. return detail::get_latencies(
  149. const_cast<detail::PercentileWindow*>(&_latency_percentile_window));
  150. }
  151. int64_t LatencyRecorder::qps(time_t window_size) const {
  152. detail::Sample<Stat> s;
  153. _latency_window.get_span(window_size, &s);
  154. // Use floating point to avoid overflow.
  155. if (s.time_us <= 0) {
  156. return 0;
  157. }
  158. return static_cast<int64_t>(round(s.data.num * 1000000.0 / s.time_us));
  159. }
  160. int LatencyRecorder::expose(const butil::StringPiece& prefix1,
  161. const butil::StringPiece& prefix2) {
  162. if (prefix2.empty()) {
  163. LOG(ERROR) << "Parameter[prefix2] is empty";
  164. return -1;
  165. }
  166. butil::StringPiece prefix = prefix2;
  167. // User may add "_latency" as the suffix, remove it.
  168. if (prefix.ends_with("latency") || prefix.ends_with("Latency")) {
  169. prefix.remove_suffix(7);
  170. if (prefix.empty()) {
  171. LOG(ERROR) << "Invalid prefix2=" << prefix2;
  172. return -1;
  173. }
  174. }
  175. std::string tmp;
  176. if (!prefix1.empty()) {
  177. tmp.reserve(prefix1.size() + prefix.size() + 1);
  178. tmp.append(prefix1.data(), prefix1.size());
  179. tmp.push_back('_'); // prefix1 ending with _ is good.
  180. tmp.append(prefix.data(), prefix.size());
  181. prefix = tmp;
  182. }
  183. // set debug names for printing helpful error log.
  184. _latency.set_debug_name(prefix);
  185. _latency_percentile.set_debug_name(prefix);
  186. if (_latency_window.expose_as(prefix, "latency") != 0) {
  187. return -1;
  188. }
  189. if (_max_latency_window.expose_as(prefix, "max_latency") != 0) {
  190. return -1;
  191. }
  192. if (_count.expose_as(prefix, "count") != 0) {
  193. return -1;
  194. }
  195. if (_qps.expose_as(prefix, "qps") != 0) {
  196. return -1;
  197. }
  198. char namebuf[32];
  199. snprintf(namebuf, sizeof(namebuf), "latency_%d", (int)FLAGS_bvar_latency_p1);
  200. if (_latency_p1.expose_as(prefix, namebuf, DISPLAY_ON_PLAIN_TEXT) != 0) {
  201. return -1;
  202. }
  203. snprintf(namebuf, sizeof(namebuf), "latency_%d", (int)FLAGS_bvar_latency_p2);
  204. if (_latency_p2.expose_as(prefix, namebuf, DISPLAY_ON_PLAIN_TEXT) != 0) {
  205. return -1;
  206. }
  207. snprintf(namebuf, sizeof(namebuf), "latency_%u", (int)FLAGS_bvar_latency_p3);
  208. if (_latency_p3.expose_as(prefix, namebuf, DISPLAY_ON_PLAIN_TEXT) != 0) {
  209. return -1;
  210. }
  211. if (_latency_999.expose_as(prefix, "latency_999", DISPLAY_ON_PLAIN_TEXT) != 0) {
  212. return -1;
  213. }
  214. if (_latency_9999.expose_as(prefix, "latency_9999") != 0) {
  215. return -1;
  216. }
  217. if (_latency_cdf.expose_as(prefix, "latency_cdf", DISPLAY_ON_HTML) != 0) {
  218. return -1;
  219. }
  220. if (_latency_percentiles.expose_as(prefix, "latency_percentiles", DISPLAY_ON_HTML) != 0) {
  221. return -1;
  222. }
  223. snprintf(namebuf, sizeof(namebuf), "%d%%,%d%%,%d%%,99.9%%",
  224. (int)FLAGS_bvar_latency_p1, (int)FLAGS_bvar_latency_p2,
  225. (int)FLAGS_bvar_latency_p3);
  226. CHECK_EQ(0, _latency_percentiles.set_vector_names(namebuf));
  227. return 0;
  228. }
  229. int64_t LatencyRecorder::latency_percentile(double ratio) const {
  230. std::unique_ptr<detail::CombinedPercentileSamples> cb(
  231. combine((detail::PercentileWindow*)&_latency_percentile_window));
  232. return cb->get_number(ratio);
  233. }
  234. void LatencyRecorder::hide() {
  235. _latency_window.hide();
  236. _max_latency_window.hide();
  237. _count.hide();
  238. _qps.hide();
  239. _latency_p1.hide();
  240. _latency_p2.hide();
  241. _latency_p3.hide();
  242. _latency_999.hide();
  243. _latency_9999.hide();
  244. _latency_cdf.hide();
  245. _latency_percentiles.hide();
  246. }
  247. LatencyRecorder& LatencyRecorder::operator<<(int64_t latency) {
  248. _latency << latency;
  249. _max_latency << latency;
  250. _latency_percentile << latency;
  251. return *this;
  252. }
  253. std::ostream& operator<<(std::ostream& os, const LatencyRecorder& rec) {
  254. return os << "{latency=" << rec.latency()
  255. << " max" << rec.window_size() << '=' << rec.max_latency()
  256. << " qps=" << rec.qps()
  257. << " count=" << rec.count() << '}';
  258. }
  259. } // namespace bvar