20 #include <ripple/basics/PerfLog.h>
21 #include <ripple/basics/random.h>
22 #include <ripple/beast/unit_test.h>
23 #include <ripple/beast/utility/Journal.h>
24 #include <ripple/json/json_reader.h>
25 #include <ripple/protocol/jss.h>
26 #include <ripple/rpc/impl/Handler.h>
27 #include <test/jtx/Env.h>
28 #include <test/jtx/TestHelpers.h>
45 using path = boost::filesystem::path;
68 using namespace boost::filesystem;
75 if (!exists(dir) || !is_directory(dir) || !is_empty(dir))
91 using namespace boost::filesystem;
92 return temp_directory_path() /
"perf_log_test_dir";
98 return logDir() /
"perf_log.txt";
122 using namespace boost::filesystem;
135 secondSize = file_size(
path);
136 }
while (firstSize >= secondSize);
141 }
while (secondSize >= file_size(
path));
177 cur.isMember(jss::job) ? cur[jss::job].asString()
178 : cur[jss::method].asString());
186 [](
Cur const& lhs,
Cur const& rhs) {
187 if (lhs.dur != rhs.dur)
188 return (rhs.dur < lhs.dur);
189 return (lhs.name < rhs.name);
198 using namespace boost::filesystem;
203 BEAST_EXPECT(!exists(fixture.logFile()));
207 BEAST_EXPECT(fixture.stopSignaled ==
false);
208 BEAST_EXPECT(exists(fixture.logFile()));
215 if (!BEAST_EXPECT(!exists(fixture.logDir())))
222 fixture.logDir().c_str(), std::ios::out | std::ios::app);
223 if (!BEAST_EXPECT(nastyFile))
230 BEAST_EXPECT(fixture.stopSignaled ==
false);
232 BEAST_EXPECT(fixture.stopSignaled ==
true);
242 remove(fixture.logDir());
249 if (!BEAST_EXPECT(!exists(fixture.logDir())))
254 boost::system::error_code ec;
255 boost::filesystem::create_directories(fixture.logDir(), ec);
256 if (!BEAST_EXPECT(!ec))
259 auto fileWriteable = [](boost::filesystem::path
const& p) ->
bool {
260 return std::ofstream{p.c_str(), std::ios::out | std::ios::app}
264 if (!BEAST_EXPECT(fileWriteable(fixture.logFile())))
267 boost::filesystem::permissions(
269 perms::remove_perms | perms::owner_write | perms::others_write |
274 if (fileWriteable(fixture.logFile()))
276 log <<
"Unable to write protect file. Test skipped."
283 BEAST_EXPECT(fixture.stopSignaled ==
false);
285 BEAST_EXPECT(fixture.stopSignaled ==
true);
295 boost::filesystem::permissions(
297 perms::add_perms | perms::owner_write | perms::others_write |
308 auto perfLog{fixture.perfLog(withFile)};
338 for (
int labelIndex = 0; labelIndex < labels.
size(); ++labelIndex)
340 for (
int idIndex = 0; idIndex < 2; ++idIndex)
344 labels[labelIndex], ids[(labelIndex * 2) + idIndex]);
350 BEAST_EXPECT(countersJson.size() == labels.
size() + 1);
351 for (
auto& label : labels)
355 BEAST_EXPECT(counter[jss::duration_us] ==
"0");
356 BEAST_EXPECT(counter[jss::errored] ==
"0");
357 BEAST_EXPECT(counter[jss::finished] ==
"0");
358 BEAST_EXPECT(counter[jss::started] ==
"2");
361 Json::Value const& total{countersJson[jss::total]};
362 BEAST_EXPECT(total[jss::duration_us] ==
"0");
363 BEAST_EXPECT(total[jss::errored] ==
"0");
364 BEAST_EXPECT(total[jss::finished] ==
"0");
373 BEAST_EXPECT(currents.size() == labels.
size() * 2);
376 for (
int i = 0; i < currents.size(); ++i)
378 BEAST_EXPECT(currents[i].name == labels[i / 2]);
379 BEAST_EXPECT(prevDur > currents[i].dur);
380 prevDur = currents[i].dur;
387 for (
int labelIndex = labels.
size() - 1; labelIndex > 0; --labelIndex)
390 perfLog->rpcFinish(labels[labelIndex], ids[(labelIndex * 2) + 1]);
392 perfLog->rpcError(labels[labelIndex], ids[(labelIndex * 2) + 0]);
394 perfLog->rpcFinish(labels[0], ids[0 + 1]);
397 auto validateFinalCounters = [
this, &labels](
400 Json::Value const& jobQueue = countersJson[jss::job_queue];
402 BEAST_EXPECT(jobQueue.
size() == 0);
406 BEAST_EXPECT(rpc.
size() == labels.
size() + 1);
414 BEAST_EXPECT(first[jss::duration_us] !=
"0");
415 BEAST_EXPECT(first[jss::errored] ==
"0");
416 BEAST_EXPECT(first[jss::finished] ==
"1");
417 BEAST_EXPECT(first[jss::started] ==
"2");
422 for (
int i = 1; i < labels.
size(); ++i)
427 BEAST_EXPECT(dur != 0 && dur < prevDur);
429 BEAST_EXPECT(counter[jss::errored] ==
"1");
430 BEAST_EXPECT(counter[jss::finished] ==
"1");
431 BEAST_EXPECT(counter[jss::started] ==
"2");
436 BEAST_EXPECT(total[jss::duration_us] !=
"0");
444 auto validateFinalCurrent = [
this,
447 Json::Value const& job_queue = currentJson[jss::jobs];
448 BEAST_EXPECT(job_queue.
isArray());
449 BEAST_EXPECT(job_queue.
size() == 0);
452 Json::Value const& methods = currentJson[jss::methods];
453 BEAST_EXPECT(methods.
size() == 1);
454 BEAST_EXPECT(methods.
isArray());
457 BEAST_EXPECT(only.
size() == 2);
459 BEAST_EXPECT(only[jss::duration_us] !=
"0");
460 BEAST_EXPECT(only[jss::method] == labels[0]);
464 validateFinalCounters(
perfLog->countersJson());
465 validateFinalCurrent(
perfLog->currentJson());
473 auto const fullPath = fixture.logFile();
477 BEAST_EXPECT(!exists(fullPath));
491 lastLine = std::move(line);
501 validateFinalCounters(parsedLastLine[jss::counters]);
502 validateFinalCurrent(parsedLastLine[jss::current_activities]);
514 auto perfLog{fixture.perfLog(withFile)};
525 : type(t), typeName(std::move(name))
534 for (
auto const& job : jobTypes)
543 for (
int i = 0; i < jobs.
size(); ++i)
545 perfLog->jobQueue(jobs[i].type);
547 perfLog->countersJson()[jss::job_queue]};
549 BEAST_EXPECT(jq_counters.size() == i + 2);
550 for (
int j = 0; j <= i; ++j)
554 Json::Value const& counter{jq_counters[jobs[j].typeName]};
555 BEAST_EXPECT(counter.size() == 5);
556 BEAST_EXPECT(counter[jss::queued] ==
"1");
557 BEAST_EXPECT(counter[jss::started] ==
"0");
558 BEAST_EXPECT(counter[jss::finished] ==
"0");
559 BEAST_EXPECT(counter[jss::queued_duration_us] ==
"0");
560 BEAST_EXPECT(counter[jss::running_duration_us] ==
"0");
565 BEAST_EXPECT(total.size() == 5);
566 BEAST_EXPECT(
jsonToUint64(total[jss::queued]) == i + 1);
567 BEAST_EXPECT(total[jss::started] ==
"0");
568 BEAST_EXPECT(total[jss::finished] ==
"0");
569 BEAST_EXPECT(total[jss::queued_duration_us] ==
"0");
570 BEAST_EXPECT(total[jss::running_duration_us] ==
"0");
576 BEAST_EXPECT(
current.size() == 2);
577 BEAST_EXPECT(
current.isMember(jss::jobs));
578 BEAST_EXPECT(
current[jss::jobs].size() == 0);
579 BEAST_EXPECT(
current.isMember(jss::methods));
580 BEAST_EXPECT(
current[jss::methods].size() == 0);
592 for (
int i = 0; i < jobs.
size(); ++i)
595 jobs[i].type,
microseconds{i + 1}, steady_clock::now(), i * 2);
600 perfLog->countersJson()[jss::job_queue]};
601 for (
int j = 0; j < jobs.
size(); ++j)
603 Json::Value const& counter{jq_counters[jobs[j].typeName]};
608 BEAST_EXPECT(counter[jss::started] ==
"2");
609 BEAST_EXPECT(queued_dur_us == j + 1);
613 BEAST_EXPECT(counter[jss::started] ==
"1");
614 BEAST_EXPECT(queued_dur_us == j + 1);
618 BEAST_EXPECT(counter[jss::started] ==
"0");
619 BEAST_EXPECT(queued_dur_us == 0);
622 BEAST_EXPECT(counter[jss::queued] ==
"1");
623 BEAST_EXPECT(counter[jss::finished] ==
"0");
624 BEAST_EXPECT(counter[jss::running_duration_us] ==
"0");
630 BEAST_EXPECT(
jsonToUint64(total[jss::started]) == (i * 2) + 1);
631 BEAST_EXPECT(total[jss::finished] ==
"0");
636 (((i * i) + 3 * i + 2) / 2));
637 BEAST_EXPECT(total[jss::running_duration_us] ==
"0");
652 BEAST_EXPECT(currents.size() == (i + 1) * 2);
655 for (
int j = 0; j <= i; ++j)
657 BEAST_EXPECT(currents[j * 2].name == jobs[j].typeName);
658 BEAST_EXPECT(prevDur > currents[j * 2].dur);
659 prevDur = currents[j * 2].dur;
661 BEAST_EXPECT(currents[(j * 2) + 1].name == jobs[j].typeName);
662 BEAST_EXPECT(prevDur > currents[(j * 2) + 1].dur);
663 prevDur = currents[(j * 2) + 1].dur;
668 for (
int i = jobs.
size() - 1; i >= 0; --i)
672 int const finished = ((jobs.
size() - i) * 2) - 1;
678 perfLog->countersJson()[jss::job_queue]};
679 for (
int j = 0; j < jobs.
size(); ++j)
681 Json::Value const& counter{jq_counters[jobs[j].typeName]};
686 BEAST_EXPECT(counter[jss::finished] ==
"0");
687 BEAST_EXPECT(running_dur_us == 0);
691 BEAST_EXPECT(counter[jss::finished] ==
"1");
692 BEAST_EXPECT(running_dur_us == ((jobs.
size() - j) * 2) - 1);
696 BEAST_EXPECT(counter[jss::finished] ==
"2");
697 BEAST_EXPECT(running_dur_us == ((jobs.
size() - j) * 4) - 1);
702 BEAST_EXPECT(queued_dur_us == j + 1);
703 BEAST_EXPECT(counter[jss::queued] ==
"1");
704 BEAST_EXPECT(counter[jss::started] ==
"2");
712 BEAST_EXPECT(
jsonToUint64(total[jss::finished]) == finished);
716 int const queuedDur = ((jobs.
size() * (jobs.
size() + 1)) / 2);
718 jsonToUint64(total[jss::queued_duration_us]) == queuedDur);
721 int const runningDur = ((finished * (finished + 1)) / 2);
735 BEAST_EXPECT(currents.size() == i * 2);
738 for (
int j = 0; j < i; ++j)
740 BEAST_EXPECT(currents[j * 2].name == jobs[j].typeName);
741 BEAST_EXPECT(prevDur > currents[j * 2].dur);
742 prevDur = currents[j * 2].dur;
744 BEAST_EXPECT(currents[(j * 2) + 1].name == jobs[j].typeName);
745 BEAST_EXPECT(prevDur > currents[(j * 2) + 1].dur);
746 prevDur = currents[(j * 2) + 1].dur;
751 auto validateFinalCounters = [
this,
756 BEAST_EXPECT(rpc.
size() == 0);
759 Json::Value const& jobQueue = countersJson[jss::job_queue];
760 for (
int i = jobs.
size() - 1; i >= 0; --i)
762 Json::Value const& counter{jobQueue[jobs[i].typeName]};
765 BEAST_EXPECT(running_dur_us == ((jobs.
size() - i) * 4) - 1);
769 BEAST_EXPECT(queued_dur_us == i + 1);
771 BEAST_EXPECT(counter[jss::queued] ==
"1");
772 BEAST_EXPECT(counter[jss::started] ==
"2");
773 BEAST_EXPECT(counter[jss::finished] ==
"2");
778 const int finished = jobs.
size() * 2;
780 BEAST_EXPECT(
jsonToUint64(total[jss::started]) == finished);
781 BEAST_EXPECT(
jsonToUint64(total[jss::finished]) == finished);
785 int const queuedDur = ((jobs.
size() * (jobs.
size() + 1)) / 2);
787 jsonToUint64(total[jss::queued_duration_us]) == queuedDur);
790 int const runningDur = ((finished * (finished + 1)) / 2);
792 jsonToUint64(total[jss::running_duration_us]) == runningDur);
795 auto validateFinalCurrent = [
this](
Json::Value const& currentJson) {
799 BEAST_EXPECT(j.
size() == 0);
802 Json::Value const& methods = currentJson[jss::methods];
803 BEAST_EXPECT(methods.
size() == 0);
804 BEAST_EXPECT(methods.
isArray());
808 validateFinalCounters(
perfLog->countersJson());
809 validateFinalCurrent(
perfLog->currentJson());
818 auto const fullPath = fixture.logFile();
822 BEAST_EXPECT(!exists(fullPath));
836 lastLine = std::move(line);
846 validateFinalCounters(parsedLastLine[jss::counters]);
847 validateFinalCurrent(parsedLastLine[jss::current_activities]);
861 auto perfLog{fixture.perfLog(withFile)};
871 auto iter{jobTypes.begin()};
874 jobType = iter->second.type();
875 jobTypeName = iter->second.name();
882 auto verifyCounters = [
this, jobTypeName](
888 BEAST_EXPECT(countersJson.
isObject());
889 BEAST_EXPECT(countersJson.
size() == 2);
891 BEAST_EXPECT(countersJson.
isMember(jss::rpc));
892 BEAST_EXPECT(countersJson[jss::rpc].isObject());
893 BEAST_EXPECT(countersJson[jss::rpc].size() == 0);
895 BEAST_EXPECT(countersJson.
isMember(jss::job_queue));
896 BEAST_EXPECT(countersJson[jss::job_queue].isObject());
897 BEAST_EXPECT(countersJson[jss::job_queue].size() == 1);
900 countersJson[jss::job_queue][jobTypeName]};
902 BEAST_EXPECT(job.isObject());
904 BEAST_EXPECT(
jsonToUint64(job[jss::started]) == started);
905 BEAST_EXPECT(
jsonToUint64(job[jss::finished]) == finished);
908 jsonToUint64(job[jss::queued_duration_us]) == queued_us);
910 jsonToUint64(job[jss::running_duration_us]) == running_us);
915 auto verifyEmptyCurrent = [
this](
Json::Value const& currentJson) {
916 BEAST_EXPECT(currentJson.isObject());
917 BEAST_EXPECT(currentJson.size() == 2);
919 BEAST_EXPECT(currentJson.isMember(jss::jobs));
920 BEAST_EXPECT(currentJson[jss::jobs].isArray());
921 BEAST_EXPECT(currentJson[jss::jobs].size() == 0);
923 BEAST_EXPECT(currentJson.isMember(jss::methods));
924 BEAST_EXPECT(currentJson[jss::methods].isArray());
925 BEAST_EXPECT(currentJson[jss::methods].size() == 0);
931 verifyCounters(
perfLog->countersJson(), 1, 0, 11, 0);
932 verifyEmptyCurrent(
perfLog->currentJson());
937 verifyCounters(
perfLog->countersJson(), 2, 0, 24, 0);
938 verifyEmptyCurrent(
perfLog->currentJson());
943 verifyCounters(
perfLog->countersJson(), 2, 1, 24, 17);
944 verifyEmptyCurrent(
perfLog->currentJson());
949 verifyCounters(
perfLog->countersJson(), 2, 2, 24, 36);
950 verifyEmptyCurrent(
perfLog->currentJson());
959 auto const fullPath = fixture.logFile();
963 BEAST_EXPECT(!exists(fullPath));
977 lastLine = std::move(line);
987 verifyCounters(parsedLastLine[jss::counters], 2, 2, 24, 36);
988 verifyEmptyCurrent(parsedLastLine[jss::current_activities]);
998 using namespace boost::filesystem;
1001 BEAST_EXPECT(!exists(fixture.logDir()));
1003 auto perfLog{fixture.perfLog(withFile)};
1005 BEAST_EXPECT(fixture.stopSignaled ==
false);
1008 BEAST_EXPECT(!exists(fixture.logDir()));
1012 BEAST_EXPECT(exists(fixture.logFile()));
1013 BEAST_EXPECT(file_size(fixture.logFile()) == 0);
1021 decltype(file_size(fixture.logFile())) firstFileSize{0};
1024 BEAST_EXPECT(!exists(fixture.logDir()));
1028 firstFileSize = file_size(fixture.logFile());
1029 BEAST_EXPECT(firstFileSize > 0);
1040 BEAST_EXPECT(!exists(fixture.logDir()));
1044 BEAST_EXPECT(file_size(fixture.logFile()) > firstFileSize);