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  JobTypes const& jobTypes)
43 {
44  {
45  // populateRpc
46  rpc_.reserve(labels.size());
47  for (std::string const label : labels)
48  {
49  auto const inserted = rpc_.emplace(label, Rpc()).second;
50  if (!inserted)
51  {
52  // Ensure that no other function populates this entry.
53  assert(false);
54  }
55  }
56  }
57  {
58  // populateJq
59  jq_.reserve(jobTypes.size());
60  for (auto const& [jobType, jobTypeInfo] : jobTypes)
61  {
62  auto const inserted = jq_.emplace(jobType, Jq(jobTypeInfo.name())).second;
63  if (!inserted)
64  {
65  // Ensure that no other function populates this entry.
66  assert(false);
67  }
68  }
69  }
70 }
71 
74 {
76  // totalRpc represents all rpc methods. All that started, finished, etc.
77  Rpc totalRpc;
78  for (auto const& proc : rpc_)
79  {
81  {
82  auto const sync =
83  [&proc]() ->boost::optional<Counters::Rpc::Sync> {
84  std::lock_guard lock(proc.second.mut);
85  if (!proc.second.sync.started &&
86  !proc.second.sync.finished &&
87  !proc.second.sync.errored)
88  {
89  return boost::none;
90  }
91  return proc.second.sync;
92  }();
93  if (!sync)
94  continue;
95 
96  p[jss::started] = std::to_string(sync->started);
97  totalRpc.sync.started += sync->started;
98  p[jss::finished] = std::to_string(sync->finished);
99  totalRpc.sync.finished += sync->finished;
100  p[jss::errored] = std::to_string(sync->errored);
101  totalRpc.sync.errored += sync->errored;
102  p[jss::duration_us] = std::to_string(sync->duration.count());
103  totalRpc.sync.duration += sync->duration;
104  }
105  rpcobj[proc.first] = p;
106  }
107 
108  if (totalRpc.sync.started)
109  {
110  Json::Value totalRpcJson(Json::objectValue);
111  totalRpcJson[jss::started] = std::to_string(totalRpc.sync.started);
112  totalRpcJson[jss::finished] = std::to_string(totalRpc.sync.finished);
113  totalRpcJson[jss::errored] = std::to_string(totalRpc.sync.errored);
114  totalRpcJson[jss::duration_us] = std::to_string(
115  totalRpc.sync.duration.count());
116  rpcobj[jss::total] = totalRpcJson;
117  }
118 
120  // totalJq represents all jobs. All enqueued, started, finished, etc.
121  Jq totalJq("total");
122  for (auto const& proc : jq_)
123  {
125  {
126  auto const sync =
127  [&proc]() ->boost::optional<Counters::Jq::Sync> {
128  std::lock_guard lock(proc.second.mut);
129  if (!proc.second.sync.queued &&
130  !proc.second.sync.started &&
131  !proc.second.sync.finished)
132  {
133  return boost::none;
134  }
135  return proc.second.sync;
136  }();
137  if (!sync)
138  continue;
139 
140  j[jss::queued] = std::to_string(sync->queued);
141  totalJq.sync.queued += sync->queued;
142  j[jss::started] = std::to_string(sync->started);
143  totalJq.sync.started += sync->started;
144  j[jss::finished] = std::to_string(sync->finished);
145  totalJq.sync.finished += sync->finished;
146  j[jss::queued_duration_us] = std::to_string(
147  sync->queuedDuration.count());
148  totalJq.sync.queuedDuration += sync->queuedDuration;
149  j[jss::running_duration_us] = std::to_string(
150  sync->runningDuration.count());
151  totalJq.sync.runningDuration += sync->runningDuration;
152  }
153  jqobj[proc.second.label] = j;
154  }
155 
156  if (totalJq.sync.queued)
157  {
158  Json::Value totalJqJson(Json::objectValue);
159  totalJqJson[jss::queued] = std::to_string(totalJq.sync.queued);
160  totalJqJson[jss::started] = std::to_string(totalJq.sync.started);
161  totalJqJson[jss::finished] = std::to_string(totalJq.sync.finished);
162  totalJqJson[jss::queued_duration_us] = std::to_string(
163  totalJq.sync.queuedDuration.count());
164  totalJqJson[jss::running_duration_us] = std::to_string(
165  totalJq.sync.runningDuration.count());
166  jqobj[jss::total] = totalJqJson;
167  }
168 
169  Json::Value counters(Json::objectValue);
170  // Be kind to reporting tools and let them expect rpc and jq objects
171  // even if empty.
172  counters[jss::rpc] = rpcobj;
173  counters[jss::job_queue] = jqobj;
174  return counters;
175 }
176 
179 {
180  auto const present = steady_clock::now();
181 
182  Json::Value jobsArray(Json::arrayValue);
183  auto const jobs = [this]{
184  std::lock_guard lock(jobsMutex_);
185  return jobs_;
186  }();
187 
188  for (auto const& j : jobs)
189  {
190  if (j.first == jtINVALID)
191  continue;
193  auto const e = jq_.find(j.first);
194  if (e == jq_.end())
195  {
196  assert(false);
197  continue;
198  }
199  // label is const and created before multi-threading so needs no lock.
200  jobj[jss::job] = e->second.label;
201  jobj[jss::duration_us] = std::to_string(
202  std::chrono::duration_cast<microseconds>(
203  present - j.second).count());
204  jobsArray.append(jobj);
205  }
206 
207  Json::Value methodsArray(Json::arrayValue);
208  std::vector<MethodStart> methods;
209  {
210  std::lock_guard lock(methodsMutex_);
211  methods.reserve(methods_.size());
212  for (auto const& m : methods_)
213  methods.push_back(m.second);
214  }
215  for (auto m : methods)
216  {
217  Json::Value methodobj(Json::objectValue);
218  methodobj[jss::method] = m.first;
219  methodobj[jss::duration_us] = std::to_string(
220  std::chrono::duration_cast<microseconds>(
221  present - m.second).count());
222  methodsArray.append(methodobj);
223  }
224 
226  current[jss::jobs] = jobsArray;
227  current[jss::methods] = methodsArray;
228  return current;
229 }
230 
231 //-----------------------------------------------------------------------------
232 
233 void
235 {
236  if (! setup_.perfLog.empty())
237  {
238  if (logFile_.is_open())
239  logFile_.close();
240 
241  auto logDir = setup_.perfLog.parent_path();
242  if (!boost::filesystem::is_directory(logDir))
243  {
244  boost::system::error_code ec;
245  boost::filesystem::create_directories(logDir, ec);
246  if (ec)
247  {
248  JLOG(j_.fatal()) << "Unable to create performance log "
249  "directory " << 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()) << "Unable to open performance log " <<
260  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  Stoppable& parent,
316  beast::Journal journal,
317  std::function<void()>&& signalStop)
318  : Stoppable ("PerfLogImp", parent)
319  , setup_ (setup)
320  , j_ (journal)
321  , signalStop_ (std::move (signalStop))
322 {
323  openLog();
324 }
325 
327 {
328  onStop();
329 }
330 
331 void
332 PerfLogImp::rpcStart(std::string const& method, std::uint64_t const requestId)
333 {
334  auto counter = counters_.rpc_.find(method);
335  if (counter == counters_.rpc_.end())
336  {
337  assert(false);
338  return;
339  }
340 
341  {
342  std::lock_guard lock(counter->second.mut);
343  ++counter->second.sync.started;
344  }
346  counters_.methods_[requestId] = {
347  counter->first.c_str(),
349  };
350 }
351 
352 void
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 +=
383  std::chrono::duration_cast<microseconds>(
384  steady_clock::now() - startTime);
385 }
386 
387 void
389 {
390  auto counter = counters_.jq_.find(type);
391  if (counter == counters_.jq_.end())
392  {
393  assert(false);
394  return;
395  }
396  std::lock_guard lock(counter->second.mut);
397  ++counter->second.sync.queued;
398 }
399 
400 void
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
424  int instance)
425 {
426  auto counter = counters_.jq_.find(type);
427  if (counter == counters_.jq_.end())
428  {
429  assert(false);
430  return;
431  }
432  {
433  std::lock_guard lock(counter->second.mut);
434  ++counter->second.sync.finished;
435  counter->second.sync.runningDuration += dur;
436  }
438  if (instance >= 0 && instance < counters_.jobs_.size())
439  counters_.jobs_[instance] = {jtINVALID, steady_time_point()};
440 }
441 
442 void
443 PerfLogImp::resizeJobs(int const resize)
444 {
446  counters_.workers_ = resize;
447  if (resize > counters_.jobs_.size())
449 }
450 
451 
452 void
454 {
455  if (setup_.perfLog.empty())
456  return;
457 
458  std::lock_guard lock(mutex_);
459  rotate_ = true;
460  cond_.notify_one();
461 }
462 
463 void
465 {
466  if (setup_.perfLog.size())
468 }
469 
470 void
472 {
473  if (thread_.joinable())
474  {
475  {
476  std::lock_guard lock(mutex_);
477  stop_ = true;
478  cond_.notify_one();
479  }
480  thread_.join();
481  }
482  if (areChildrenStopped())
483  stopped();
484 }
485 
486 void
488 {
489  onStop();
490 }
491 
492 //-----------------------------------------------------------------------------
493 
495 setup_PerfLog(Section const& section, boost::filesystem::path const& configDir)
496 {
497  PerfLog::Setup setup;
498  std::string perfLog;
499  set(perfLog, "perf_log", section);
500  if (perfLog.size())
501  {
502  setup.perfLog = boost::filesystem::path(perfLog);
503  if (setup.perfLog.is_relative())
504  {
505  setup.perfLog = boost::filesystem::absolute(
506  setup.perfLog, configDir);
507  }
508  }
509 
510  std::uint64_t logInterval;
511  if (get_if_exists(section, "log_interval", logInterval))
512  setup.logInterval = std::chrono::seconds(logInterval);
513  return setup;
514 }
515 
518  PerfLog::Setup const& setup,
519  Stoppable& parent,
520  beast::Journal journal,
521  std::function<void()>&& signalStop)
522 {
523  return std::make_unique<PerfLogImp>(
524  setup, parent, journal, std::move(signalStop));
525 }
526 
527 } // perf
528 } // ripple
beast::Journal::fatal
Stream fatal() const
Definition: Journal.h:312
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:143
utility
ripple::Stoppable::stopped
void stopped()
Called by derived classes to indicate that the stoppable has stopped.
Definition: Stoppable.cpp:71
ripple::JobTypes
Definition: JobTypes.h:33
ripple::perf::PerfLogImp::openLog
void openLog()
Definition: PerfLogImp.cpp:234
ripple::perf::PerfLog::Setup::perfLog
boost::filesystem::path perfLog
Definition: PerfLog.h:60
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: json_value.h:44
ripple::perf::PerfLogImp::Counters::jobsMutex_
std::mutex jobsMutex_
Definition: PerfLogImp.h:125
std::vector::reserve
T reserve(T... args)
Json::Compact
Decorator for streaming out compact json.
Definition: json_writer.h:277
ripple::perf::PerfLogImp::Counters::methodsMutex_
std::mutex methodsMutex_
Definition: PerfLogImp.h:127
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:136
ripple::perf::PerfLogImp::rotate
void rotate() override
Rotate perf log file.
Definition: PerfLogImp.cpp:453
std::chrono::microseconds
ripple::perf::PerfLogImp::cond_
std::condition_variable cond_
Definition: PerfLogImp.h:142
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:126
std::function
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:41
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:517
iostream
ripple::perf::PerfLogImp::hostname_
const std::string hostname_
Definition: PerfLogImp.h:144
ripple::perf::PerfLog::Setup
Configuration from [perf] section of rippled.cfg.
Definition: PerfLog.h:58
ripple::perf::PerfLogImp::Counters::Jq::Sync::queued
std::uint64_t queued
Definition: PerfLogImp.h:97
ripple::perf::PerfLogImp::Counters::Rpc::Sync::errored
std::uint64_t errored
Definition: PerfLogImp.h:71
ripple::perf::PerfLogImp::jobStart
void jobStart(JobType const type, microseconds dur, steady_time_point startTime, int instance) override
Log job executing.
Definition: PerfLogImp.cpp:401
ripple::get_if_exists
bool get_if_exists(Section const &section, std::string const &name, T &v)
Definition: BasicConfig.h:342
std::vector::push_back
T push_back(T... args)
ripple::perf::PerfLogImp::Counters::Jq::Sync::started
std::uint64_t started
Definition: PerfLogImp.h:98
stdexcept
ripple::perf::PerfLogImp::rotate_
bool rotate_
Definition: PerfLogImp.h:146
std::thread::joinable
T joinable(T... args)
ripple::perf::PerfLogImp::Counters::rpc_
std::unordered_map< std::string, Rpc > rpc_
Definition: PerfLogImp.h:121
Json::Value::append
Value & append(const Value &value)
Append value to array at the end.
Definition: json_value.cpp:907
ripple::Stoppable
Provides an interface for starting and stopping.
Definition: Stoppable.h:200
std::thread
STL class.
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:45
ripple::perf::PerfLogImp::onStop
void onStop() override
Override called when the stop notification is issued.
Definition: PerfLogImp.cpp:471
ripple::perf::PerfLogImp::mutex_
std::mutex mutex_
Definition: PerfLogImp.h:141
ripple::perf::PerfLogImp::Counters::jobs_
std::vector< std::pair< JobType, steady_time_point > > jobs_
Definition: PerfLogImp.h:123
ripple::perf::PerfLogImp::Counters::Rpc::Sync::duration
microseconds duration
Definition: PerfLogImp.h:73
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:36
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:271
std::ofstream::close
T close(T... args)
ripple::perf::PerfLogImp::Counters::Jq::Sync::finished
std::uint64_t finished
Definition: PerfLogImp.h:99
ripple::perf::PerfLogImp::Counters::jq_
std::unordered_map< std::underlying_type_t< JobType >, Jq > jq_
Definition: PerfLogImp.h:122
std::chrono::time_point
ripple::perf::PerfLogImp::Counters::Rpc::Sync::finished
std::uint64_t finished
Definition: PerfLogImp.h:70
cstdint
ripple::perf::PerfLogImp::thread_
std::thread thread_
Definition: PerfLogImp.h:140
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:60
std::uint64_t
atomic
ripple::perf::PerfLogImp::signalStop_
const std::function< void()> signalStop_
Definition: PerfLogImp.h:137
ripple::perf::PerfLogImp::Counters::Jq
Job Queue task performance counters.
Definition: PerfLogImp.h:89
ripple::perf::PerfLogImp::~PerfLogImp
~PerfLogImp() override
Definition: PerfLogImp.cpp:326
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:495
ripple::perf::PerfLogImp::Counters::Jq::Sync::runningDuration
microseconds runningDuration
Definition: PerfLogImp.h:102
beast::setCurrentThreadName
void setCurrentThreadName(std::string_view name)
Changes the name of the caller thread.
Definition: CurrentThreadName.cpp:113
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:49
cstdlib
ripple::perf::PerfLogImp::Counters::Rpc::Sync::started
std::uint64_t started
Definition: PerfLogImp.h:69
std::endl
T endl(T... args)
ripple::perf::PerfLogImp::stop_
bool stop_
Definition: PerfLogImp.h:145
ripple::perf::PerfLogImp::Counters::Rpc
RPC performance counters.
Definition: PerfLogImp.h:61
std::condition_variable::wait_until
T wait_until(T... args)
std
STL namespace.
ripple::perf::PerfLogImp::Counters::Rpc::sync
Sync sync
Definition: PerfLogImp.h:76
ripple::perf::PerfLogImp::rpcEnd
void rpcEnd(std::string const &method, std::uint64_t const requestId, bool finish)
Definition: PerfLogImp.cpp:353
ripple::perf::PerfLogImp::rpcStart
void rpcStart(std::string const &method, std::uint64_t const requestId) override
Log start of RPC call.
Definition: PerfLogImp.cpp:332
ripple::perf::PerfLogImp::Counters::currentJson
Json::Value currentJson() const
Definition: PerfLogImp.cpp:178
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:135
ripple::perf::PerfLogImp::onChildrenStopped
void onChildrenStopped() override
Override called when all children have stopped.
Definition: PerfLogImp.cpp:487
ripple::perf::PerfLogImp::Counters::Jq::sync
Sync sync
Definition: PerfLogImp.h:105
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:139
ripple::perf::PerfLogImp::counters_
Counters counters_
Definition: PerfLogImp.h:138
std::unique_ptr
STL class.
ripple::perf::PerfLogImp::jobQueue
void jobQueue(JobType const type) override
Log queued job.
Definition: PerfLogImp.cpp:388
unordered_map
ripple::perf::PerfLog::Setup::logInterval
milliseconds logInterval
Definition: PerfLog.h:62
ripple::JobTypes::size
Map::size_type size() const
Definition: JobTypes.h:109
ripple::perf::PerfLogImp::Counters::workers_
int workers_
Definition: PerfLogImp.h:124
std::ofstream::is_open
T is_open(T... args)
ripple::perf::PerfLogImp::onStart
void onStart() override
Override called during start.
Definition: PerfLogImp.cpp:464
ripple::perf::PerfLogImp::resizeJobs
void resizeJobs(int const resize) override
Ensure enough room to store each currently executing job.
Definition: PerfLogImp.cpp:443
ripple::perf::PerfLogImp::Counters::countersJson
Json::Value countersJson() const
Definition: PerfLogImp.cpp:73
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:101
Json::Value
Represents a JSON value.
Definition: json_value.h:141
string
std::chrono::steady_clock::now
T now(T... args)