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>
30 #include <test/jtx/Env.h>
41 using path = boost::filesystem::path;
119 using namespace boost::filesystem;
120 return temp_directory_path() /
"perf_log_test_dir";
126 return {
"perf_log.txt"};
148 using namespace boost::filesystem;
152 if (exists(fullPath))
155 if (!exists(perfLogPath) || !is_directory(perfLogPath) ||
156 !is_empty(perfLogPath))
171 parent.
getSetup(withFile), parent,
j_, [&parent]() {
172 return parent.signalStop();
213 cur.isMember(jss::job) ? cur[jss::job].asString()
214 : cur[jss::method].asString());
222 [](
Cur const& lhs,
Cur const& rhs) {
223 if (lhs.dur != rhs.dur)
224 return (rhs.dur < lhs.dur);
225 return (lhs.name < rhs.name);
239 using namespace boost::filesystem;
252 secondSize = file_size(
path);
253 }
while (firstSize >= secondSize);
258 }
while (secondSize >= file_size(
path));
267 using namespace boost::filesystem;
274 BEAST_EXPECT(!exists(perfLogPath));
278 BEAST_EXPECT(parent.stopSignaled ==
false);
279 BEAST_EXPECT(exists(perfLogPath));
286 if (!BEAST_EXPECT(!exists(perfLogPath)))
293 perfLogPath.c_str(), std::ios::out | std::ios::app);
294 if (!BEAST_EXPECT(nastyFile))
301 BEAST_EXPECT(parent.stopSignaled ==
false);
303 BEAST_EXPECT(parent.stopSignaled ==
true);
320 if (!BEAST_EXPECT(!exists(perfLogPath)))
325 boost::system::error_code ec;
326 boost::filesystem::create_directories(perfLogPath, ec);
327 if (!BEAST_EXPECT(!ec))
330 auto fileWriteable = [](boost::filesystem::path
const& p) ->
bool {
331 return std::ofstream{p.c_str(), std::ios::out | std::ios::app}
335 if (!BEAST_EXPECT(fileWriteable(fullPath)))
338 boost::filesystem::permissions(
340 perms::remove_perms | perms::owner_write | perms::others_write |
345 if (fileWriteable(fullPath))
347 log <<
"Unable to write protect file. Test skipped."
354 BEAST_EXPECT(parent.stopSignaled ==
false);
356 BEAST_EXPECT(parent.stopSignaled ==
true);
366 boost::filesystem::permissions(
368 perms::add_perms | perms::owner_write | perms::others_write |
391 ids.
reserve(labels.size() * 2);
408 for (
int labelIndex = 0; labelIndex < labels.size(); ++labelIndex)
410 for (
int idIndex = 0; idIndex < 2; ++idIndex)
414 labels[labelIndex], ids[(labelIndex * 2) + idIndex]);
419 Json::Value const countersJson{perfLog->countersJson()[
"rpc"]};
420 BEAST_EXPECT(countersJson.size() == labels.size() + 1);
421 for (
auto& label : labels)
425 BEAST_EXPECT(counter[jss::duration_us] ==
"0");
426 BEAST_EXPECT(counter[jss::errored] ==
"0");
427 BEAST_EXPECT(counter[jss::finished] ==
"0");
428 BEAST_EXPECT(counter[jss::started] ==
"2");
431 Json::Value const& total{countersJson[jss::total]};
432 BEAST_EXPECT(total[jss::duration_us] ==
"0");
433 BEAST_EXPECT(total[jss::errored] ==
"0");
434 BEAST_EXPECT(total[jss::finished] ==
"0");
443 BEAST_EXPECT(currents.size() == labels.size() * 2);
446 for (
int i = 0; i < currents.size(); ++i)
448 BEAST_EXPECT(currents[i].name == labels[i / 2]);
449 BEAST_EXPECT(prevDur > currents[i].dur);
450 prevDur = currents[i].dur;
457 for (
int labelIndex = labels.size() - 1; labelIndex > 0; --labelIndex)
460 perfLog->rpcFinish(labels[labelIndex], ids[(labelIndex * 2) + 1]);
462 perfLog->rpcError(labels[labelIndex], ids[(labelIndex * 2) + 0]);
464 perfLog->rpcFinish(labels[0], ids[0 + 1]);
467 auto validateFinalCounters = [
this, &labels](
470 Json::Value const& jobQueue = countersJson[jss::job_queue];
472 BEAST_EXPECT(jobQueue.
size() == 0);
476 BEAST_EXPECT(rpc.
size() == labels.size() + 1);
484 BEAST_EXPECT(first[jss::duration_us] !=
"0");
485 BEAST_EXPECT(first[jss::errored] ==
"0");
486 BEAST_EXPECT(first[jss::finished] ==
"1");
487 BEAST_EXPECT(first[jss::started] ==
"2");
492 for (
int i = 1; i < labels.size(); ++i)
497 BEAST_EXPECT(dur != 0 && dur < prevDur);
499 BEAST_EXPECT(counter[jss::errored] ==
"1");
500 BEAST_EXPECT(counter[jss::finished] ==
"1");
501 BEAST_EXPECT(counter[jss::started] ==
"2");
506 BEAST_EXPECT(total[jss::duration_us] !=
"0");
508 jsonToUint64(total[jss::errored]) == labels.size() - 1);
509 BEAST_EXPECT(
jsonToUint64(total[jss::finished]) == labels.size());
511 jsonToUint64(total[jss::started]) == labels.size() * 2);
514 auto validateFinalCurrent = [
this,
517 Json::Value const& job_queue = currentJson[jss::jobs];
518 BEAST_EXPECT(job_queue.
isArray());
519 BEAST_EXPECT(job_queue.
size() == 0);
522 Json::Value const& methods = currentJson[jss::methods];
523 BEAST_EXPECT(methods.
size() == 1);
524 BEAST_EXPECT(methods.
isArray());
527 BEAST_EXPECT(only.
size() == 2);
529 BEAST_EXPECT(only[jss::duration_us] !=
"0");
530 BEAST_EXPECT(only[jss::method] == labels[0]);
534 validateFinalCounters(perfLog->countersJson());
535 validateFinalCurrent(perfLog->currentJson());
543 auto const fullPath =
544 parent.getPerfLogPath() / parent.getPerfLogFileName();
548 BEAST_EXPECT(!exists(fullPath));
562 lastLine = std::move(line);
572 validateFinalCounters(parsedLastLine[jss::counters]);
573 validateFinalCurrent(parsedLastLine[jss::current_activities]);
596 : type(t), typeName(std::move(name))
605 for (
auto const& job : jobTypes)
614 for (
int i = 0; i < jobs.
size(); ++i)
616 perfLog->jobQueue(jobs[i].type);
618 perfLog->countersJson()[jss::job_queue]};
620 BEAST_EXPECT(jq_counters.size() == i + 2);
621 for (
int j = 0; j <= i; ++j)
625 Json::Value const& counter{jq_counters[jobs[j].typeName]};
626 BEAST_EXPECT(counter.size() == 5);
627 BEAST_EXPECT(counter[jss::queued] ==
"1");
628 BEAST_EXPECT(counter[jss::started] ==
"0");
629 BEAST_EXPECT(counter[jss::finished] ==
"0");
630 BEAST_EXPECT(counter[jss::queued_duration_us] ==
"0");
631 BEAST_EXPECT(counter[jss::running_duration_us] ==
"0");
636 BEAST_EXPECT(total.size() == 5);
637 BEAST_EXPECT(
jsonToUint64(total[jss::queued]) == i + 1);
638 BEAST_EXPECT(total[jss::started] ==
"0");
639 BEAST_EXPECT(total[jss::finished] ==
"0");
640 BEAST_EXPECT(total[jss::queued_duration_us] ==
"0");
641 BEAST_EXPECT(total[jss::running_duration_us] ==
"0");
647 BEAST_EXPECT(
current.size() == 2);
648 BEAST_EXPECT(
current.isMember(jss::jobs));
649 BEAST_EXPECT(
current[jss::jobs].size() == 0);
650 BEAST_EXPECT(
current.isMember(jss::methods));
651 BEAST_EXPECT(
current[jss::methods].size() == 0);
657 perfLog->resizeJobs(jobs.
size() * 2);
663 for (
int i = 0; i < jobs.
size(); ++i)
666 jobs[i].type,
microseconds{i + 1}, steady_clock::now(), i * 2);
671 perfLog->countersJson()[jss::job_queue]};
672 for (
int j = 0; j < jobs.
size(); ++j)
674 Json::Value const& counter{jq_counters[jobs[j].typeName]};
679 BEAST_EXPECT(counter[jss::started] ==
"2");
680 BEAST_EXPECT(queued_dur_us == j + 1);
684 BEAST_EXPECT(counter[jss::started] ==
"1");
685 BEAST_EXPECT(queued_dur_us == j + 1);
689 BEAST_EXPECT(counter[jss::started] ==
"0");
690 BEAST_EXPECT(queued_dur_us == 0);
693 BEAST_EXPECT(counter[jss::queued] ==
"1");
694 BEAST_EXPECT(counter[jss::finished] ==
"0");
695 BEAST_EXPECT(counter[jss::running_duration_us] ==
"0");
701 BEAST_EXPECT(
jsonToUint64(total[jss::started]) == (i * 2) + 1);
702 BEAST_EXPECT(total[jss::finished] ==
"0");
707 (((i * i) + 3 * i + 2) / 2));
708 BEAST_EXPECT(total[jss::running_duration_us] ==
"0");
723 BEAST_EXPECT(currents.size() == (i + 1) * 2);
726 for (
int j = 0; j <= i; ++j)
728 BEAST_EXPECT(currents[j * 2].name == jobs[j].typeName);
729 BEAST_EXPECT(prevDur > currents[j * 2].dur);
730 prevDur = currents[j * 2].dur;
732 BEAST_EXPECT(currents[(j * 2) + 1].name == jobs[j].typeName);
733 BEAST_EXPECT(prevDur > currents[(j * 2) + 1].dur);
734 prevDur = currents[(j * 2) + 1].dur;
739 for (
int i = jobs.
size() - 1; i >= 0; --i)
743 int const finished = ((jobs.
size() - i) * 2) - 1;
749 perfLog->countersJson()[jss::job_queue]};
750 for (
int j = 0; j < jobs.
size(); ++j)
752 Json::Value const& counter{jq_counters[jobs[j].typeName]};
757 BEAST_EXPECT(counter[jss::finished] ==
"0");
758 BEAST_EXPECT(running_dur_us == 0);
762 BEAST_EXPECT(counter[jss::finished] ==
"1");
763 BEAST_EXPECT(running_dur_us == ((jobs.
size() - j) * 2) - 1);
767 BEAST_EXPECT(counter[jss::finished] ==
"2");
768 BEAST_EXPECT(running_dur_us == ((jobs.
size() - j) * 4) - 1);
773 BEAST_EXPECT(queued_dur_us == j + 1);
774 BEAST_EXPECT(counter[jss::queued] ==
"1");
775 BEAST_EXPECT(counter[jss::started] ==
"2");
783 BEAST_EXPECT(
jsonToUint64(total[jss::finished]) == finished);
787 int const queuedDur = ((jobs.
size() * (jobs.
size() + 1)) / 2);
789 jsonToUint64(total[jss::queued_duration_us]) == queuedDur);
792 int const runningDur = ((finished * (finished + 1)) / 2);
806 BEAST_EXPECT(currents.size() == i * 2);
809 for (
int j = 0; j < i; ++j)
811 BEAST_EXPECT(currents[j * 2].name == jobs[j].typeName);
812 BEAST_EXPECT(prevDur > currents[j * 2].dur);
813 prevDur = currents[j * 2].dur;
815 BEAST_EXPECT(currents[(j * 2) + 1].name == jobs[j].typeName);
816 BEAST_EXPECT(prevDur > currents[(j * 2) + 1].dur);
817 prevDur = currents[(j * 2) + 1].dur;
822 auto validateFinalCounters = [
this,
827 BEAST_EXPECT(rpc.
size() == 0);
830 Json::Value const& jobQueue = countersJson[jss::job_queue];
831 for (
int i = jobs.
size() - 1; i >= 0; --i)
833 Json::Value const& counter{jobQueue[jobs[i].typeName]};
836 BEAST_EXPECT(running_dur_us == ((jobs.
size() - i) * 4) - 1);
840 BEAST_EXPECT(queued_dur_us == i + 1);
842 BEAST_EXPECT(counter[jss::queued] ==
"1");
843 BEAST_EXPECT(counter[jss::started] ==
"2");
844 BEAST_EXPECT(counter[jss::finished] ==
"2");
849 const int finished = jobs.
size() * 2;
851 BEAST_EXPECT(
jsonToUint64(total[jss::started]) == finished);
852 BEAST_EXPECT(
jsonToUint64(total[jss::finished]) == finished);
856 int const queuedDur = ((jobs.
size() * (jobs.
size() + 1)) / 2);
858 jsonToUint64(total[jss::queued_duration_us]) == queuedDur);
861 int const runningDur = ((finished * (finished + 1)) / 2);
863 jsonToUint64(total[jss::running_duration_us]) == runningDur);
866 auto validateFinalCurrent = [
this](
Json::Value const& currentJson) {
870 BEAST_EXPECT(j.
size() == 0);
873 Json::Value const& methods = currentJson[jss::methods];
874 BEAST_EXPECT(methods.
size() == 0);
875 BEAST_EXPECT(methods.
isArray());
879 validateFinalCounters(perfLog->countersJson());
880 validateFinalCurrent(perfLog->currentJson());
889 auto const fullPath =
890 parent.getPerfLogPath() / parent.getPerfLogFileName();
894 BEAST_EXPECT(!exists(fullPath));
908 lastLine = std::move(line);
918 validateFinalCounters(parsedLastLine[jss::counters]);
919 validateFinalCurrent(parsedLastLine[jss::current_activities]);
943 auto iter{jobTypes.begin()};
946 jobType = iter->second.type();
947 jobTypeName = iter->second.name();
951 perfLog->resizeJobs(1);
954 auto verifyCounters = [
this, jobTypeName](
960 BEAST_EXPECT(countersJson.
isObject());
961 BEAST_EXPECT(countersJson.
size() == 2);
963 BEAST_EXPECT(countersJson.
isMember(jss::rpc));
964 BEAST_EXPECT(countersJson[jss::rpc].isObject());
965 BEAST_EXPECT(countersJson[jss::rpc].size() == 0);
967 BEAST_EXPECT(countersJson.
isMember(jss::job_queue));
968 BEAST_EXPECT(countersJson[jss::job_queue].isObject());
969 BEAST_EXPECT(countersJson[jss::job_queue].size() == 1);
972 countersJson[jss::job_queue][jobTypeName]};
974 BEAST_EXPECT(job.isObject());
977 BEAST_EXPECT(
jsonToUint64(job[jss::finished]) == finished);
980 jsonToUint64(job[jss::queued_duration_us]) == queued_us);
982 jsonToUint64(job[jss::running_duration_us]) == running_us);
987 auto verifyEmptyCurrent = [
this](
Json::Value const& currentJson) {
988 BEAST_EXPECT(currentJson.isObject());
989 BEAST_EXPECT(currentJson.size() == 2);
991 BEAST_EXPECT(currentJson.isMember(jss::jobs));
992 BEAST_EXPECT(currentJson[jss::jobs].isArray());
993 BEAST_EXPECT(currentJson[jss::jobs].size() == 0);
995 BEAST_EXPECT(currentJson.isMember(jss::methods));
996 BEAST_EXPECT(currentJson[jss::methods].isArray());
997 BEAST_EXPECT(currentJson[jss::methods].size() == 0);
1001 perfLog->jobStart(jobType,
microseconds{11}, steady_clock::now(), 2);
1003 verifyCounters(perfLog->countersJson(), 1, 0, 11, 0);
1004 verifyEmptyCurrent(perfLog->currentJson());
1007 perfLog->jobStart(jobType,
microseconds{13}, steady_clock::now(), -1);
1009 verifyCounters(perfLog->countersJson(), 2, 0, 24, 0);
1010 verifyEmptyCurrent(perfLog->currentJson());
1015 verifyCounters(perfLog->countersJson(), 2, 1, 24, 17);
1016 verifyEmptyCurrent(perfLog->currentJson());
1021 verifyCounters(perfLog->countersJson(), 2, 2, 24, 36);
1022 verifyEmptyCurrent(perfLog->currentJson());
1031 auto const fullPath =
1032 parent.getPerfLogPath() / parent.getPerfLogFileName();
1036 BEAST_EXPECT(!exists(fullPath));
1050 lastLine = std::move(line);
1060 verifyCounters(parsedLastLine[jss::counters], 2, 2, 24, 36);
1061 verifyEmptyCurrent(parsedLastLine[jss::current_activities]);
1071 using namespace boost::filesystem;
1077 BEAST_EXPECT(!exists(perfLogPath));
1081 BEAST_EXPECT(parent.stopSignaled ==
false);
1084 BEAST_EXPECT(!exists(perfLogPath));
1088 BEAST_EXPECT(exists(fullPath));
1089 BEAST_EXPECT(file_size(fullPath) == 0);
1097 decltype(file_size(fullPath)) firstFileSize{0};
1100 BEAST_EXPECT(!exists(perfLogPath));
1104 firstFileSize = file_size(fullPath);
1105 BEAST_EXPECT(firstFileSize > 0);
1116 BEAST_EXPECT(!exists(perfLogPath));
1120 BEAST_EXPECT(file_size(fullPath) > firstFileSize);