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>
44 using path = boost::filesystem::path;
67 using namespace boost::filesystem;
74 if (!exists(dir) || !is_directory(dir) || !is_empty(dir))
90 using namespace boost::filesystem;
91 return temp_directory_path() /
"perf_log_test_dir";
97 return logDir() /
"perf_log.txt";
121 using namespace boost::filesystem;
134 secondSize = file_size(
path);
135 }
while (firstSize >= secondSize);
140 }
while (secondSize >= file_size(
path));
176 cur.isMember(jss::job) ? cur[jss::job].asString()
177 : cur[jss::method].asString());
185 [](
Cur const& lhs,
Cur const& rhs) {
186 if (lhs.dur != rhs.dur)
187 return (rhs.dur < lhs.dur);
188 return (lhs.name < rhs.name);
197 using namespace boost::filesystem;
202 BEAST_EXPECT(!exists(fixture.logFile()));
206 BEAST_EXPECT(fixture.stopSignaled ==
false);
207 BEAST_EXPECT(exists(fixture.logFile()));
214 if (!BEAST_EXPECT(!exists(fixture.logDir())))
221 fixture.logDir().c_str(), std::ios::out | std::ios::app);
222 if (!BEAST_EXPECT(nastyFile))
229 BEAST_EXPECT(fixture.stopSignaled ==
false);
231 BEAST_EXPECT(fixture.stopSignaled ==
true);
241 remove(fixture.logDir());
248 if (!BEAST_EXPECT(!exists(fixture.logDir())))
253 boost::system::error_code ec;
254 boost::filesystem::create_directories(fixture.logDir(), ec);
255 if (!BEAST_EXPECT(!ec))
258 auto fileWriteable = [](boost::filesystem::path
const& p) ->
bool {
259 return std::ofstream{p.c_str(), std::ios::out | std::ios::app}
263 if (!BEAST_EXPECT(fileWriteable(fixture.logFile())))
266 boost::filesystem::permissions(
268 perms::remove_perms | perms::owner_write | perms::others_write |
273 if (fileWriteable(fixture.logFile()))
275 log <<
"Unable to write protect file. Test skipped."
282 BEAST_EXPECT(fixture.stopSignaled ==
false);
284 BEAST_EXPECT(fixture.stopSignaled ==
true);
294 boost::filesystem::permissions(
296 perms::add_perms | perms::owner_write | perms::others_write |
307 auto perfLog{fixture.perfLog(withFile)};
319 ids.
reserve(labels.size() * 2);
336 for (
int labelIndex = 0; labelIndex < labels.size(); ++labelIndex)
338 for (
int idIndex = 0; idIndex < 2; ++idIndex)
342 labels[labelIndex], ids[(labelIndex * 2) + idIndex]);
348 BEAST_EXPECT(countersJson.size() == labels.size() + 1);
349 for (
auto& label : labels)
353 BEAST_EXPECT(counter[jss::duration_us] ==
"0");
354 BEAST_EXPECT(counter[jss::errored] ==
"0");
355 BEAST_EXPECT(counter[jss::finished] ==
"0");
356 BEAST_EXPECT(counter[jss::started] ==
"2");
359 Json::Value const& total{countersJson[jss::total]};
360 BEAST_EXPECT(total[jss::duration_us] ==
"0");
361 BEAST_EXPECT(total[jss::errored] ==
"0");
362 BEAST_EXPECT(total[jss::finished] ==
"0");
371 BEAST_EXPECT(currents.size() == labels.size() * 2);
374 for (
int i = 0; i < currents.size(); ++i)
376 BEAST_EXPECT(currents[i].name == labels[i / 2]);
377 BEAST_EXPECT(prevDur > currents[i].dur);
378 prevDur = currents[i].dur;
385 for (
int labelIndex = labels.size() - 1; labelIndex > 0; --labelIndex)
388 perfLog->rpcFinish(labels[labelIndex], ids[(labelIndex * 2) + 1]);
390 perfLog->rpcError(labels[labelIndex], ids[(labelIndex * 2) + 0]);
392 perfLog->rpcFinish(labels[0], ids[0 + 1]);
395 auto validateFinalCounters = [
this, &labels](
398 Json::Value const& jobQueue = countersJson[jss::job_queue];
400 BEAST_EXPECT(jobQueue.
size() == 0);
404 BEAST_EXPECT(rpc.
size() == labels.size() + 1);
412 BEAST_EXPECT(first[jss::duration_us] !=
"0");
413 BEAST_EXPECT(first[jss::errored] ==
"0");
414 BEAST_EXPECT(first[jss::finished] ==
"1");
415 BEAST_EXPECT(first[jss::started] ==
"2");
420 for (
int i = 1; i < labels.size(); ++i)
425 BEAST_EXPECT(dur != 0 && dur < prevDur);
427 BEAST_EXPECT(counter[jss::errored] ==
"1");
428 BEAST_EXPECT(counter[jss::finished] ==
"1");
429 BEAST_EXPECT(counter[jss::started] ==
"2");
434 BEAST_EXPECT(total[jss::duration_us] !=
"0");
436 jsonToUint64(total[jss::errored]) == labels.size() - 1);
437 BEAST_EXPECT(
jsonToUint64(total[jss::finished]) == labels.size());
439 jsonToUint64(total[jss::started]) == labels.size() * 2);
442 auto validateFinalCurrent = [
this,
445 Json::Value const& job_queue = currentJson[jss::jobs];
446 BEAST_EXPECT(job_queue.
isArray());
447 BEAST_EXPECT(job_queue.
size() == 0);
450 Json::Value const& methods = currentJson[jss::methods];
451 BEAST_EXPECT(methods.
size() == 1);
452 BEAST_EXPECT(methods.
isArray());
455 BEAST_EXPECT(only.
size() == 2);
457 BEAST_EXPECT(only[jss::duration_us] !=
"0");
458 BEAST_EXPECT(only[jss::method] == labels[0]);
462 validateFinalCounters(
perfLog->countersJson());
463 validateFinalCurrent(
perfLog->currentJson());
471 auto const fullPath = fixture.logFile();
475 BEAST_EXPECT(!exists(fullPath));
489 lastLine = std::move(line);
499 validateFinalCounters(parsedLastLine[jss::counters]);
500 validateFinalCurrent(parsedLastLine[jss::current_activities]);
512 auto perfLog{fixture.perfLog(withFile)};
523 : type(t), typeName(std::move(name))
532 for (
auto const& job : jobTypes)
541 for (
int i = 0; i < jobs.
size(); ++i)
543 perfLog->jobQueue(jobs[i].type);
545 perfLog->countersJson()[jss::job_queue]};
547 BEAST_EXPECT(jq_counters.size() == i + 2);
548 for (
int j = 0; j <= i; ++j)
552 Json::Value const& counter{jq_counters[jobs[j].typeName]};
553 BEAST_EXPECT(counter.size() == 5);
554 BEAST_EXPECT(counter[jss::queued] ==
"1");
555 BEAST_EXPECT(counter[jss::started] ==
"0");
556 BEAST_EXPECT(counter[jss::finished] ==
"0");
557 BEAST_EXPECT(counter[jss::queued_duration_us] ==
"0");
558 BEAST_EXPECT(counter[jss::running_duration_us] ==
"0");
563 BEAST_EXPECT(total.size() == 5);
564 BEAST_EXPECT(
jsonToUint64(total[jss::queued]) == i + 1);
565 BEAST_EXPECT(total[jss::started] ==
"0");
566 BEAST_EXPECT(total[jss::finished] ==
"0");
567 BEAST_EXPECT(total[jss::queued_duration_us] ==
"0");
568 BEAST_EXPECT(total[jss::running_duration_us] ==
"0");
574 BEAST_EXPECT(
current.size() == 2);
575 BEAST_EXPECT(
current.isMember(jss::jobs));
576 BEAST_EXPECT(
current[jss::jobs].size() == 0);
577 BEAST_EXPECT(
current.isMember(jss::methods));
578 BEAST_EXPECT(
current[jss::methods].size() == 0);
590 for (
int i = 0; i < jobs.
size(); ++i)
593 jobs[i].type,
microseconds{i + 1}, steady_clock::now(), i * 2);
598 perfLog->countersJson()[jss::job_queue]};
599 for (
int j = 0; j < jobs.
size(); ++j)
601 Json::Value const& counter{jq_counters[jobs[j].typeName]};
606 BEAST_EXPECT(counter[jss::started] ==
"2");
607 BEAST_EXPECT(queued_dur_us == j + 1);
611 BEAST_EXPECT(counter[jss::started] ==
"1");
612 BEAST_EXPECT(queued_dur_us == j + 1);
616 BEAST_EXPECT(counter[jss::started] ==
"0");
617 BEAST_EXPECT(queued_dur_us == 0);
620 BEAST_EXPECT(counter[jss::queued] ==
"1");
621 BEAST_EXPECT(counter[jss::finished] ==
"0");
622 BEAST_EXPECT(counter[jss::running_duration_us] ==
"0");
628 BEAST_EXPECT(
jsonToUint64(total[jss::started]) == (i * 2) + 1);
629 BEAST_EXPECT(total[jss::finished] ==
"0");
634 (((i * i) + 3 * i + 2) / 2));
635 BEAST_EXPECT(total[jss::running_duration_us] ==
"0");
650 BEAST_EXPECT(currents.size() == (i + 1) * 2);
653 for (
int j = 0; j <= i; ++j)
655 BEAST_EXPECT(currents[j * 2].name == jobs[j].typeName);
656 BEAST_EXPECT(prevDur > currents[j * 2].dur);
657 prevDur = currents[j * 2].dur;
659 BEAST_EXPECT(currents[(j * 2) + 1].name == jobs[j].typeName);
660 BEAST_EXPECT(prevDur > currents[(j * 2) + 1].dur);
661 prevDur = currents[(j * 2) + 1].dur;
666 for (
int i = jobs.
size() - 1; i >= 0; --i)
670 int const finished = ((jobs.
size() - i) * 2) - 1;
676 perfLog->countersJson()[jss::job_queue]};
677 for (
int j = 0; j < jobs.
size(); ++j)
679 Json::Value const& counter{jq_counters[jobs[j].typeName]};
684 BEAST_EXPECT(counter[jss::finished] ==
"0");
685 BEAST_EXPECT(running_dur_us == 0);
689 BEAST_EXPECT(counter[jss::finished] ==
"1");
690 BEAST_EXPECT(running_dur_us == ((jobs.
size() - j) * 2) - 1);
694 BEAST_EXPECT(counter[jss::finished] ==
"2");
695 BEAST_EXPECT(running_dur_us == ((jobs.
size() - j) * 4) - 1);
700 BEAST_EXPECT(queued_dur_us == j + 1);
701 BEAST_EXPECT(counter[jss::queued] ==
"1");
702 BEAST_EXPECT(counter[jss::started] ==
"2");
710 BEAST_EXPECT(
jsonToUint64(total[jss::finished]) == finished);
714 int const queuedDur = ((jobs.
size() * (jobs.
size() + 1)) / 2);
716 jsonToUint64(total[jss::queued_duration_us]) == queuedDur);
719 int const runningDur = ((finished * (finished + 1)) / 2);
733 BEAST_EXPECT(currents.size() == i * 2);
736 for (
int j = 0; j < i; ++j)
738 BEAST_EXPECT(currents[j * 2].name == jobs[j].typeName);
739 BEAST_EXPECT(prevDur > currents[j * 2].dur);
740 prevDur = currents[j * 2].dur;
742 BEAST_EXPECT(currents[(j * 2) + 1].name == jobs[j].typeName);
743 BEAST_EXPECT(prevDur > currents[(j * 2) + 1].dur);
744 prevDur = currents[(j * 2) + 1].dur;
749 auto validateFinalCounters = [
this,
754 BEAST_EXPECT(rpc.
size() == 0);
757 Json::Value const& jobQueue = countersJson[jss::job_queue];
758 for (
int i = jobs.
size() - 1; i >= 0; --i)
760 Json::Value const& counter{jobQueue[jobs[i].typeName]};
763 BEAST_EXPECT(running_dur_us == ((jobs.
size() - i) * 4) - 1);
767 BEAST_EXPECT(queued_dur_us == i + 1);
769 BEAST_EXPECT(counter[jss::queued] ==
"1");
770 BEAST_EXPECT(counter[jss::started] ==
"2");
771 BEAST_EXPECT(counter[jss::finished] ==
"2");
776 const int finished = jobs.
size() * 2;
778 BEAST_EXPECT(
jsonToUint64(total[jss::started]) == finished);
779 BEAST_EXPECT(
jsonToUint64(total[jss::finished]) == finished);
783 int const queuedDur = ((jobs.
size() * (jobs.
size() + 1)) / 2);
785 jsonToUint64(total[jss::queued_duration_us]) == queuedDur);
788 int const runningDur = ((finished * (finished + 1)) / 2);
790 jsonToUint64(total[jss::running_duration_us]) == runningDur);
793 auto validateFinalCurrent = [
this](
Json::Value const& currentJson) {
797 BEAST_EXPECT(j.
size() == 0);
800 Json::Value const& methods = currentJson[jss::methods];
801 BEAST_EXPECT(methods.
size() == 0);
802 BEAST_EXPECT(methods.
isArray());
806 validateFinalCounters(
perfLog->countersJson());
807 validateFinalCurrent(
perfLog->currentJson());
816 auto const fullPath = fixture.logFile();
820 BEAST_EXPECT(!exists(fullPath));
834 lastLine = std::move(line);
844 validateFinalCounters(parsedLastLine[jss::counters]);
845 validateFinalCurrent(parsedLastLine[jss::current_activities]);
859 auto perfLog{fixture.perfLog(withFile)};
869 auto iter{jobTypes.begin()};
872 jobType = iter->second.type();
873 jobTypeName = iter->second.name();
880 auto verifyCounters = [
this, jobTypeName](
886 BEAST_EXPECT(countersJson.
isObject());
887 BEAST_EXPECT(countersJson.
size() == 2);
889 BEAST_EXPECT(countersJson.
isMember(jss::rpc));
890 BEAST_EXPECT(countersJson[jss::rpc].isObject());
891 BEAST_EXPECT(countersJson[jss::rpc].size() == 0);
893 BEAST_EXPECT(countersJson.
isMember(jss::job_queue));
894 BEAST_EXPECT(countersJson[jss::job_queue].isObject());
895 BEAST_EXPECT(countersJson[jss::job_queue].size() == 1);
898 countersJson[jss::job_queue][jobTypeName]};
900 BEAST_EXPECT(job.isObject());
902 BEAST_EXPECT(
jsonToUint64(job[jss::started]) == started);
903 BEAST_EXPECT(
jsonToUint64(job[jss::finished]) == finished);
906 jsonToUint64(job[jss::queued_duration_us]) == queued_us);
908 jsonToUint64(job[jss::running_duration_us]) == running_us);
913 auto verifyEmptyCurrent = [
this](
Json::Value const& currentJson) {
914 BEAST_EXPECT(currentJson.isObject());
915 BEAST_EXPECT(currentJson.size() == 2);
917 BEAST_EXPECT(currentJson.isMember(jss::jobs));
918 BEAST_EXPECT(currentJson[jss::jobs].isArray());
919 BEAST_EXPECT(currentJson[jss::jobs].size() == 0);
921 BEAST_EXPECT(currentJson.isMember(jss::methods));
922 BEAST_EXPECT(currentJson[jss::methods].isArray());
923 BEAST_EXPECT(currentJson[jss::methods].size() == 0);
929 verifyCounters(
perfLog->countersJson(), 1, 0, 11, 0);
930 verifyEmptyCurrent(
perfLog->currentJson());
935 verifyCounters(
perfLog->countersJson(), 2, 0, 24, 0);
936 verifyEmptyCurrent(
perfLog->currentJson());
941 verifyCounters(
perfLog->countersJson(), 2, 1, 24, 17);
942 verifyEmptyCurrent(
perfLog->currentJson());
947 verifyCounters(
perfLog->countersJson(), 2, 2, 24, 36);
948 verifyEmptyCurrent(
perfLog->currentJson());
957 auto const fullPath = fixture.logFile();
961 BEAST_EXPECT(!exists(fullPath));
975 lastLine = std::move(line);
985 verifyCounters(parsedLastLine[jss::counters], 2, 2, 24, 36);
986 verifyEmptyCurrent(parsedLastLine[jss::current_activities]);
996 using namespace boost::filesystem;
999 BEAST_EXPECT(!exists(fixture.logDir()));
1001 auto perfLog{fixture.perfLog(withFile)};
1003 BEAST_EXPECT(fixture.stopSignaled ==
false);
1006 BEAST_EXPECT(!exists(fixture.logDir()));
1010 BEAST_EXPECT(exists(fixture.logFile()));
1011 BEAST_EXPECT(file_size(fixture.logFile()) == 0);
1019 decltype(file_size(fixture.logFile())) firstFileSize{0};
1022 BEAST_EXPECT(!exists(fixture.logDir()));
1026 firstFileSize = file_size(fixture.logFile());
1027 BEAST_EXPECT(firstFileSize > 0);
1038 BEAST_EXPECT(!exists(fixture.logDir()));
1042 BEAST_EXPECT(file_size(fixture.logFile()) > firstFileSize);