mirror of
https://github.com/dragonflydb/dragonfly.git
synced 2025-05-11 10:25:47 +02:00
feat: introduce 'debug iostats' command (#5051)
The command shows verious io stats per thread Signed-off-by: Roman Gershman <roman@dragonflydb.io>
This commit is contained in:
parent
5a901b9bc7
commit
f09df995a6
3 changed files with 86 additions and 11 deletions
|
@ -484,6 +484,55 @@ const char* EncodingName(unsigned obj_type, unsigned encoding) {
|
||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct IOStat {
|
||||||
|
uint64_t conn_received = 0;
|
||||||
|
uint64_t curr_conn_count = 0;
|
||||||
|
uint64_t cmd_total = 0, pipelined_cmd_total = 0;
|
||||||
|
size_t io_read_bytes = 0;
|
||||||
|
uint64_t io_reads_total = 0;
|
||||||
|
|
||||||
|
void From(const facade::FacadeStats& fs);
|
||||||
|
void Print(RedisReplyBuilder* rb) const;
|
||||||
|
|
||||||
|
IOStat& operator-=(const IOStat& other);
|
||||||
|
};
|
||||||
|
|
||||||
|
void IOStat::From(const facade::FacadeStats& fs) {
|
||||||
|
conn_received = fs.conn_stats.conn_received_cnt;
|
||||||
|
curr_conn_count = fs.conn_stats.num_conns_main;
|
||||||
|
cmd_total = fs.conn_stats.command_cnt_main;
|
||||||
|
pipelined_cmd_total = fs.conn_stats.pipelined_cmd_cnt;
|
||||||
|
io_read_bytes = fs.conn_stats.io_read_bytes;
|
||||||
|
io_reads_total = fs.conn_stats.io_read_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IOStat::Print(RedisReplyBuilder* rb) const {
|
||||||
|
rb->StartCollection(6, RedisReplyBuilder::CollectionType::MAP);
|
||||||
|
rb->SendSimpleString("connections_received");
|
||||||
|
rb->SendLong(conn_received);
|
||||||
|
rb->SendSimpleString("current_conn_count");
|
||||||
|
rb->SendLong(curr_conn_count);
|
||||||
|
rb->SendSimpleString("commands_total");
|
||||||
|
rb->SendLong(cmd_total);
|
||||||
|
rb->SendSimpleString("pipelined_commands_total");
|
||||||
|
rb->SendLong(pipelined_cmd_total);
|
||||||
|
rb->SendSimpleString("io_read_bytes");
|
||||||
|
rb->SendLong(io_read_bytes);
|
||||||
|
rb->SendSimpleString("io_reads_total");
|
||||||
|
rb->SendLong(io_reads_total);
|
||||||
|
}
|
||||||
|
|
||||||
|
IOStat& IOStat::operator-=(const IOStat& other) {
|
||||||
|
conn_received -= other.conn_received;
|
||||||
|
curr_conn_count -= other.curr_conn_count;
|
||||||
|
cmd_total -= other.cmd_total;
|
||||||
|
pipelined_cmd_total -= other.pipelined_cmd_total;
|
||||||
|
io_read_bytes -= other.io_read_bytes;
|
||||||
|
io_reads_total -= other.io_reads_total;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
DebugCmd::DebugCmd(ServerFamily* owner, cluster::ClusterFamily* cf, ConnectionContext* cntx)
|
DebugCmd::DebugCmd(ServerFamily* owner, cluster::ClusterFamily* cf, ConnectionContext* cntx)
|
||||||
|
@ -550,6 +599,9 @@ void DebugCmd::Run(CmdArgList args, facade::SinkReplyBuilder* builder) {
|
||||||
"COMPRESSION [type]"
|
"COMPRESSION [type]"
|
||||||
" Estimate the compressibility of values of the given type. if no type is given, ",
|
" Estimate the compressibility of values of the given type. if no type is given, ",
|
||||||
" checks compressibility of keys",
|
" checks compressibility of keys",
|
||||||
|
"IOSTATS [PS]",
|
||||||
|
" Prints IO stats per thread. If PS is specified, prints thread-level stats ",
|
||||||
|
" per second.",
|
||||||
"HELP",
|
"HELP",
|
||||||
" Prints this help.",
|
" Prints this help.",
|
||||||
};
|
};
|
||||||
|
@ -625,6 +677,9 @@ void DebugCmd::Run(CmdArgList args, facade::SinkReplyBuilder* builder) {
|
||||||
return Compression(args.subspan(1), builder);
|
return Compression(args.subspan(1), builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (subcmd == "IOSTATS") {
|
||||||
|
return IOStats(args.subspan(1), builder);
|
||||||
|
}
|
||||||
string reply = UnknownSubCmd(subcmd, "DEBUG");
|
string reply = UnknownSubCmd(subcmd, "DEBUG");
|
||||||
return builder->SendError(reply, kSyntaxErrType);
|
return builder->SendError(reply, kSyntaxErrType);
|
||||||
}
|
}
|
||||||
|
@ -1276,6 +1331,33 @@ void DebugCmd::Compression(CmdArgList args, facade::SinkReplyBuilder* builder) {
|
||||||
rb->SendDouble(ratio);
|
rb->SendDouble(ratio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DebugCmd::IOStats(CmdArgList args, facade::SinkReplyBuilder* builder) {
|
||||||
|
auto* rb = static_cast<RedisReplyBuilder*>(builder);
|
||||||
|
|
||||||
|
bool per_second = args.size() > 0 && absl::EqualsIgnoreCase(args[0], "PS");
|
||||||
|
vector<IOStat> stats(shard_set->pool()->size());
|
||||||
|
|
||||||
|
shard_set->pool()->AwaitBrief(
|
||||||
|
[&](unsigned index, ProactorBase*) { stats[index].From(*facade::tl_facade_stats); });
|
||||||
|
|
||||||
|
if (per_second) {
|
||||||
|
ThisFiber::SleepFor(1s);
|
||||||
|
vector<IOStat> stats2(shard_set->pool()->size());
|
||||||
|
shard_set->pool()->AwaitBrief(
|
||||||
|
[&](unsigned index, ProactorBase*) { stats2[index].From(*facade::tl_facade_stats); });
|
||||||
|
|
||||||
|
for (size_t i = 0; i < stats.size(); ++i) {
|
||||||
|
stats2[i] -= stats[i];
|
||||||
|
}
|
||||||
|
stats = std::move(stats2);
|
||||||
|
}
|
||||||
|
|
||||||
|
rb->StartArray(stats.size());
|
||||||
|
for (const auto& stat : stats) {
|
||||||
|
stat.Print(rb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DebugCmd::DoPopulateBatch(const PopulateOptions& options, const PopulateBatch& batch) {
|
void DebugCmd::DoPopulateBatch(const PopulateOptions& options, const PopulateBatch& batch) {
|
||||||
boost::intrusive_ptr<Transaction> local_tx =
|
boost::intrusive_ptr<Transaction> local_tx =
|
||||||
new Transaction{sf_.service().mutable_registry()->Find("EXEC")};
|
new Transaction{sf_.service().mutable_registry()->Find("EXEC")};
|
||||||
|
|
|
@ -59,13 +59,13 @@ class DebugCmd {
|
||||||
void Topk(CmdArgList args, facade::SinkReplyBuilder* builder);
|
void Topk(CmdArgList args, facade::SinkReplyBuilder* builder);
|
||||||
void Keys(CmdArgList args, facade::SinkReplyBuilder* builder);
|
void Keys(CmdArgList args, facade::SinkReplyBuilder* builder);
|
||||||
void Compression(CmdArgList args, facade::SinkReplyBuilder* builder);
|
void Compression(CmdArgList args, facade::SinkReplyBuilder* builder);
|
||||||
|
void IOStats(CmdArgList args, facade::SinkReplyBuilder* builder);
|
||||||
struct PopulateBatch {
|
struct PopulateBatch {
|
||||||
DbIndex dbid;
|
DbIndex dbid;
|
||||||
uint64_t index[32];
|
uint64_t index[32];
|
||||||
uint64_t sz = 0;
|
uint64_t sz = 0;
|
||||||
|
|
||||||
PopulateBatch(DbIndex id) : dbid(id) {
|
explicit PopulateBatch(DbIndex id) : dbid(id) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -475,15 +475,8 @@ TEST_F(DflyEngineTest, Bug207) {
|
||||||
ASSERT_EQ(resp, "OK");
|
ASSERT_EQ(resp, "OK");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto evicted_count = [](const string& str) -> size_t {
|
auto metrics = GetMetrics();
|
||||||
const string matcher = "evicted_keys:";
|
EXPECT_GT(metrics.events.evicted_keys, 0) << FormatMetrics(metrics);
|
||||||
const auto pos = str.find(matcher) + matcher.size();
|
|
||||||
const auto sub = str.substr(pos, 1);
|
|
||||||
return atoi(sub.c_str());
|
|
||||||
};
|
|
||||||
|
|
||||||
resp = Run({"info", "stats"});
|
|
||||||
EXPECT_GT(evicted_count(resp.GetString()), 0);
|
|
||||||
|
|
||||||
for (; i > 0; --i) {
|
for (; i > 0; --i) {
|
||||||
resp = Run({"setex", StrCat("key", i), "30", "bar"});
|
resp = Run({"setex", StrCat("key", i), "30", "bar"});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue