aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortarum <tarum@yandex-team.com>2023-04-14 15:47:28 +0300
committertarum <tarum@yandex-team.com>2023-04-14 15:47:28 +0300
commitf186fba2006170397fc55829216039b6e86808cb (patch)
treec6aa843a9cf298e9aabb99740b5fed8e5077d64e
parentfb642d882910bcf70b25fa17c3de522e61b4ac84 (diff)
downloadydb-f186fba2006170397fc55829216039b6e86808cb.tar.gz
Add pagination to archive, polish table look
-rw-r--r--ydb/core/load_test/aggregated_result.cpp22
-rw-r--r--ydb/core/load_test/aggregated_result.h34
-rw-r--r--ydb/core/load_test/archive.cpp4
-rw-r--r--ydb/core/load_test/archive.h2
-rw-r--r--ydb/core/load_test/service_actor.cpp73
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 << " &le; " << field.AvgValue << " &le; " << field.MaxValue;
- output << "\">" << field.AvgValue << "</abbr>";
+ output << "<span title=\"";
+ output << PrintValueFixedPrecision(field.MinValue) <<
+ " &le; " << PrintValueFixedPrecision(field.AvgValue) <<
+ " &le; " << 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'>&lt; 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 &gt;</a></span>\n";
+ }
+ str << "</div>\n";
}
}
str << "</div>";