Skip to content

Commit f09df99

Browse files
authored
feat: introduce 'debug iostats' command (#5051)
The command shows verious io stats per thread Signed-off-by: Roman Gershman <[email protected]>
1 parent 5a901b9 commit f09df99

File tree

3 files changed

+86
-11
lines changed

3 files changed

+86
-11
lines changed

src/server/debugcmd.cc

+82
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,55 @@ const char* EncodingName(unsigned obj_type, unsigned encoding) {
484484
return "unknown";
485485
}
486486

487+
struct IOStat {
488+
uint64_t conn_received = 0;
489+
uint64_t curr_conn_count = 0;
490+
uint64_t cmd_total = 0, pipelined_cmd_total = 0;
491+
size_t io_read_bytes = 0;
492+
uint64_t io_reads_total = 0;
493+
494+
void From(const facade::FacadeStats& fs);
495+
void Print(RedisReplyBuilder* rb) const;
496+
497+
IOStat& operator-=(const IOStat& other);
498+
};
499+
500+
void IOStat::From(const facade::FacadeStats& fs) {
501+
conn_received = fs.conn_stats.conn_received_cnt;
502+
curr_conn_count = fs.conn_stats.num_conns_main;
503+
cmd_total = fs.conn_stats.command_cnt_main;
504+
pipelined_cmd_total = fs.conn_stats.pipelined_cmd_cnt;
505+
io_read_bytes = fs.conn_stats.io_read_bytes;
506+
io_reads_total = fs.conn_stats.io_read_cnt;
507+
}
508+
509+
void IOStat::Print(RedisReplyBuilder* rb) const {
510+
rb->StartCollection(6, RedisReplyBuilder::CollectionType::MAP);
511+
rb->SendSimpleString("connections_received");
512+
rb->SendLong(conn_received);
513+
rb->SendSimpleString("current_conn_count");
514+
rb->SendLong(curr_conn_count);
515+
rb->SendSimpleString("commands_total");
516+
rb->SendLong(cmd_total);
517+
rb->SendSimpleString("pipelined_commands_total");
518+
rb->SendLong(pipelined_cmd_total);
519+
rb->SendSimpleString("io_read_bytes");
520+
rb->SendLong(io_read_bytes);
521+
rb->SendSimpleString("io_reads_total");
522+
rb->SendLong(io_reads_total);
523+
}
524+
525+
IOStat& IOStat::operator-=(const IOStat& other) {
526+
conn_received -= other.conn_received;
527+
curr_conn_count -= other.curr_conn_count;
528+
cmd_total -= other.cmd_total;
529+
pipelined_cmd_total -= other.pipelined_cmd_total;
530+
io_read_bytes -= other.io_read_bytes;
531+
io_reads_total -= other.io_reads_total;
532+
533+
return *this;
534+
}
535+
487536
} // namespace
488537

489538
DebugCmd::DebugCmd(ServerFamily* owner, cluster::ClusterFamily* cf, ConnectionContext* cntx)
@@ -550,6 +599,9 @@ void DebugCmd::Run(CmdArgList args, facade::SinkReplyBuilder* builder) {
550599
"COMPRESSION [type]"
551600
" Estimate the compressibility of values of the given type. if no type is given, ",
552601
" checks compressibility of keys",
602+
"IOSTATS [PS]",
603+
" Prints IO stats per thread. If PS is specified, prints thread-level stats ",
604+
" per second.",
553605
"HELP",
554606
" Prints this help.",
555607
};
@@ -625,6 +677,9 @@ void DebugCmd::Run(CmdArgList args, facade::SinkReplyBuilder* builder) {
625677
return Compression(args.subspan(1), builder);
626678
}
627679

680+
if (subcmd == "IOSTATS") {
681+
return IOStats(args.subspan(1), builder);
682+
}
628683
string reply = UnknownSubCmd(subcmd, "DEBUG");
629684
return builder->SendError(reply, kSyntaxErrType);
630685
}
@@ -1276,6 +1331,33 @@ void DebugCmd::Compression(CmdArgList args, facade::SinkReplyBuilder* builder) {
12761331
rb->SendDouble(ratio);
12771332
}
12781333

1334+
void DebugCmd::IOStats(CmdArgList args, facade::SinkReplyBuilder* builder) {
1335+
auto* rb = static_cast<RedisReplyBuilder*>(builder);
1336+
1337+
bool per_second = args.size() > 0 && absl::EqualsIgnoreCase(args[0], "PS");
1338+
vector<IOStat> stats(shard_set->pool()->size());
1339+
1340+
shard_set->pool()->AwaitBrief(
1341+
[&](unsigned index, ProactorBase*) { stats[index].From(*facade::tl_facade_stats); });
1342+
1343+
if (per_second) {
1344+
ThisFiber::SleepFor(1s);
1345+
vector<IOStat> stats2(shard_set->pool()->size());
1346+
shard_set->pool()->AwaitBrief(
1347+
[&](unsigned index, ProactorBase*) { stats2[index].From(*facade::tl_facade_stats); });
1348+
1349+
for (size_t i = 0; i < stats.size(); ++i) {
1350+
stats2[i] -= stats[i];
1351+
}
1352+
stats = std::move(stats2);
1353+
}
1354+
1355+
rb->StartArray(stats.size());
1356+
for (const auto& stat : stats) {
1357+
stat.Print(rb);
1358+
}
1359+
}
1360+
12791361
void DebugCmd::DoPopulateBatch(const PopulateOptions& options, const PopulateBatch& batch) {
12801362
boost::intrusive_ptr<Transaction> local_tx =
12811363
new Transaction{sf_.service().mutable_registry()->Find("EXEC")};

src/server/debugcmd.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,13 @@ class DebugCmd {
5959
void Topk(CmdArgList args, facade::SinkReplyBuilder* builder);
6060
void Keys(CmdArgList args, facade::SinkReplyBuilder* builder);
6161
void Compression(CmdArgList args, facade::SinkReplyBuilder* builder);
62-
62+
void IOStats(CmdArgList args, facade::SinkReplyBuilder* builder);
6363
struct PopulateBatch {
6464
DbIndex dbid;
6565
uint64_t index[32];
6666
uint64_t sz = 0;
6767

68-
PopulateBatch(DbIndex id) : dbid(id) {
68+
explicit PopulateBatch(DbIndex id) : dbid(id) {
6969
}
7070
};
7171

src/server/dragonfly_test.cc

+2-9
Original file line numberDiff line numberDiff line change
@@ -475,15 +475,8 @@ TEST_F(DflyEngineTest, Bug207) {
475475
ASSERT_EQ(resp, "OK");
476476
}
477477

478-
auto evicted_count = [](const string& str) -> size_t {
479-
const string matcher = "evicted_keys:";
480-
const auto pos = str.find(matcher) + matcher.size();
481-
const auto sub = str.substr(pos, 1);
482-
return atoi(sub.c_str());
483-
};
484-
485-
resp = Run({"info", "stats"});
486-
EXPECT_GT(evicted_count(resp.GetString()), 0);
478+
auto metrics = GetMetrics();
479+
EXPECT_GT(metrics.events.evicted_keys, 0) << FormatMetrics(metrics);
487480

488481
for (; i > 0; --i) {
489482
resp = Run({"setex", StrCat("key", i), "30", "bar"});

0 commit comments

Comments
 (0)