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>
32 #include <test/jtx/Env.h>
43 using path = boost::filesystem::path;
62 using namespace boost::filesystem;
69 if (!exists(dir) || !is_directory(dir) || !is_empty(dir))
85 using namespace boost::filesystem;
86 return temp_directory_path() /
"perf_log_test_dir";
92 return logDir() /
"perf_log.txt";
116 using namespace boost::filesystem;
129 secondSize = file_size(
path);
130 }
while (firstSize >= secondSize);
135 }
while (secondSize >= file_size(
path));
171 cur.isMember(jss::job) ? cur[jss::job].asString()
172 : cur[jss::method].asString());
180 [](
Cur const& lhs,
Cur const& rhs) {
181 if (lhs.dur != rhs.dur)
182 return (rhs.dur < lhs.dur);
183 return (lhs.name < rhs.name);
192 using namespace boost::filesystem;
197 BEAST_EXPECT(!exists(fixture.logFile()));
201 BEAST_EXPECT(fixture.stopSignaled ==
false);
202 BEAST_EXPECT(exists(fixture.logFile()));
209 if (!BEAST_EXPECT(!exists(fixture.logDir())))
216 fixture.logDir().c_str(), std::ios::out | std::ios::app);
217 if (!BEAST_EXPECT(nastyFile))
224 BEAST_EXPECT(fixture.stopSignaled ==
false);
226 BEAST_EXPECT(fixture.stopSignaled ==
true);
236 remove(fixture.logDir());
243 if (!BEAST_EXPECT(!exists(fixture.logDir())))
248 boost::system::error_code ec;
249 boost::filesystem::create_directories(fixture.logDir(), ec);
250 if (!BEAST_EXPECT(!ec))
253 auto fileWriteable = [](boost::filesystem::path
const& p) ->
bool {
254 return std::ofstream{p.c_str(), std::ios::out | std::ios::app}
258 if (!BEAST_EXPECT(fileWriteable(fixture.logFile())))
261 boost::filesystem::permissions(
263 perms::remove_perms | perms::owner_write | perms::others_write |
268 if (fileWriteable(fixture.logFile()))
270 log <<
"Unable to write protect file. Test skipped."
277 BEAST_EXPECT(fixture.stopSignaled ==
false);
279 BEAST_EXPECT(fixture.stopSignaled ==
true);
289 boost::filesystem::permissions(
291 perms::add_perms | perms::owner_write | perms::others_write |
302 auto perfLog{fixture.perfLog(withFile)};
314 ids.
reserve(labels.size() * 2);
331 for (
int labelIndex = 0; labelIndex < labels.size(); ++labelIndex)
333 for (
int idIndex = 0; idIndex < 2; ++idIndex)
337 labels[labelIndex], ids[(labelIndex * 2) + idIndex]);
343 BEAST_EXPECT(countersJson.size() == labels.size() + 1);
344 for (
auto& label : labels)
348 BEAST_EXPECT(counter[jss::duration_us] ==
"0");
349 BEAST_EXPECT(counter[jss::errored] ==
"0");
350 BEAST_EXPECT(counter[jss::finished] ==
"0");
351 BEAST_EXPECT(counter[jss::started] ==
"2");
354 Json::Value const& total{countersJson[jss::total]};
355 BEAST_EXPECT(total[jss::duration_us] ==
"0");
356 BEAST_EXPECT(total[jss::errored] ==
"0");
357 BEAST_EXPECT(total[jss::finished] ==
"0");
366 BEAST_EXPECT(currents.size() == labels.size() * 2);
369 for (
int i = 0; i < currents.size(); ++i)
371 BEAST_EXPECT(currents[i].name == labels[i / 2]);
372 BEAST_EXPECT(prevDur > currents[i].dur);
373 prevDur = currents[i].dur;
380 for (
int labelIndex = labels.size() - 1; labelIndex > 0; --labelIndex)
383 perfLog->rpcFinish(labels[labelIndex], ids[(labelIndex * 2) + 1]);
385 perfLog->rpcError(labels[labelIndex], ids[(labelIndex * 2) + 0]);
387 perfLog->rpcFinish(labels[0], ids[0 + 1]);
390 auto validateFinalCounters = [
this, &labels](
393 Json::Value const& jobQueue = countersJson[jss::job_queue];
395 BEAST_EXPECT(jobQueue.
size() == 0);
399 BEAST_EXPECT(rpc.
size() == labels.size() + 1);
407 BEAST_EXPECT(first[jss::duration_us] !=
"0");
408 BEAST_EXPECT(first[jss::errored] ==
"0");
409 BEAST_EXPECT(first[jss::finished] ==
"1");
410 BEAST_EXPECT(first[jss::started] ==
"2");
415 for (
int i = 1; i < labels.size(); ++i)
420 BEAST_EXPECT(dur != 0 && dur < prevDur);
422 BEAST_EXPECT(counter[jss::errored] ==
"1");
423 BEAST_EXPECT(counter[jss::finished] ==
"1");
424 BEAST_EXPECT(counter[jss::started] ==
"2");
429 BEAST_EXPECT(total[jss::duration_us] !=
"0");
431 jsonToUint64(total[jss::errored]) == labels.size() - 1);
432 BEAST_EXPECT(
jsonToUint64(total[jss::finished]) == labels.size());
434 jsonToUint64(total[jss::started]) == labels.size() * 2);
437 auto validateFinalCurrent = [
this,
440 Json::Value const& job_queue = currentJson[jss::jobs];
441 BEAST_EXPECT(job_queue.
isArray());
442 BEAST_EXPECT(job_queue.
size() == 0);
445 Json::Value const& methods = currentJson[jss::methods];
446 BEAST_EXPECT(methods.
size() == 1);
447 BEAST_EXPECT(methods.
isArray());
450 BEAST_EXPECT(only.
size() == 2);
452 BEAST_EXPECT(only[jss::duration_us] !=
"0");
453 BEAST_EXPECT(only[jss::method] == labels[0]);
457 validateFinalCounters(
perfLog->countersJson());
458 validateFinalCurrent(
perfLog->currentJson());
466 auto const fullPath = fixture.logFile();
470 BEAST_EXPECT(!exists(fullPath));
484 lastLine = std::move(line);
494 validateFinalCounters(parsedLastLine[jss::counters]);
495 validateFinalCurrent(parsedLastLine[jss::current_activities]);
507 auto perfLog{fixture.perfLog(withFile)};
518 : type(t), typeName(std::move(name))
527 for (
auto const& job : jobTypes)
536 for (
int i = 0; i < jobs.
size(); ++i)
538 perfLog->jobQueue(jobs[i].type);
540 perfLog->countersJson()[jss::job_queue]};
542 BEAST_EXPECT(jq_counters.size() == i + 2);
543 for (
int j = 0; j <= i; ++j)
547 Json::Value const& counter{jq_counters[jobs[j].typeName]};
548 BEAST_EXPECT(counter.size() == 5);
549 BEAST_EXPECT(counter[jss::queued] ==
"1");
550 BEAST_EXPECT(counter[jss::started] ==
"0");
551 BEAST_EXPECT(counter[jss::finished] ==
"0");
552 BEAST_EXPECT(counter[jss::queued_duration_us] ==
"0");
553 BEAST_EXPECT(counter[jss::running_duration_us] ==
"0");
558 BEAST_EXPECT(total.size() == 5);
559 BEAST_EXPECT(
jsonToUint64(total[jss::queued]) == i + 1);
560 BEAST_EXPECT(total[jss::started] ==
"0");
561 BEAST_EXPECT(total[jss::finished] ==
"0");
562 BEAST_EXPECT(total[jss::queued_duration_us] ==
"0");
563 BEAST_EXPECT(total[jss::running_duration_us] ==
"0");
569 BEAST_EXPECT(
current.size() == 2);
570 BEAST_EXPECT(
current.isMember(jss::jobs));
571 BEAST_EXPECT(
current[jss::jobs].size() == 0);
572 BEAST_EXPECT(
current.isMember(jss::methods));
573 BEAST_EXPECT(
current[jss::methods].size() == 0);
585 for (
int i = 0; i < jobs.
size(); ++i)
588 jobs[i].type,
microseconds{i + 1}, steady_clock::now(), i * 2);
593 perfLog->countersJson()[jss::job_queue]};
594 for (
int j = 0; j < jobs.
size(); ++j)
596 Json::Value const& counter{jq_counters[jobs[j].typeName]};
601 BEAST_EXPECT(counter[jss::started] ==
"2");
602 BEAST_EXPECT(queued_dur_us == j + 1);
606 BEAST_EXPECT(counter[jss::started] ==
"1");
607 BEAST_EXPECT(queued_dur_us == j + 1);
611 BEAST_EXPECT(counter[jss::started] ==
"0");
612 BEAST_EXPECT(queued_dur_us == 0);
615 BEAST_EXPECT(counter[jss::queued] ==
"1");
616 BEAST_EXPECT(counter[jss::finished] ==
"0");
617 BEAST_EXPECT(counter[jss::running_duration_us] ==
"0");
623 BEAST_EXPECT(
jsonToUint64(total[jss::started]) == (i * 2) + 1);
624 BEAST_EXPECT(total[jss::finished] ==
"0");
629 (((i * i) + 3 * i + 2) / 2));
630 BEAST_EXPECT(total[jss::running_duration_us] ==
"0");
645 BEAST_EXPECT(currents.size() == (i + 1) * 2);
648 for (
int j = 0; j <= i; ++j)
650 BEAST_EXPECT(currents[j * 2].name == jobs[j].typeName);
651 BEAST_EXPECT(prevDur > currents[j * 2].dur);
652 prevDur = currents[j * 2].dur;
654 BEAST_EXPECT(currents[(j * 2) + 1].name == jobs[j].typeName);
655 BEAST_EXPECT(prevDur > currents[(j * 2) + 1].dur);
656 prevDur = currents[(j * 2) + 1].dur;
661 for (
int i = jobs.
size() - 1; i >= 0; --i)
665 int const finished = ((jobs.
size() - i) * 2) - 1;
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::finished] ==
"0");
680 BEAST_EXPECT(running_dur_us == 0);
684 BEAST_EXPECT(counter[jss::finished] ==
"1");
685 BEAST_EXPECT(running_dur_us == ((jobs.
size() - j) * 2) - 1);
689 BEAST_EXPECT(counter[jss::finished] ==
"2");
690 BEAST_EXPECT(running_dur_us == ((jobs.
size() - j) * 4) - 1);
695 BEAST_EXPECT(queued_dur_us == j + 1);
696 BEAST_EXPECT(counter[jss::queued] ==
"1");
697 BEAST_EXPECT(counter[jss::started] ==
"2");
705 BEAST_EXPECT(
jsonToUint64(total[jss::finished]) == finished);
709 int const queuedDur = ((jobs.
size() * (jobs.
size() + 1)) / 2);
711 jsonToUint64(total[jss::queued_duration_us]) == queuedDur);
714 int const runningDur = ((finished * (finished + 1)) / 2);
728 BEAST_EXPECT(currents.size() == i * 2);
731 for (
int j = 0; j < i; ++j)
733 BEAST_EXPECT(currents[j * 2].name == jobs[j].typeName);
734 BEAST_EXPECT(prevDur > currents[j * 2].dur);
735 prevDur = currents[j * 2].dur;
737 BEAST_EXPECT(currents[(j * 2) + 1].name == jobs[j].typeName);
738 BEAST_EXPECT(prevDur > currents[(j * 2) + 1].dur);
739 prevDur = currents[(j * 2) + 1].dur;
744 auto validateFinalCounters = [
this,
749 BEAST_EXPECT(rpc.
size() == 0);
752 Json::Value const& jobQueue = countersJson[jss::job_queue];
753 for (
int i = jobs.
size() - 1; i >= 0; --i)
755 Json::Value const& counter{jobQueue[jobs[i].typeName]};
758 BEAST_EXPECT(running_dur_us == ((jobs.
size() - i) * 4) - 1);
762 BEAST_EXPECT(queued_dur_us == i + 1);
764 BEAST_EXPECT(counter[jss::queued] ==
"1");
765 BEAST_EXPECT(counter[jss::started] ==
"2");
766 BEAST_EXPECT(counter[jss::finished] ==
"2");
771 const int finished = jobs.
size() * 2;
773 BEAST_EXPECT(
jsonToUint64(total[jss::started]) == finished);
774 BEAST_EXPECT(
jsonToUint64(total[jss::finished]) == finished);
778 int const queuedDur = ((jobs.
size() * (jobs.
size() + 1)) / 2);
780 jsonToUint64(total[jss::queued_duration_us]) == queuedDur);
783 int const runningDur = ((finished * (finished + 1)) / 2);
785 jsonToUint64(total[jss::running_duration_us]) == runningDur);
788 auto validateFinalCurrent = [
this](
Json::Value const& currentJson) {
792 BEAST_EXPECT(j.
size() == 0);
795 Json::Value const& methods = currentJson[jss::methods];
796 BEAST_EXPECT(methods.
size() == 0);
797 BEAST_EXPECT(methods.
isArray());
801 validateFinalCounters(
perfLog->countersJson());
802 validateFinalCurrent(
perfLog->currentJson());
811 auto const fullPath = fixture.logFile();
815 BEAST_EXPECT(!exists(fullPath));
829 lastLine = std::move(line);
839 validateFinalCounters(parsedLastLine[jss::counters]);
840 validateFinalCurrent(parsedLastLine[jss::current_activities]);
854 auto perfLog{fixture.perfLog(withFile)};
864 auto iter{jobTypes.begin()};
867 jobType = iter->second.type();
868 jobTypeName = iter->second.name();
875 auto verifyCounters = [
this, jobTypeName](
881 BEAST_EXPECT(countersJson.
isObject());
882 BEAST_EXPECT(countersJson.
size() == 2);
884 BEAST_EXPECT(countersJson.
isMember(jss::rpc));
885 BEAST_EXPECT(countersJson[jss::rpc].isObject());
886 BEAST_EXPECT(countersJson[jss::rpc].size() == 0);
888 BEAST_EXPECT(countersJson.
isMember(jss::job_queue));
889 BEAST_EXPECT(countersJson[jss::job_queue].isObject());
890 BEAST_EXPECT(countersJson[jss::job_queue].size() == 1);
893 countersJson[jss::job_queue][jobTypeName]};
895 BEAST_EXPECT(job.isObject());
897 BEAST_EXPECT(
jsonToUint64(job[jss::started]) == started);
898 BEAST_EXPECT(
jsonToUint64(job[jss::finished]) == finished);
901 jsonToUint64(job[jss::queued_duration_us]) == queued_us);
903 jsonToUint64(job[jss::running_duration_us]) == running_us);
908 auto verifyEmptyCurrent = [
this](
Json::Value const& currentJson) {
909 BEAST_EXPECT(currentJson.isObject());
910 BEAST_EXPECT(currentJson.size() == 2);
912 BEAST_EXPECT(currentJson.isMember(jss::jobs));
913 BEAST_EXPECT(currentJson[jss::jobs].isArray());
914 BEAST_EXPECT(currentJson[jss::jobs].size() == 0);
916 BEAST_EXPECT(currentJson.isMember(jss::methods));
917 BEAST_EXPECT(currentJson[jss::methods].isArray());
918 BEAST_EXPECT(currentJson[jss::methods].size() == 0);
924 verifyCounters(
perfLog->countersJson(), 1, 0, 11, 0);
925 verifyEmptyCurrent(
perfLog->currentJson());
930 verifyCounters(
perfLog->countersJson(), 2, 0, 24, 0);
931 verifyEmptyCurrent(
perfLog->currentJson());
936 verifyCounters(
perfLog->countersJson(), 2, 1, 24, 17);
937 verifyEmptyCurrent(
perfLog->currentJson());
942 verifyCounters(
perfLog->countersJson(), 2, 2, 24, 36);
943 verifyEmptyCurrent(
perfLog->currentJson());
952 auto const fullPath = fixture.logFile();
956 BEAST_EXPECT(!exists(fullPath));
970 lastLine = std::move(line);
980 verifyCounters(parsedLastLine[jss::counters], 2, 2, 24, 36);
981 verifyEmptyCurrent(parsedLastLine[jss::current_activities]);
991 using namespace boost::filesystem;
994 BEAST_EXPECT(!exists(fixture.logDir()));
996 auto perfLog{fixture.perfLog(withFile)};
998 BEAST_EXPECT(fixture.stopSignaled ==
false);
1001 BEAST_EXPECT(!exists(fixture.logDir()));
1005 BEAST_EXPECT(exists(fixture.logFile()));
1006 BEAST_EXPECT(file_size(fixture.logFile()) == 0);
1014 decltype(file_size(fixture.logFile())) firstFileSize{0};
1017 BEAST_EXPECT(!exists(fixture.logDir()));
1021 firstFileSize = file_size(fixture.logFile());
1022 BEAST_EXPECT(firstFileSize > 0);
1033 BEAST_EXPECT(!exists(fixture.logDir()));
1037 BEAST_EXPECT(file_size(fixture.logFile()) > firstFileSize);