20 #include <ripple/basics/PerfLog.h>
21 #include <ripple/basics/random.h>
22 #include <ripple/beast/unit_test.h>
23 #include <ripple/json/json_reader.h>
24 #include <ripple/protocol/jss.h>
25 #include <ripple/rpc/impl/Handler.h>
26 #include <test/jtx/Env.h>
45 using path = boost::filesystem::path;
115 using namespace boost::filesystem;
116 return temp_directory_path() /
"perf_log_test_dir";
121 return {
"perf_log.txt"};
141 using namespace boost::filesystem;
145 if (exists (fullPath))
148 if (!exists (perfLogPath)
149 || !is_directory (perfLogPath)
150 || !is_empty (perfLogPath))
154 remove (perfLogPath);
165 [&parent] () { return parent.signalStop(); });
189 , name (
std::move (n))
204 cur.isMember (jss::job) ?
205 cur[jss::job].asString() : cur[jss::method].asString());
211 [] (
Cur const& lhs,
Cur const& rhs)
213 if (lhs.dur != rhs.dur)
214 return (rhs.dur < lhs.dur);
215 return (lhs.name < rhs.name);
228 using namespace boost::filesystem;
241 secondSize = file_size (
path);
242 }
while (firstSize >= secondSize);
247 }
while (secondSize >= file_size (
path));
255 using namespace boost::filesystem;
262 BEAST_EXPECT(! exists (perfLogPath));
266 BEAST_EXPECT(parent.stopSignaled ==
false);
267 BEAST_EXPECT(exists (perfLogPath));
274 if (!BEAST_EXPECT(! exists (perfLogPath)))
281 perfLogPath.c_str(), std::ios::out | std::ios::app);
282 if (! BEAST_EXPECT(nastyFile))
289 BEAST_EXPECT(parent.stopSignaled ==
false);
291 BEAST_EXPECT(parent.stopSignaled ==
true);
301 remove (perfLogPath);
308 if (! BEAST_EXPECT(! exists (perfLogPath)))
313 boost::system::error_code ec;
314 boost::filesystem::create_directories (perfLogPath, ec);
315 if (! BEAST_EXPECT(! ec))
318 auto fileWriteable = [](boost::filesystem::path
const& p) ->
bool
321 p.c_str(), std::ios::out | std::ios::app}.
is_open();
324 if (! BEAST_EXPECT(fileWriteable (fullPath)))
327 boost::filesystem::permissions (fullPath,
328 perms::remove_perms | perms::owner_write |
329 perms::others_write | perms::group_write);
333 if (fileWriteable (fullPath))
335 log <<
"Unable to write protect file. Test skipped."
342 BEAST_EXPECT(parent.stopSignaled ==
false);
344 BEAST_EXPECT(parent.stopSignaled ==
true);
354 boost::filesystem::permissions (fullPath,
355 perms::add_perms | perms::owner_write |
356 perms::others_write | perms::group_write);
377 ids.
reserve (labels.size() * 2);
380 mutable { return i++; });
383 mutable { return i--; });
388 for (
int labelIndex = 0; labelIndex < labels.size(); ++labelIndex)
390 for (
int idIndex = 0; idIndex < 2; ++idIndex)
394 labels[labelIndex], ids[(labelIndex * 2) + idIndex]);
399 Json::Value const countersJson {perfLog->countersJson()[
"rpc"]};
400 BEAST_EXPECT(countersJson.size() == labels.size() + 1);
401 for (
auto& label : labels)
405 BEAST_EXPECT(counter[jss::duration_us] ==
"0");
406 BEAST_EXPECT(counter[jss::errored] ==
"0");
407 BEAST_EXPECT(counter[jss::finished] ==
"0");
408 BEAST_EXPECT(counter[jss::started] ==
"2");
411 Json::Value const& total {countersJson[jss::total]};
412 BEAST_EXPECT(total[jss::duration_us] ==
"0");
413 BEAST_EXPECT(total[jss::errored] ==
"0");
414 BEAST_EXPECT(total[jss::finished] ==
"0");
423 BEAST_EXPECT(currents.size() == labels.size() * 2);
426 for (
int i = 0; i < currents.size(); ++i)
428 BEAST_EXPECT(currents[i].name == labels[i / 2]);
429 BEAST_EXPECT(prevDur > currents[i].dur);
430 prevDur = currents[i].dur;
437 for (
int labelIndex = labels.size() - 1; labelIndex > 0; --labelIndex)
440 perfLog->rpcFinish (labels[labelIndex], ids[(labelIndex * 2) + 1]);
442 perfLog->rpcError (labels[labelIndex], ids[(labelIndex * 2) + 0]);
444 perfLog->rpcFinish (labels[0], ids[0 + 1]);
447 auto validateFinalCounters =
451 Json::Value const& jobQueue = countersJson[jss::job_queue];
453 BEAST_EXPECT(jobQueue.
size() == 0);
457 BEAST_EXPECT(rpc.
size() == labels.size() + 1);
465 BEAST_EXPECT(first[jss::duration_us] !=
"0");
466 BEAST_EXPECT(first[jss::errored] ==
"0");
467 BEAST_EXPECT(first[jss::finished] ==
"1");
468 BEAST_EXPECT(first[jss::started] ==
"2");
473 for (
int i = 1; i < labels.size(); ++i)
478 BEAST_EXPECT(dur != 0 && dur < prevDur);
480 BEAST_EXPECT(counter[jss::errored] ==
"1");
481 BEAST_EXPECT(counter[jss::finished] ==
"1");
482 BEAST_EXPECT(counter[jss::started] ==
"2");
487 BEAST_EXPECT(total[jss::duration_us] !=
"0");
489 jsonToUint64 (total[jss::errored]) == labels.size() - 1);
493 jsonToUint64 (total[jss::started]) == labels.size() * 2);
496 auto validateFinalCurrent =
500 Json::Value const& job_queue = currentJson[jss::jobs];
501 BEAST_EXPECT(job_queue.
isArray());
502 BEAST_EXPECT(job_queue.
size() == 0);
505 Json::Value const& methods = currentJson[jss::methods];
506 BEAST_EXPECT(methods.
size() == 1);
507 BEAST_EXPECT(methods.
isArray());
510 BEAST_EXPECT(only.
size() == 2);
512 BEAST_EXPECT(only[jss::duration_us] !=
"0");
513 BEAST_EXPECT(only[jss::method] == labels[0]);
517 validateFinalCounters (perfLog->countersJson());
518 validateFinalCurrent (perfLog->currentJson());
526 auto const fullPath =
527 parent.getPerfLogPath() / parent.getPerfLogFileName();
531 BEAST_EXPECT(! exists (fullPath));
545 lastLine = std::move (line);
555 validateFinalCounters (parsedLastLine[jss::counters]);
556 validateFinalCurrent (parsedLastLine[jss::current_activities]);
579 , typeName (std::move (name))
586 jobs.
reserve (jobTypes.size());
587 for (
auto const& job : jobTypes)
596 for (
int i = 0; i < jobs.
size(); ++i)
598 perfLog->jobQueue (jobs[i].type);
600 perfLog->countersJson()[jss::job_queue]};
602 BEAST_EXPECT(jq_counters.size() == i + 2);
603 for (
int j = 0; j<= i; ++j)
607 Json::Value const& counter {jq_counters[jobs[j].typeName]};
608 BEAST_EXPECT(counter.size() == 5);
609 BEAST_EXPECT(counter[jss::queued] ==
"1");
610 BEAST_EXPECT(counter[jss::started] ==
"0");
611 BEAST_EXPECT(counter[jss::finished] ==
"0");
612 BEAST_EXPECT(counter[jss::queued_duration_us] ==
"0");
613 BEAST_EXPECT(counter[jss::running_duration_us] ==
"0");
617 Json::Value const& total {jq_counters[jss::total]};
618 BEAST_EXPECT(total.size() == 5);
619 BEAST_EXPECT(
jsonToUint64 (total[jss::queued]) == i + 1);
620 BEAST_EXPECT(total[jss::started] ==
"0");
621 BEAST_EXPECT(total[jss::finished] ==
"0");
622 BEAST_EXPECT(total[jss::queued_duration_us] ==
"0");
623 BEAST_EXPECT(total[jss::running_duration_us] ==
"0");
629 BEAST_EXPECT(
current.size() == 2);
630 BEAST_EXPECT(
current.isMember (jss::jobs));
631 BEAST_EXPECT(
current[jss::jobs].size() == 0);
632 BEAST_EXPECT(
current.isMember (jss::methods));
633 BEAST_EXPECT(
current[jss::methods].size() == 0);
639 perfLog->resizeJobs (jobs.
size() * 2);
645 for (
int i = 0; i < jobs.
size(); ++i)
648 jobs[i].type,
microseconds {i+1}, steady_clock::now(), i * 2);
653 perfLog->countersJson()[jss::job_queue]};
654 for (
int j = 0; j< jobs.
size(); ++j)
656 Json::Value const& counter {jq_counters[jobs[j].typeName]};
661 BEAST_EXPECT(counter[jss::started] ==
"2");
662 BEAST_EXPECT(queued_dur_us == j + 1);
666 BEAST_EXPECT(counter[jss::started] ==
"1");
667 BEAST_EXPECT(queued_dur_us == j + 1);
671 BEAST_EXPECT(counter[jss::started] ==
"0");
672 BEAST_EXPECT(queued_dur_us == 0);
675 BEAST_EXPECT(counter[jss::queued] ==
"1");
676 BEAST_EXPECT(counter[jss::finished] ==
"0");
677 BEAST_EXPECT(counter[jss::running_duration_us] ==
"0");
681 Json::Value const& total {jq_counters[jss::total]};
685 BEAST_EXPECT(total[jss::finished] ==
"0");
689 total[jss::queued_duration_us]) == (((i*i) + 3*i + 2) / 2));
690 BEAST_EXPECT(total[jss::running_duration_us] ==
"0");
693 perfLog->jobStart (jobs[i].type,
702 BEAST_EXPECT(currents.size() == (i + 1) * 2);
705 for (
int j = 0; j <= i; ++j)
707 BEAST_EXPECT(currents[j * 2].name == jobs[j].typeName);
708 BEAST_EXPECT(prevDur > currents[j * 2].dur);
709 prevDur = currents[j * 2].dur;
711 BEAST_EXPECT(currents[(j * 2) + 1].name == jobs[j].typeName);
712 BEAST_EXPECT(prevDur > currents[(j * 2) + 1].dur);
713 prevDur = currents[(j * 2) + 1].dur;
718 for (
int i = jobs.
size() - 1; i >= 0; --i)
722 int const finished = ((jobs.
size() - i) * 2) - 1;
728 perfLog->countersJson()[jss::job_queue]};
729 for (
int j = 0; j < jobs.
size(); ++j)
731 Json::Value const& counter {jq_counters[jobs[j].typeName]};
736 BEAST_EXPECT(counter[jss::finished] ==
"0");
737 BEAST_EXPECT(running_dur_us == 0);
741 BEAST_EXPECT(counter[jss::finished] ==
"1");
742 BEAST_EXPECT(running_dur_us == ((jobs.
size() - j) * 2) - 1);
746 BEAST_EXPECT(counter[jss::finished] ==
"2");
747 BEAST_EXPECT(running_dur_us == ((jobs.
size() - j) * 4) - 1);
752 BEAST_EXPECT(queued_dur_us == j + 1);
753 BEAST_EXPECT(counter[jss::queued] ==
"1");
754 BEAST_EXPECT(counter[jss::started] ==
"2");
758 Json::Value const& total {jq_counters[jss::total]};
767 int const queuedDur = ((jobs.
size() * (jobs.
size() + 1)) / 2);
769 jsonToUint64 (total[jss::queued_duration_us]) == queuedDur);
772 int const runningDur = ((finished * (finished + 1)) / 2);
774 total[jss::running_duration_us]) == runningDur);
785 BEAST_EXPECT(currents.size() == i * 2);
788 for (
int j = 0; j < i; ++j)
790 BEAST_EXPECT(currents[j * 2].name == jobs[j].typeName);
791 BEAST_EXPECT(prevDur > currents[j * 2].dur);
792 prevDur = currents[j * 2].dur;
794 BEAST_EXPECT(currents[(j * 2) + 1].name == jobs[j].typeName);
795 BEAST_EXPECT(prevDur > currents[(j * 2) + 1].dur);
796 prevDur = currents[(j * 2) + 1].dur;
801 auto validateFinalCounters =
807 BEAST_EXPECT(rpc.
size() == 0);
810 Json::Value const& jobQueue = countersJson[jss::job_queue];
811 for (
int i = jobs.
size() - 1; i >= 0; --i)
813 Json::Value const& counter {jobQueue[jobs[i].typeName]};
816 BEAST_EXPECT(running_dur_us == ((jobs.
size() - i) * 4) - 1);
820 BEAST_EXPECT(queued_dur_us == i + 1);
822 BEAST_EXPECT(counter[jss::queued] ==
"1");
823 BEAST_EXPECT(counter[jss::started] ==
"2");
824 BEAST_EXPECT(counter[jss::finished] ==
"2");
829 const int finished = jobs.
size() * 2;
838 int const queuedDur = ((jobs.
size() * (jobs.
size() + 1)) / 2);
840 jsonToUint64 (total[jss::queued_duration_us]) == queuedDur);
843 int const runningDur = ((finished * (finished + 1)) / 2);
845 total[jss::running_duration_us]) == runningDur);
848 auto validateFinalCurrent =
854 BEAST_EXPECT(j.
size() == 0);
857 Json::Value const& methods = currentJson[jss::methods];
858 BEAST_EXPECT(methods.
size() == 0);
859 BEAST_EXPECT(methods.
isArray());
863 validateFinalCounters (perfLog->countersJson());
864 validateFinalCurrent (perfLog->currentJson());
873 auto const fullPath =
874 parent.getPerfLogPath() / parent.getPerfLogFileName();
878 BEAST_EXPECT(! exists (fullPath));
892 lastLine = std::move (line);
902 validateFinalCounters (parsedLastLine[jss::counters]);
903 validateFinalCurrent (parsedLastLine[jss::current_activities]);
926 auto iter {jobTypes.begin()};
929 jobType = iter->second.type();
930 jobTypeName = iter->second.name();
934 perfLog-> resizeJobs(1);
937 auto verifyCounters =
938 [
this, jobTypeName] (
Json::Value const& countersJson,
939 int started,
int finished,
int queued_us,
int running_us)
941 BEAST_EXPECT(countersJson.
isObject());
942 BEAST_EXPECT(countersJson.
size() == 2);
944 BEAST_EXPECT(countersJson.
isMember (jss::rpc));
945 BEAST_EXPECT(countersJson[jss::rpc].isObject());
946 BEAST_EXPECT(countersJson[jss::rpc].size() == 0);
948 BEAST_EXPECT(countersJson.
isMember (jss::job_queue));
949 BEAST_EXPECT(countersJson[jss::job_queue].isObject());
950 BEAST_EXPECT(countersJson[jss::job_queue].size() == 1);
953 countersJson[jss::job_queue][jobTypeName]};
955 BEAST_EXPECT(job.isObject());
958 BEAST_EXPECT(
jsonToUint64 (job[jss::finished]) == finished);
961 jsonToUint64 (job[jss::queued_duration_us]) == queued_us);
963 jsonToUint64 (job[jss::running_duration_us]) == running_us);
968 auto verifyEmptyCurrent = [
this] (
Json::Value const& currentJson)
970 BEAST_EXPECT(currentJson.isObject());
971 BEAST_EXPECT(currentJson.size() == 2);
973 BEAST_EXPECT(currentJson.isMember (jss::jobs));
974 BEAST_EXPECT(currentJson[jss::jobs].isArray());
975 BEAST_EXPECT(currentJson[jss::jobs].size() == 0);
977 BEAST_EXPECT(currentJson.isMember (jss::methods));
978 BEAST_EXPECT(currentJson[jss::methods].isArray());
979 BEAST_EXPECT(currentJson[jss::methods].size() == 0);
983 perfLog->jobStart (jobType,
microseconds {11}, steady_clock::now(), 2);
985 verifyCounters (perfLog->countersJson(), 1, 0, 11, 0);
986 verifyEmptyCurrent (perfLog->currentJson());
989 perfLog->jobStart (jobType,
microseconds {13}, steady_clock::now(), -1);
991 verifyCounters (perfLog->countersJson(), 2, 0, 24, 0);
992 verifyEmptyCurrent (perfLog->currentJson());
997 verifyCounters (perfLog->countersJson(), 2, 1, 24, 17);
998 verifyEmptyCurrent (perfLog->currentJson());
1003 verifyCounters (perfLog->countersJson(), 2, 2, 24, 36);
1004 verifyEmptyCurrent (perfLog->currentJson());
1013 auto const fullPath =
1014 parent.getPerfLogPath() / parent.getPerfLogFileName();
1018 BEAST_EXPECT(! exists (fullPath));
1032 lastLine = std::move (line);
1042 verifyCounters (parsedLastLine[jss::counters], 2, 2, 24, 36);
1043 verifyEmptyCurrent (parsedLastLine[jss::current_activities]);
1052 using namespace boost::filesystem;
1058 BEAST_EXPECT(! exists (perfLogPath));
1060 auto perfLog {
getPerfLog (parent, withFile)};
1062 BEAST_EXPECT(parent.stopSignaled ==
false);
1065 BEAST_EXPECT(! exists (perfLogPath));
1069 BEAST_EXPECT(exists (fullPath));
1070 BEAST_EXPECT(file_size (fullPath) == 0);
1078 decltype (file_size (fullPath)) firstFileSize {0};
1081 BEAST_EXPECT(! exists (perfLogPath));
1085 firstFileSize = file_size (fullPath);
1086 BEAST_EXPECT(firstFileSize > 0);
1097 BEAST_EXPECT(! exists (perfLogPath));
1101 BEAST_EXPECT(file_size (fullPath) > firstFileSize);