rippled
PerfLogImp.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2018 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/basics/BasicConfig.h>
21 #include <ripple/basics/impl/PerfLogImp.h>
22 #include <ripple/beast/core/CurrentThreadName.h>
23 #include <ripple/beast/utility/Journal.h>
24 #include <ripple/json/json_writer.h>
25 #include <ripple/json/to_string.h>
26 #include <boost/optional.hpp>
27 #include <atomic>
28 #include <cstdint>
29 #include <cstdlib>
30 #include <iostream>
31 #include <iterator>
32 #include <sstream>
33 #include <stdexcept>
34 #include <string>
35 #include <unordered_map>
36 #include <utility>
37 
38 namespace ripple {
39 namespace perf {
40 
42  std::vector<char const*> const& labels,
43  JobTypes const& jobTypes)
44 {
45  {
46  // populateRpc
47  rpc_.reserve(labels.size());
48  for (std::string const label : labels)
49  {
50  auto const inserted = rpc_.emplace(label, Rpc()).second;
51  if (!inserted)
52  {
53  // Ensure that no other function populates this entry.
54  assert(false);
55  }
56  }
57  }
58  {
59  // populateJq
60  jq_.reserve(jobTypes.size());
61  for (auto const& [jobType, jobTypeInfo] : jobTypes)
62  {
63  auto const inserted =
64  jq_.emplace(jobType, Jq(jobTypeInfo.name())).second;
65  if (!inserted)
66  {
67  // Ensure that no other function populates this entry.
68  assert(false);
69  }
70  }
71  }
72 }
73 
76 {
78  // totalRpc represents all rpc methods. All that started, finished, etc.
79  Rpc totalRpc;
80  for (auto const& proc : rpc_)
81  {
83  {
84  auto const sync =
85  [&proc]() -> boost::optional<Counters::Rpc::Sync> {
86  std::lock_guard lock(proc.second.mut);
87  if (!proc.second.sync.started && !proc.second.sync.finished &&
88  !proc.second.sync.errored)
89  {
90  return boost::none;
91  }
92  return proc.second.sync;
93  }();
94  if (!sync)
95  continue;
96 
97  p[jss::started] = std::to_string(sync->started);
98  totalRpc.sync.started += sync->started;
99  p[jss::finished] = std::to_string(sync->finished);
100  totalRpc.sync.finished += sync->finished;
101  p[jss::errored] = std::to_string(sync->errored);
102  totalRpc.sync.errored += sync->errored;
103  p[jss::duration_us] = std::to_string(sync->duration.count());
104  totalRpc.sync.duration += sync->duration;
105  }
106  rpcobj[proc.first] = p;
107  }
108 
109  if (totalRpc.sync.started)
110  {
111  Json::Value totalRpcJson(Json::objectValue);
112  totalRpcJson[jss::started] = std::to_string(totalRpc.sync.started);
113  totalRpcJson[jss::finished] = std::to_string(totalRpc.sync.finished);
114  totalRpcJson[jss::errored] = std::to_string(totalRpc.sync.errored);
115  totalRpcJson[jss::duration_us] =
116  std::to_string(totalRpc.sync.duration.count());
117  rpcobj[jss::total] = totalRpcJson;
118  }
119 
121  // totalJq represents all jobs. All enqueued, started, finished, etc.
122  Jq totalJq("total");
123  for (auto const& proc : jq_)
124  {
126  {
127  auto const sync = [&proc]() -> boost::optional<Counters::Jq::Sync> {
128  std::lock_guard lock(proc.second.mut);
129  if (!proc.second.sync.queued && !proc.second.sync.started &&
130  !proc.second.sync.finished)
131  {
132  return boost::none;
133  }
134  return proc.second.sync;
135  }();
136  if (!sync)
137  continue;
138 
139  j[jss::queued] = std::to_string(sync->queued);
140  totalJq.sync.queued += sync->queued;
141  j[jss::started] = std::to_string(sync->started);
142  totalJq.sync.started += sync->started;
143  j[jss::finished] = std::to_string(sync->finished);
144  totalJq.sync.finished += sync->finished;
145  j[jss::queued_duration_us] =
146  std::to_string(sync->queuedDuration.count());
147  totalJq.sync.queuedDuration += sync->queuedDuration;
148  j[jss::running_duration_us] =
149  std::to_string(sync->runningDuration.count());
150  totalJq.sync.runningDuration += sync->runningDuration;
151  }
152  jqobj[proc.second.label] = j;
153  }
154 
155  if (totalJq.sync.queued)
156  {
157  Json::Value totalJqJson(Json::objectValue);
158  totalJqJson[jss::queued] = std::to_string(totalJq.sync.queued);
159  totalJqJson[jss::started] = std::to_string(totalJq.sync.started);
160  totalJqJson[jss::finished] = std::to_string(totalJq.sync.finished);
161  totalJqJson[jss::queued_duration_us] =
163  totalJqJson[jss::running_duration_us] =
165  jqobj[jss::total] = totalJqJson;
166  }
167 
168  Json::Value counters(Json::objectValue);
169  // Be kind to reporting tools and let them expect rpc and jq objects
170  // even if empty.
171  counters[jss::rpc] = rpcobj;
172  counters[jss::job_queue] = jqobj;
173  return counters;
174 }
175 
178 {
179  auto const present = steady_clock::now();
180 
181  Json::Value jobsArray(Json::arrayValue);
182  auto const jobs = [this] {
183  std::lock_guard lock(jobsMutex_);
184  return jobs_;
185  }();
186 
187  for (auto const& j : jobs)
188  {
189  if (j.first == jtINVALID)
190  continue;
192  auto const e = jq_.find(j.first);
193  if (e == jq_.end())
194  {
195  assert(false);
196  continue;
197  }
198  // label is const and created before multi-threading so needs no lock.
199  jobj[jss::job] = e->second.label;
200  jobj[jss::duration_us] = std::to_string(
201  std::chrono::duration_cast<microseconds>(present - j.second)
202  .count());
203  jobsArray.append(jobj);
204  }
205 
206  Json::Value methodsArray(Json::arrayValue);
207  std::vector<MethodStart> methods;
208  {
209  std::lock_guard lock(methodsMutex_);
210  methods.reserve(methods_.size());
211  for (auto const& m : methods_)
212  methods.push_back(m.second);
213  }
214  for (auto m : methods)
215  {
216  Json::Value methodobj(Json::objectValue);
217  methodobj[jss::method] = m.first;
218  methodobj[jss::duration_us] = std::to_string(
219  std::chrono::duration_cast<microseconds>(present - m.second)
220  .count());
221  methodsArray.append(methodobj);
222  }
223 
225  current[jss::jobs] = jobsArray;
226  current[jss::methods] = methodsArray;
227  return current;
228 }
229 
230 //-----------------------------------------------------------------------------
231 
232 void
234 {
235  if (!setup_.perfLog.empty())
236  {
237  if (logFile_.is_open())
238  logFile_.close();
239 
240  auto logDir = setup_.perfLog.parent_path();
241  if (!boost::filesystem::is_directory(logDir))
242  {
243  boost::system::error_code ec;
244  boost::filesystem::create_directories(logDir, ec);
245  if (ec)
246  {
247  JLOG(j_.fatal()) << "Unable to create performance log "
248  "directory "
249  << logDir << ": " << ec.message();
250  signalStop_();
251  return;
252  }
253  }
254 
255  logFile_.open(setup_.perfLog.c_str(), std::ios::out | std::ios::app);
256 
257  if (!logFile_)
258  {
259  JLOG(j_.fatal())
260  << "Unable to open performance log " << setup_.perfLog << ".";
261  signalStop_();
262  }
263  }
264 }
265 
266 void
268 {
269  beast::setCurrentThreadName("perflog");
271 
272  while (true)
273  {
274  {
276  if (stop_)
277  {
278  return;
279  }
280  if (rotate_)
281  {
282  openLog();
283  rotate_ = false;
284  }
286  }
287  report();
288  }
289 }
290 
291 void
293 {
294  if (!logFile_)
295  // If logFile_ is not writable do no further work.
296  return;
297 
298  auto const present = system_clock::now();
299  if (present < lastLog_ + setup_.logInterval)
300  return;
301  lastLog_ = present;
302 
304  report[jss::time] = to_string(date::floor<microseconds>(present));
305  report[jss::workers] = counters_.workers_;
306  report[jss::hostid] = hostname_;
307  report[jss::counters] = counters_.countersJson();
308  auto cur = counters_.currentJson();
309  report[jss::current_activities] = counters_.currentJson();
310 
311  logFile_ << Json::Compact{std::move(report)} << std::endl;
312 }
313 
315  Setup const& setup,
316  Stoppable& parent,
317  beast::Journal journal,
318  std::function<void()>&& signalStop)
319  : Stoppable("PerfLogImp", parent)
320  , setup_(setup)
321  , j_(journal)
322  , signalStop_(std::move(signalStop))
323 {
324  openLog();
325 }
326 
328 {
329  onStop();
330 }
331 
332 void
333 PerfLogImp::rpcStart(std::string const& method, std::uint64_t const requestId)
334 {
335  auto counter = counters_.rpc_.find(method);
336  if (counter == counters_.rpc_.end())
337  {
338  assert(false);
339  return;
340  }
341 
342  {
343  std::lock_guard lock(counter->second.mut);
344  ++counter->second.sync.started;
345  }
347  counters_.methods_[requestId] = {
348  counter->first.c_str(), steady_clock::now()};
349 }
350 
351 void
353  std::string const& method,
354  std::uint64_t const requestId,
355  bool finish)
356 {
357  auto counter = counters_.rpc_.find(method);
358  if (counter == counters_.rpc_.end())
359  {
360  assert(false);
361  return;
362  }
363  steady_time_point startTime;
364  {
366  auto const e = counters_.methods_.find(requestId);
367  if (e != counters_.methods_.end())
368  {
369  startTime = e->second.second;
370  counters_.methods_.erase(e);
371  }
372  else
373  {
374  assert(false);
375  }
376  }
377  std::lock_guard lock(counter->second.mut);
378  if (finish)
379  ++counter->second.sync.finished;
380  else
381  ++counter->second.sync.errored;
382  counter->second.sync.duration += std::chrono::duration_cast<microseconds>(
383  steady_clock::now() - startTime);
384 }
385 
386 void
388 {
389  auto counter = counters_.jq_.find(type);
390  if (counter == counters_.jq_.end())
391  {
392  assert(false);
393  return;
394  }
395  std::lock_guard lock(counter->second.mut);
396  ++counter->second.sync.queued;
397 }
398 
399 void
401  JobType const type,
402  microseconds dur,
403  steady_time_point startTime,
404  int instance)
405 {
406  auto counter = counters_.jq_.find(type);
407  if (counter == counters_.jq_.end())
408  {
409  assert(false);
410  return;
411  }
412  {
413  std::lock_guard lock(counter->second.mut);
414  ++counter->second.sync.started;
415  counter->second.sync.queuedDuration += dur;
416  }
418  if (instance >= 0 && instance < counters_.jobs_.size())
419  counters_.jobs_[instance] = {type, startTime};
420 }
421 
422 void
423 PerfLogImp::jobFinish(JobType const type, microseconds dur, int instance)
424 {
425  auto counter = counters_.jq_.find(type);
426  if (counter == counters_.jq_.end())
427  {
428  assert(false);
429  return;
430  }
431  {
432  std::lock_guard lock(counter->second.mut);
433  ++counter->second.sync.finished;
434  counter->second.sync.runningDuration += dur;
435  }
437  if (instance >= 0 && instance < counters_.jobs_.size())
438  counters_.jobs_[instance] = {jtINVALID, steady_time_point()};
439 }
440 
441 void
442 PerfLogImp::resizeJobs(int const resize)
443 {
445  counters_.workers_ = resize;
446  if (resize > counters_.jobs_.size())
448 }
449 
450 void
452 {
453  if (setup_.perfLog.empty())
454  return;
455 
456  std::lock_guard lock(mutex_);
457  rotate_ = true;
458  cond_.notify_one();
459 }
460 
461 void
463 {
464  if (setup_.perfLog.size())
466 }
467 
468 void
470 {
471  if (thread_.joinable())
472  {
473  {
474  std::lock_guard lock(mutex_);
475  stop_ = true;
476  cond_.notify_one();
477  }
478  thread_.join();
479  }
480  if (areChildrenStopped())
481  stopped();
482 }
483 
484 void
486 {
487  onStop();
488 }
489 
490 //-----------------------------------------------------------------------------
491 
493 setup_PerfLog(Section const& section, boost::filesystem::path const& configDir)
494 {
495  PerfLog::Setup setup;
496  std::string perfLog;
497  set(perfLog, "perf_log", section);
498  if (perfLog.size())
499  {
500  setup.perfLog = boost::filesystem::path(perfLog);
501  if (setup.perfLog.is_relative())
502  {
503  setup.perfLog =
504  boost::filesystem::absolute(setup.perfLog, configDir);
505  }
506  }
507 
508  std::uint64_t logInterval;
509  if (get_if_exists(section, "log_interval", logInterval))
510  setup.logInterval = std::chrono::seconds(logInterval);
511  return setup;
512 }
513 
516  PerfLog::Setup const& setup,
517  Stoppable& parent,
518  beast::Journal journal,
519  std::function<void()>&& signalStop)
520 {
521  return std::make_unique<PerfLogImp>(
522  setup, parent, journal, std::move(signalStop));
523 }
524 
525 } // namespace perf
526 } // namespace ripple
beast::Journal::fatal
Stream fatal() const
Definition: Journal.h:339
ripple::Section
Holds a collection of configuration values.
Definition: BasicConfig.h:43
sstream
std::vector::resize
T resize(T... args)
std::string
STL class.
ripple::perf::PerfLogImp::lastLog_
system_time_point lastLog_
Definition: PerfLogImp.h:144
utility
ripple::Stoppable::stopped
void stopped()
Called by derived classes to indicate that the stoppable has stopped.
Definition: Stoppable.cpp:72
ripple::JobTypes
Definition: JobTypes.h:32
ripple::perf::PerfLogImp::openLog
void openLog()
Definition: PerfLogImp.cpp:233
ripple::perf::PerfLog::Setup::perfLog
boost::filesystem::path perfLog
Definition: PerfLog.h:62
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
ripple::perf::PerfLogImp::Counters::jobsMutex_
std::mutex jobsMutex_
Definition: PerfLogImp.h:123
std::vector::reserve
T reserve(T... args)
Json::Compact
Decorator for streaming out compact json.
Definition: json_writer.h:316
ripple::perf::PerfLogImp::Counters::methodsMutex_
std::mutex methodsMutex_
Definition: PerfLogImp.h:125
std::vector
STL class.
std::vector::size
T size(T... args)
ripple::perf::PerfLogImp::jobFinish
void jobFinish(JobType const type, microseconds dur, int instance) override
Log job finishing.
Definition: PerfLogImp.cpp:423
ripple::perf::PerfLogImp::j_
const beast::Journal j_
Definition: PerfLogImp.h:137
ripple::perf::PerfLogImp::rotate
void rotate() override
Rotate perf log file.
Definition: PerfLogImp.cpp:451
std::chrono::microseconds
ripple::perf::PerfLogImp::cond_
std::condition_variable cond_
Definition: PerfLogImp.h:143
iterator
ripple::perf::PerfLogImp::PerfLogImp
PerfLogImp(Setup const &setup, Stoppable &parent, beast::Journal journal, std::function< void()> &&signalStop)
Definition: PerfLogImp.cpp:314
std::lock_guard
STL class.
ripple::perf::PerfLogImp::Counters::methods_
std::unordered_map< std::uint64_t, MethodStart > methods_
Definition: PerfLogImp.h:124
std::function
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:42
ripple::perf::make_PerfLog
std::unique_ptr< PerfLog > make_PerfLog(PerfLog::Setup const &setup, Stoppable &parent, beast::Journal journal, std::function< void()> &&signalStop)
Definition: PerfLogImp.cpp:515
iostream
ripple::perf::PerfLogImp::hostname_
const std::string hostname_
Definition: PerfLogImp.h:145
ripple::perf::PerfLog::Setup
Configuration from [perf] section of rippled.cfg.
Definition: PerfLog.h:60
ripple::perf::PerfLogImp::Counters::Jq::Sync::queued
std::uint64_t queued
Definition: PerfLogImp.h:96
ripple::perf::PerfLogImp::Counters::Rpc::Sync::errored
std::uint64_t errored
Definition: PerfLogImp.h:70
ripple::perf::PerfLogImp::jobStart
void jobStart(JobType const type, microseconds dur, steady_time_point startTime, int instance) override
Log job executing.
Definition: PerfLogImp.cpp:400
ripple::get_if_exists
bool get_if_exists(Section const &section, std::string const &name, T &v)
Definition: BasicConfig.h:347
std::vector::push_back
T push_back(T... args)
ripple::perf::PerfLogImp::Counters::Jq::Sync::started
std::uint64_t started
Definition: PerfLogImp.h:97
stdexcept
ripple::perf::PerfLogImp::rotate_
bool rotate_
Definition: PerfLogImp.h:147
std::thread::joinable
T joinable(T... args)
ripple::perf::PerfLogImp::Counters::rpc_
std::unordered_map< std::string, Rpc > rpc_
Definition: PerfLogImp.h:119
Json::Value::append
Value & append(const Value &value)
Append value to array at the end.
Definition: json_value.cpp:882
ripple::Stoppable
Provides an interface for starting and stopping.
Definition: Stoppable.h:201
std::thread
STL class.
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::perf::PerfLogImp::onStop
void onStop() override
Override called when the stop notification is issued.
Definition: PerfLogImp.cpp:469
ripple::perf::PerfLogImp::mutex_
std::mutex mutex_
Definition: PerfLogImp.h:142
ripple::perf::PerfLogImp::Counters::jobs_
std::vector< std::pair< JobType, steady_time_point > > jobs_
Definition: PerfLogImp.h:121
ripple::perf::PerfLogImp::Counters::Rpc::Sync::duration
microseconds duration
Definition: PerfLogImp.h:72
std::unique_lock
STL class.
ripple::Stoppable::areChildrenStopped
bool areChildrenStopped() const
Returns true if all children have stopped.
Definition: Stoppable.cpp:66
std::to_string
T to_string(T... args)
ripple::jtINVALID
@ jtINVALID
Definition: Job.h:35
ripple::set
bool set(T &target, std::string const &name, Section const &section)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
Definition: BasicConfig.h:276
std::ofstream::close
T close(T... args)
ripple::perf::PerfLogImp::Counters::Jq::Sync::finished
std::uint64_t finished
Definition: PerfLogImp.h:98
ripple::perf::PerfLogImp::Counters::jq_
std::unordered_map< std::underlying_type_t< JobType >, Jq > jq_
Definition: PerfLogImp.h:120
std::chrono::time_point
ripple::perf::PerfLogImp::Counters::Rpc::Sync::finished
std::uint64_t finished
Definition: PerfLogImp.h:69
cstdint
ripple::perf::PerfLogImp::thread_
std::thread thread_
Definition: PerfLogImp.h:141
ripple::ValStatus::current
@ current
This was a new validation and was added.
std::ofstream::open
T open(T... args)
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
std::uint64_t
atomic
ripple::perf::PerfLogImp::signalStop_
const std::function< void()> signalStop_
Definition: PerfLogImp.h:138
ripple::perf::PerfLogImp::Counters::Jq
Job Queue task performance counters.
Definition: PerfLogImp.h:88
ripple::perf::PerfLogImp::~PerfLogImp
~PerfLogImp() override
Definition: PerfLogImp.cpp:327
std::condition_variable::notify_one
T notify_one(T... args)
ripple::perf::setup_PerfLog
PerfLog::Setup setup_PerfLog(Section const &section, boost::filesystem::path const &configDir)
Definition: PerfLogImp.cpp:493
ripple::perf::PerfLogImp::Counters::Jq::Sync::runningDuration
microseconds runningDuration
Definition: PerfLogImp.h:101
beast::setCurrentThreadName
void setCurrentThreadName(std::string_view name)
Changes the name of the caller thread.
Definition: CurrentThreadName.cpp:119
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::perf::PerfLog::steady_time_point
std::chrono::time_point< steady_clock > steady_time_point
Definition: PerfLog.h:51
cstdlib
ripple::perf::PerfLogImp::Counters::Rpc::Sync::started
std::uint64_t started
Definition: PerfLogImp.h:68
std::endl
T endl(T... args)
ripple::perf::PerfLogImp::stop_
bool stop_
Definition: PerfLogImp.h:146
ripple::perf::PerfLogImp::Counters::Rpc
RPC performance counters.
Definition: PerfLogImp.h:60
std::condition_variable::wait_until
T wait_until(T... args)
std
STL namespace.
ripple::perf::PerfLogImp::Counters::Rpc::sync
Sync sync
Definition: PerfLogImp.h:75
ripple::perf::PerfLogImp::rpcEnd
void rpcEnd(std::string const &method, std::uint64_t const requestId, bool finish)
Definition: PerfLogImp.cpp:352
ripple::perf::PerfLogImp::rpcStart
void rpcStart(std::string const &method, std::uint64_t const requestId) override
Log start of RPC call.
Definition: PerfLogImp.cpp:333
ripple::perf::PerfLogImp::Counters::currentJson
Json::Value currentJson() const
Definition: PerfLogImp.cpp:177
std::chrono::microseconds::count
T count(T... args)
ripple::perf::PerfLogImp::run
void run()
Definition: PerfLogImp.cpp:267
ripple::JobType
JobType
Definition: Job.h:33
ripple::perf::PerfLogImp::setup_
const Setup setup_
Definition: PerfLogImp.h:136
ripple::perf::PerfLogImp::onChildrenStopped
void onChildrenStopped() override
Override called when all children have stopped.
Definition: PerfLogImp.cpp:485
ripple::perf::PerfLogImp::Counters::Jq::sync
Sync sync
Definition: PerfLogImp.h:104
ripple::perf::PerfLogImp::Counters::Counters
Counters(std::vector< char const * > const &labels, JobTypes const &jobTypes)
Definition: PerfLogImp.cpp:41
ripple::perf::PerfLogImp::logFile_
std::ofstream logFile_
Definition: PerfLogImp.h:140
ripple::perf::PerfLogImp::counters_
Counters counters_
Definition: PerfLogImp.h:139
std::unique_ptr
STL class.
ripple::perf::PerfLogImp::jobQueue
void jobQueue(JobType const type) override
Log queued job.
Definition: PerfLogImp.cpp:387
unordered_map
ripple::perf::PerfLog::Setup::logInterval
milliseconds logInterval
Definition: PerfLog.h:64
ripple::JobTypes::size
Map::size_type size() const
Definition: JobTypes.h:126
ripple::perf::PerfLogImp::Counters::workers_
int workers_
Definition: PerfLogImp.h:122
std::ofstream::is_open
T is_open(T... args)
ripple::perf::PerfLogImp::onStart
void onStart() override
Override called during start.
Definition: PerfLogImp.cpp:462
ripple::perf::PerfLogImp::resizeJobs
void resizeJobs(int const resize) override
Ensure enough room to store each currently executing job.
Definition: PerfLogImp.cpp:442
ripple::perf::PerfLogImp::Counters::countersJson
Json::Value countersJson() const
Definition: PerfLogImp.cpp:75
ripple::perf::PerfLogImp::report
void report()
Definition: PerfLogImp.cpp:292
std::thread::join
T join(T... args)
ripple::perf::PerfLogImp::Counters::Jq::Sync::queuedDuration
microseconds queuedDuration
Definition: PerfLogImp.h:100
Json::Value
Represents a JSON value.
Definition: json_value.h:145
string
std::chrono::steady_clock::now
T now(T... args)