1#include <xrpld/perflog/detail/PerfLogImp.h>
3#include <xrpl/basics/Log.h>
4#include <xrpl/basics/chrono.h>
5#include <xrpl/beast/core/CurrentThreadName.h>
6#include <xrpl/beast/utility/Journal.h>
7#include <xrpl/beast/utility/instrumentation.h>
8#include <xrpl/config/BasicConfig.h>
9#include <xrpl/config/Constants.h>
10#include <xrpl/core/Job.h>
11#include <xrpl/core/JobTypes.h>
12#include <xrpl/core/PerfLog.h>
13#include <xrpl/json/json_value.h>
14#include <xrpl/json/json_writer.h>
15#include <xrpl/protocol/jss.h>
17#include <boost/filesystem/operations.hpp>
18#include <boost/system/detail/error_code.hpp>
42 auto const inserted =
rpc.emplace(label,
Rpc()).second;
48 "xrpl::perf::PerfLogImp::Counters::Counters : failed to "
56 jq.reserve(jobTypes.
size());
57 for (
auto const& [jobType, _] : jobTypes)
59 auto const inserted =
jq.emplace(jobType,
Jq()).second;
65 "xrpl::perf::PerfLogImp::Counters::Counters : failed to "
79 for (
auto const& proc :
rpc)
84 if ((proc.second.value.started == 0u) && (proc.second.value.finished == 0u) &&
85 (proc.second.value.errored == 0u))
89 value = proc.second.value;
94 totalRpc.
started += value.started;
98 totalRpc.
errored += value.errored;
100 totalRpc.
duration += value.duration;
101 rpcobj[proc.first] = p;
111 rpcobj[jss::total] = totalRpcJson;
117 for (
auto const& proc :
jq)
122 if ((proc.second.value.queued == 0u) && (proc.second.value.started == 0u) &&
123 (proc.second.value.finished == 0u))
127 value = proc.second.value;
132 totalJq.
queued += value.queued;
134 totalJq.
started += value.started;
137 j[jss::queued_duration_us] =
std::to_string(value.queuedDuration.count());
139 j[jss::running_duration_us] =
std::to_string(value.runningDuration.count());
152 jobQueueObj[jss::total] = totalJqJson;
158 counters[jss::rpc] = rpcobj;
159 counters[jss::job_queue] = jobQueueObj;
169 auto const jobs = [
this] {
174 for (
auto const& j :
jobs)
180 jobj[jss::duration_us] =
190 for (
auto const& m : this->methods)
196 methodobj[jss::method] = m.first;
197 methodobj[jss::duration_us] =
199 methodsArray.
append(methodobj);
203 current[jss::jobs] = jobsArray;
204 current[jss::methods] = methodsArray;
213 if (
setup_.perfLog.empty())
219 auto logDir =
setup_.perfLog.parent_path();
220 if (!boost::filesystem::is_directory(logDir))
222 boost::system::error_code ec;
223 boost::filesystem::create_directories(logDir, ec);
226 JLOG(
j_.fatal()) <<
"Unable to create performance log "
228 << logDir <<
": " << ec.message();
234 logFile_.open(
setup_.perfLog.c_str(), std::ios::out | std::ios::app);
238 JLOG(
j_.fatal()) <<
"Unable to open performance log " <<
setup_.perfLog <<
".";
282 report[jss::time] =
to_string(std::chrono::floor<microseconds>(present));
285 report[jss::workers] =
static_cast<unsigned int>(
counters_.jobs.size());
290 app_.getNodeStore().getCountsJson(
report[jss::nodestore]);
315 auto counter =
counters_.rpc.find(method);
319 UNREACHABLE(
"xrpl::perf::PerfLogImp::rpcStart : valid method input");
326 ++counter->second.value.started;
335 auto counter =
counters_.rpc.find(method);
339 UNREACHABLE(
"xrpl::perf::PerfLogImp::rpcEnd : valid method input");
346 auto const e =
counters_.methods.find(requestId);
349 startTime = e->second.second;
355 UNREACHABLE(
"xrpl::perf::PerfLogImp::rpcEnd : valid requestId input");
362 ++counter->second.value.finished;
366 ++counter->second.value.errored;
368 counter->second.value.duration +=
379 UNREACHABLE(
"xrpl::perf::PerfLogImp::jobQueue : valid job type input");
384 ++counter->second.value.queued;
398 UNREACHABLE(
"xrpl::perf::PerfLogImp::jobStart : valid job type input");
405 ++counter->second.value.started;
406 counter->second.value.queuedDuration += dur;
409 if (instance >= 0 && instance <
counters_.jobs.size())
410 counters_.jobs[instance] = {type, startTime};
420 UNREACHABLE(
"xrpl::perf::PerfLogImp::jobFinish : valid job type input");
427 ++counter->second.value.finished;
428 counter->second.value.runningDuration += dur;
431 if (instance >= 0 && instance <
counters_.jobs.size())
446 if (
setup_.perfLog.empty())
457 if (!
setup_.perfLog.empty())
482 set(perfLog,
"perf_log", section);
483 if (!perfLog.
empty())
485 setup.
perfLog = boost::filesystem::path(perfLog);
486 if (setup.
perfLog.is_relative())
488 setup.
perfLog = boost::filesystem::absolute(setup.
perfLog, configDir);
A generic endpoint for log messages.
Decorator for streaming out compact json.
Value & append(Value const &value)
Append value to array at the end.
Map::size_type size() const
static std::string const & name(JobType jt)
Holds a collection of configuration values.
std::condition_variable cond_
void jobFinish(JobType const type, microseconds dur, int instance) override
Log job finishing.
PerfLogImp(Setup setup, Application &app, beast::Journal journal, std::function< void()> &&signalStop)
void rpcStart(std::string const &method, std::uint64_t const requestId) override
Log start of RPC call.
void jobQueue(JobType const type) override
Log queued job.
void resizeJobs(int const resize) override
Ensure enough room to store each currently executing job.
system_time_point lastLog_
void rpcEnd(std::string const &method, std::uint64_t const requestId, bool finish)
void rotate() override
Rotate perf log file.
std::function< void()> const signalStop_
void jobStart(JobType const type, microseconds dur, steady_time_point startTime, int instance) override
Log job executing.
std::string const hostname_
std::chrono::microseconds microseconds
std::chrono::time_point< steady_clock > steady_time_point
T duration_cast(T... args)
void setCurrentThreadName(std::string_view newThreadName)
Changes the name of the caller thread.
@ Array
array value (ordered list)
@ Object
object value (collection of name/value pairs).
Dummy class for unit tests.
std::unique_ptr< PerfLog > makePerfLog(PerfLog::Setup const &setup, Application &app, beast::Journal journal, std::function< void()> &&signalStop)
PerfLog::Setup setupPerfLog(Section const §ion, boost::filesystem::path const &configDir)
bool set(T &target, std::string const &name, Section const §ion)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
bool getIfExists(Section const §ion, std::string const &name, T &v)
std::string to_string(BaseUInt< Bits, Tag > const &a)
static constexpr auto kLogInterval
Job Queue task performance counters.
microseconds queuedDuration
microseconds runningDuration
RPC performance counters.
std::vector< std::pair< JobType, steady_time_point > > jobs
std::unordered_map< std::string, Locked< Rpc > > rpc
json::Value countersJson() const
json::Value currentJson() const
Counters(std::set< char const * > const &labels, JobTypes const &jobTypes)
std::unordered_map< JobType, Locked< Jq > > jq
std::unordered_map< std::uint64_t, MethodStart > methods
Configuration from [perf] section of xrpld.cfg.
boost::filesystem::path perfLog