1#include <xrpld/perflog/detail/PerfLogImp.h>
3#include <xrpld/app/main/Application.h>
5#include <xrpl/basics/Log.h>
6#include <xrpl/basics/StringUtilities.h>
7#include <xrpl/basics/chrono.h>
8#include <xrpl/beast/core/CurrentThreadName.h>
9#include <xrpl/beast/utility/Journal.h>
10#include <xrpl/beast/utility/instrumentation.h>
11#include <xrpl/config/BasicConfig.h>
12#include <xrpl/config/Constants.h>
13#include <xrpl/core/Job.h>
14#include <xrpl/core/JobTypes.h>
15#include <xrpl/core/PerfLog.h>
16#include <xrpl/json/json_value.h>
17#include <xrpl/json/json_writer.h>
18#include <xrpl/nodestore/Database.h>
19#include <xrpl/protocol/jss.h>
20#include <xrpl/server/NetworkOPs.h>
49 rpc.reserve(methodNames.
size());
50 for (
auto const& name : methodNames)
52 auto const inserted =
rpc.try_emplace(name).second;
56 UNREACHABLE(
"xrpl::perf::PerfLogImp::Counters::Counters : method name is unique");
63 jq.reserve(jobTypes.
size());
64 for (
auto const& [jobType, _] : jobTypes)
66 auto const inserted =
jq.emplace(jobType,
Jq()).second;
71 UNREACHABLE(
"xrpl::perf::PerfLogImp::Counters::Counters : failed to insert job type");
87 for (
auto const& label :
labels)
89 auto const entry =
rpc.find(label);
90 if (entry ==
rpc.end())
93 UNREACHABLE(
"xrpl::perf::PerfLogImp::Counters::countersJson : label has a counter");
97 auto const& counter = entry->second;
102 if ((counter.value.started == 0u) && (counter.value.finished == 0u) &&
103 (counter.value.errored == 0u))
107 value = counter.value;
112 totalRpc.
started += value.started;
114 totalRpc.
finished += value.finished;
116 totalRpc.
errored += value.errored;
118 totalRpc.
duration += value.duration;
129 rpcobj[jss::total] = totalRpcJson;
135 for (
auto const& proc :
jq)
140 if ((proc.second.value.queued == 0u) && (proc.second.value.started == 0u) &&
141 (proc.second.value.finished == 0u))
145 value = proc.second.value;
150 totalJq.
queued += value.queued;
152 totalJq.
started += value.started;
155 j[jss::queued_duration_us] =
std::to_string(value.queuedDuration.count());
157 j[jss::running_duration_us] =
std::to_string(value.runningDuration.count());
170 jobQueueObj[jss::total] = totalJqJson;
176 counters[jss::rpc] = rpcobj;
177 counters[jss::job_queue] = jobQueueObj;
187 auto const jobs = [
this] {
192 for (
auto const& j :
jobs)
198 jobj[jss::duration_us] =
208 for (
auto const& m : this->methods)
217 methodobj[jss::duration_us] =
219 methodsArray.
append(methodobj);
223 current[jss::jobs] = jobsArray;
224 current[jss::methods] = methodsArray;
233 if (
setup_.perfLog.empty())
239 auto logDir =
setup_.perfLog.parent_path();
246 JLOG(
j_.fatal()) <<
"Unable to create performance log "
248 << logDir <<
": " << ec.
message();
254 logFile_.open(
setup_.perfLog.c_str(), std::ios::out | std::ios::app);
258 JLOG(
j_.fatal()) <<
"Unable to open performance log " <<
setup_.perfLog <<
".";
302 report[jss::time] =
to_string(std::chrono::floor<Microseconds>(present));
305 report[jss::workers] =
static_cast<unsigned int>(
counters_.jobs.size());
310 app_.getNodeStore().getCountsJson(
report[jss::nodestore]);
340 auto counter =
counters_.rpc.find(method);
344 UNREACHABLE(
"xrpl::perf::PerfLogImp::rpcStart : valid method input");
351 ++counter->second.value.started;
361 auto counter =
counters_.rpc.find(method);
365 UNREACHABLE(
"xrpl::perf::PerfLogImp::rpcEnd : valid method input");
372 auto const e =
counters_.methods.find(requestId);
375 startTime = e->second.second;
381 UNREACHABLE(
"xrpl::perf::PerfLogImp::rpcEnd : valid requestId input");
388 ++counter->second.value.finished;
392 ++counter->second.value.errored;
394 counter->second.value.duration +=
405 UNREACHABLE(
"xrpl::perf::PerfLogImp::jobQueue : valid job type input");
410 ++counter->second.value.queued;
420 UNREACHABLE(
"xrpl::perf::PerfLogImp::jobStart : valid job type input");
427 ++counter->second.value.started;
428 counter->second.value.queuedDuration += dur;
431 if (instance >= 0 && instance <
counters_.jobs.size())
432 counters_.jobs[instance] = {type, startTime};
442 UNREACHABLE(
"xrpl::perf::PerfLogImp::jobFinish : valid job type input");
449 ++counter->second.value.finished;
450 counter->second.value.runningDuration += dur;
453 if (instance >= 0 && instance <
counters_.jobs.size())
468 if (
setup_.perfLog.empty())
479 if (!
setup_.perfLog.empty())
504 set(perfLog,
"perf_log", section);
505 if (!perfLog.
empty())
A generic endpoint for log messages.
Decorator for streaming out compact json.
Lightweight wrapper to tag static string.
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.
PerfLogImp(Setup setup, Application &app, std::span< NullTerminatedView const > methodNames, beast::Journal journal, std::function< void()> &&signalStop)
std::condition_variable cond_
void rpcEnd(std::string_view method, std::uint64_t const requestId, bool finish)
void jobQueue(JobType const type) override
Log queued job.
void resizeJobs(int const resize) override
Ensure enough room to store each currently executing job.
void jobStart(JobType const type, Microseconds dur, SteadyTimePoint startTime, int instance) override
Log job executing.
void rotate() override
Rotate perf log file.
std::function< void()> const signalStop_
void rpcStart(std::string_view method, std::uint64_t const requestId) override
Log start of RPC call.
void jobFinish(JobType const type, Microseconds dur, int instance) override
Log job finishing.
std::string const hostname_
std::chrono::microseconds Microseconds
std::chrono::time_point< SteadyClock > SteadyTimePoint
T create_directories(T... args)
T duration_cast(T... args)
T is_directory(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, std::span< NullTerminatedView const > methodNames, beast::Journal journal, std::function< void()> &&signalStop)
PerfLog::Setup setupPerfLog(Section const §ion, std::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< NullTerminatedView > labels
std::unordered_map< std::string_view, Locked< Rpc > > rpc
json::Value countersJson() const
json::Value currentJson() const
std::vector< std::pair< JobType, SteadyTimePoint > > jobs
std::unordered_map< JobType, Locked< Jq > > jq
std::unordered_map< std::uint64_t, MethodStart > methods
Counters(std::span< NullTerminatedView const > methodNames, JobTypes const &jobTypes)
Configuration from [perf] section of xrpld.cfg.
std::filesystem::path perfLog