diff options
author | tarum <tarum@yandex-team.com> | 2023-04-14 15:47:28 +0300 |
---|---|---|
committer | tarum <tarum@yandex-team.com> | 2023-04-14 15:47:28 +0300 |
commit | f186fba2006170397fc55829216039b6e86808cb (patch) | |
tree | c6aa843a9cf298e9aabb99740b5fed8e5077d64e | |
parent | fb642d882910bcf70b25fa17c3de522e61b4ac84 (diff) | |
download | ydb-f186fba2006170397fc55829216039b6e86808cb.tar.gz |
Add pagination to archive, polish table look
-rw-r--r-- | ydb/core/load_test/aggregated_result.cpp | 22 | ||||
-rw-r--r-- | ydb/core/load_test/aggregated_result.h | 34 | ||||
-rw-r--r-- | ydb/core/load_test/archive.cpp | 4 | ||||
-rw-r--r-- | ydb/core/load_test/archive.h | 2 | ||||
-rw-r--r-- | ydb/core/load_test/service_actor.cpp | 73 |
5 files changed, 113 insertions, 22 deletions
diff --git a/ydb/core/load_test/aggregated_result.cpp b/ydb/core/load_test/aggregated_result.cpp index 3809f630dc1..92b5064afe4 100644 --- a/ydb/core/load_test/aggregated_result.cpp +++ b/ydb/core/load_test/aggregated_result.cpp @@ -13,7 +13,7 @@ IOutputStream& operator<<(IOutputStream& output, const TAggregatedStats& stats) output << "transactions_per_sec: [" << stats.TransactionsPerSecond << "], "; output << "errors_per_sec: [" << stats.ErrorsPerSecond << "], "; for (ui32 level : xrange(stats.Percentiles.size())) { - output << "percentile" << ToString(static_cast<EPercentileLevel>(level)) << ": [" << stats.Percentiles[level] << "], "; + output << "percentile" << ToString(static_cast<EPercentileLevel>(level)) << ": [" << stats.Percentiles[level] << "], "; } output << "}"; return output; @@ -46,9 +46,25 @@ TAggregatedStats TStatsAggregator::Get() const { return result; } +TString PrintShortDate(const TInstant& instant) { + // Output format: Apr 13 + return instant.FormatGmTime("%b %d"); +} + +TString PrintShortTime(const TInstant& instant) { + // Output format: 16:45:03 + return instant.FormatGmTime("%H:%M:%S"); +} + +void PrintStartFinishToHtml(const TInstant& start, const TInstant& finish, IOutputStream& output) { + output << "<span title=\"" << start.ToStringUpToSeconds() << " / " << finish.ToStringUpToSeconds() << + "\">" << PrintShortDate(start) << " " << + PrintShortTime(start) << " / " << PrintShortTime(finish) << "</span>"; +} + void PrintUuidToHtml(const TString& uuid, IOutputStream& output) { auto dashPos = uuid.find('-'); - output << "<abbr title=\"" << uuid << "\">" << uuid.substr(0, dashPos) << "</abbr>"; + output << "<span title=\"" << uuid << "\">" << uuid.substr(0, dashPos) << "..</span>"; } IOutputStream& operator<<(IOutputStream& output, const TAggregatedResult& result) { @@ -82,7 +98,7 @@ NKikimrMiniKQL::TValue GetOptional(const NKikimrMiniKQL::TValue& listItem, ui32 template<typename T> T ExtractValue(const NKikimrMiniKQL::TValue& listItem, ui32 pos) { Y_UNUSED(listItem, pos); - Y_FAIL("unimplemented"); + Y_FAIL("unimplemented"); } template<> diff --git a/ydb/core/load_test/aggregated_result.h b/ydb/core/load_test/aggregated_result.h index 75c295e0bd8..45095b7edfa 100644 --- a/ydb/core/load_test/aggregated_result.h +++ b/ydb/core/load_test/aggregated_result.h @@ -8,6 +8,8 @@ #include <util/datetime/base.h> #include <util/generic/string.h> #include <util/stream/output.h> +#include <util/string/cast.h> +#include <util/string/printf.h> #include <util/system/types.h> #include <array> @@ -18,7 +20,7 @@ template<typename T> struct TAggregatedField { T MinValue; T MaxValue; - T AvgValue; + double AvgValue; }; template<typename T> @@ -28,10 +30,28 @@ IOutputStream& operator<<(IOutputStream& output, const TAggregatedField<T>& fiel } template<typename T> +TString PrintValueFixedPrecision(const T& x) { + return ToString(x); +} + +template<> +inline TString PrintValueFixedPrecision(const double& x) { + if (fabs(x) < 0.01) { + return Sprintf("%.4lf", x); + } else if (fabs(x) < 0.1) { + return Sprintf("%.3lf", x); + } else { + return Sprintf("%.2lf", x); + } +} + +template<typename T> void PrintFieldToHtml(const TAggregatedField<T>& field, IOutputStream& output) { - output << "<abbr title=\""; - output << field.MinValue << " ≤ " << field.AvgValue << " ≤ " << field.MaxValue; - output << "\">" << field.AvgValue << "</abbr>"; + output << "<span title=\""; + output << PrintValueFixedPrecision(field.MinValue) << + " ≤ " << PrintValueFixedPrecision(field.AvgValue) << + " ≤ " << PrintValueFixedPrecision(field.MaxValue); + output << "\">" << PrintValueFixedPrecision(field.AvgValue) << "</span>"; } struct TAggregatedStats { @@ -49,7 +69,7 @@ template<typename T> class TFieldAggregator { T MinValue = 0; T MaxValue = 0; - T Sum = 0; + double Sum = 0; ui32 Count = 0; public: void Add(T value) { @@ -65,7 +85,7 @@ public: } TAggregatedField<T> Get() const { - T avgValue = Count == 0 ? 0 : (Sum / Count); + double avgValue = Count == 0 ? 0 : (Sum / Count); return TAggregatedField<T>{ .MinValue = MinValue, .MaxValue = MaxValue, @@ -92,6 +112,8 @@ public: TAggregatedStats Get() const; }; +void PrintStartFinishToHtml(const TInstant& start, const TInstant& finish, IOutputStream& output); + struct TAggregatedResult { TString Uuid; TInstant Start; diff --git a/ydb/core/load_test/archive.cpp b/ydb/core/load_test/archive.cpp index a7bf0ab0504..62617f8ff25 100644 --- a/ydb/core/load_test/archive.cpp +++ b/ydb/core/load_test/archive.cpp @@ -117,12 +117,12 @@ TString MakeRecordInsertionYql(const TVector<TAggregatedResult>& items) { return ss.Str(); } -TString MakeRecordSelectionYql(int limit) { +TString MakeRecordSelectionYql(ui32 offset, ui32 limit) { TStringStream ss; ss << "--!syntax_v1\n"; ss << "SELECT * FROM `" << kResultTablePath << "` "; ss << "ORDER BY `start` DESC "; - ss << "LIMIT " << limit; + ss << "LIMIT " << limit << " OFFSET " << offset << ";"; return ss.Str(); } diff --git a/ydb/core/load_test/archive.h b/ydb/core/load_test/archive.h index 629d202bd1f..3089e729c4d 100644 --- a/ydb/core/load_test/archive.h +++ b/ydb/core/load_test/archive.h @@ -10,6 +10,6 @@ static constexpr TStringBuf kRecordsSelectedResult = "Records selected"; TString MakeTableCreationYql(); TString MakeRecordInsertionYql(const TVector<TAggregatedResult>& items); -TString MakeRecordSelectionYql(int limit); +TString MakeRecordSelectionYql(ui32 offset, ui32 limit); } // namespace NKikimr diff --git a/ydb/core/load_test/service_actor.cpp b/ydb/core/load_test/service_actor.cpp index 824317aa3d9..a7fe093c00b 100644 --- a/ydb/core/load_test/service_actor.cpp +++ b/ydb/core/load_test/service_actor.cpp @@ -22,6 +22,7 @@ #include <util/generic/algorithm.h> #include <util/generic/guid.h> +#include <util/string/type.h> namespace NKikimr { @@ -57,6 +58,19 @@ bool IsJsonContentType(const TString& acceptFormat) { return acceptFormat == "application/json"; } +ui32 GetCgiParamNumber(const TCgiParameters& params, const TStringBuf name, ui32 minValue, ui32 maxValue, ui32 defaultValue) { + if (params.Has(name)) { + auto param = params.Get(name); + if (IsNumber(param)) { + i64 value = FromString(param); + if (minValue <= value && value <= maxValue) { + return static_cast<ui32>(value); + } + } + } + return defaultValue; +} + bool IsLegacyRequest(const TEvLoadTestRequest& request) { return !request.HasTag() || !request.HasUuid() || !request.HasTimestamp(); } @@ -164,6 +178,8 @@ class TLoadActor : public TActorBootstrapped<TLoadActor> { ui32 HttpInfoResPending; // number of requests pending TString Mode; // mode of page content TString AcceptFormat; + ui32 Offset = 0; + ui32 Limit = 0; }; struct TNodeFinishedTestInfo { @@ -349,8 +365,8 @@ private: LOG_N("Created actor for table creation " << TableCreationActor.ToString()); } - void StartReadingResultsFromTable() { - const TString query = MakeRecordSelectionYql(10); + void StartReadingResultsFromTable(ui32 offset, ui32 limit) { + const TString query = MakeRecordSelectionYql(offset, limit); LOG_D("YQL query to select records: " << query); auto recordSelectionActor = TlsActivationContext->Register( CreateYqlSingleQueryActor( @@ -767,7 +783,11 @@ public: GenerateHttpInfoRes(mode, id); } } else if (mode == "archive") { - StartReadingResultsFromTable(); + ui32 offset = GetCgiParamNumber(params, "offset", 0, Max<ui32>(), 0); + ui32 limit = GetCgiParamNumber(params, "limit", 1, 100, 10); + info.Offset = offset; + info.Limit = limit; + StartReadingResultsFromTable(offset, limit); } else { GenerateHttpInfoRes(mode, id); } @@ -1120,13 +1140,23 @@ public: TABLEHEAD() { TABLER() { TABLEH() { str << "UUID"; } - TABLEH() { str << "Start / finish"; } - TABLEH() { str << "Success / total nodes"; } - TABLEH() { str << "Transactions"; } - TABLEH() { str << "Transactions per second"; } - TABLEH() { str << "Errors per second"; } + TABLEH() { str << "Time"; } + TABLEH() { + str << "<span title=\"Success nodes / total nodes\">Ok / nodes</span>"; + } + TABLEH() { str << "Txs"; } + TABLEH() { str << "Txs/Sec"; } + TABLEH() { str << "Errors/Sec"; } for (ui32 level : xrange(EPL_COUNT_NUM)) { - TABLEH() { str << "percentile " << ToString(static_cast<EPercentileLevel>(level)); } + TABLEH() { + str << "p"; + if (level == EPL_100) { + str << "Max"; + } else { + str << ToString(static_cast<EPercentileLevel>(level)); + } + str << "(ms)"; + } } TABLEH() { str << "Config"; } } @@ -1139,7 +1169,7 @@ public: PrintUuidToHtml(result.Uuid, str); } TABLED() { - str << result.Start.ToStringUpToSeconds() << " / " << result.Finish.ToStringUpToSeconds(); + PrintStartFinishToHtml(result.Start, result.Finish, str); } const TAggregatedStats& stats = result.Stats; TABLED() { @@ -1169,6 +1199,29 @@ public: } } } + str << "<div>\n"; + { + str << "<span>"; + if (info.Offset) { + ui32 prevOffset = info.Offset - Min(info.Limit, info.Offset); + str << "<a href='?mode=archive&offset=" << prevOffset << "&limit=" << info.Limit << "' "; + + } else { + str << "<a href='#' disabled "; + } + str << "class='btn btn-default'>< prev</a></span>\n"; + } + { + str << "<span>"; + if (ArchivedResults.size() >= info.Limit) { + ui32 nextOffset = info.Offset + info.Limit; + str << "<a href='?mode=archive&offset=" << nextOffset << "&limit=" << info.Limit << "' "; + } else { + str << "<a href='#' disabled "; + } + str << "class='btn btn-default'>next ></a></span>\n"; + } + str << "</div>\n"; } } str << "</div>"; |