ircd::fs::dev: Add stats gather struct w/ console cmd.

This commit is contained in:
Jason Volk 2023-03-16 11:44:42 -07:00
parent f85781b65a
commit 43838608fd
3 changed files with 208 additions and 0 deletions

View File

@ -14,6 +14,7 @@
namespace ircd::fs::dev
{
struct blk;
struct stats;
using major_minor = std::pair<ulong, ulong>;
@ -69,6 +70,44 @@ struct ircd::fs::dev::blk
static bool for_each(const closure &);
};
struct ircd::fs::dev::stats
{
using closure = util::function_bool<const stats &>;
char name[32] {0};
major_minor id {0, 0};
uint64_t read {0};
uint64_t read_merged {0};
uint64_t read_sectors {0};
milliseconds read_time {0ms};
uint64_t write {0};
uint64_t write_merged {0};
uint64_t write_sectors {0};
milliseconds write_time {0ms};
uint64_t io_current {0};
milliseconds io_time {0ms};
milliseconds io_weighted_time {0ms};
// 4.18+
uint64_t discard {0};
uint64_t discard_merged {0};
uint64_t discard_sectors {0};
milliseconds discard_time {0ms};
// 5.5+
uint64_t flush {0};
milliseconds flush_time {0ms};
stats(const string_view &line);
stats() = default;
static bool for_each(const closure &);
static stats get(const major_minor &id);
};
/// Return a lex_cast'able (an integer) from a sysfs target.
template<class T,
size_t bufmax>

View File

@ -231,3 +231,100 @@ ircd::fs::dev::blk::devtype(const mutable_buffer &buf,
return ret;
}
//
// dev::stats
//
ircd::fs::dev::stats
ircd::fs::dev::stats::get(const major_minor &id)
{
stats ret;
for_each([&id, &ret]
(const auto &stats)
{
if(stats.id == id)
{
ret = stats;
return false;
}
else return true;
});
return ret;
}
bool
ircd::fs::dev::stats::for_each(const closure &closure)
{
thread_local char buf[16_KiB];
const fs::fd fd
{
"/proc/diskstats", fs::fd::opts
{
.mode = std::ios::in,
},
};
fs::read_opts opts;
opts.aio = false;
const string_view read
{
fs::read(fd, buf, opts)
};
return tokens(read, '\n', [&closure]
(const auto &line)
{
return closure(stats(line));
});
}
//
// dev::stats::stats
//
ircd::fs::dev::stats::stats(const string_view &line)
{
string_view item[20];
const auto items
{
tokens(line, ' ', item)
};
id.first = lex_cast<uint64_t>(item[0]);
id.second = lex_cast<uint64_t>(item[1]);
strlcpy(name, item[2]);
read = lex_cast<uint64_t>(item[3]);
read_merged = lex_cast<uint64_t>(item[4]);
read_sectors = lex_cast<uint64_t>(item[5]);
read_time = lex_cast<milliseconds>(item[6]);
write = lex_cast<uint64_t>(item[7]);
write_merged = lex_cast<uint64_t>(item[8]);
write_sectors = lex_cast<uint64_t>(item[9]);
write_time = lex_cast<milliseconds>(item[10]);
io_current = lex_cast<uint64_t>(item[11]);
io_time = lex_cast<milliseconds>(item[12]);
io_weighted_time = lex_cast<milliseconds>(item[13]);
if(items <= 14)
return;
discard = lex_cast<uint64_t>(item[14]);
discard_merged = lex_cast<uint64_t>(item[15]);
discard_sectors = lex_cast<uint64_t>(item[16]);
discard_time = lex_cast<milliseconds>(item[17]);
if(items <= 18)
return;
flush = lex_cast<uint64_t>(item[18]);
flush_time = lex_cast<milliseconds>(item[19]);
if(items <= 20)
return;
}

View File

@ -1087,6 +1087,78 @@ console_cmd__fs__dev(opt &out, const string_view &line)
return true;
}
bool
console_cmd__fs__dev__stats(opt &out, const string_view &line)
{
const params param{line, " ",
{
"name"
}};
const string_view name
{
param["name"]
};
out
<< std::setw(3) << std::right << "maj" << ':'
<< std::setw(3) << std::left << "min" << ' '
<< std::setw(18) << std::left << "name" << ' '
<< std::setw(6) << std::right << "io cur" << ' '
<< std::setw(12) << std::right << "io time" << ' '
<< std::setw(12) << std::right << "io weighted" << ' '
<< std::setw(12) << std::right << "reads" << ' '
<< std::setw(12) << std::right << "read sect" << ' '
<< std::setw(12) << std::right << "read merge" << ' '
<< std::setw(12) << std::right << "read time" << ' '
<< std::setw(12) << std::right << "writes" << ' '
<< std::setw(12) << std::right << "write sect" << ' '
<< std::setw(12) << std::right << "write merge" << ' '
<< std::setw(12) << std::right << "write time" << ' '
<< std::setw(12) << std::right << "discards" << ' '
<< std::setw(12) << std::right << "discard sect" << ' '
<< std::setw(12) << std::right << "discard merg" << ' '
<< std::setw(12) << std::right << "discard time" << ' '
<< std::setw(12) << std::right << "flushes" << ' '
<< std::setw(12) << std::right << "flush time" << ' '
<< std::endl;
fs::dev::stats::for_each([&out, &name]
(const auto &stats)
{
if(name && !startswith(stats.name, name))
return true;
char tmbuf[8][32];
out
<< std::setw(3) << std::right << stats.id.first << ':'
<< std::setw(3) << std::left << stats.id.second << ' '
<< std::setw(18) << std::left << stats.name << ' '
<< std::setw(6) << std::right << stats.io_current << ' '
<< std::setw(12) << std::right << pretty(tmbuf[0], stats.io_time, 1) << ' '
<< std::setw(12) << std::right << pretty(tmbuf[1], stats.io_weighted_time, 1) << ' '
<< std::setw(12) << std::right << stats.read << ' '
<< std::setw(12) << std::right << stats.read_merged << ' '
<< std::setw(12) << std::right << stats.read_sectors << ' '
<< std::setw(12) << std::right << pretty(tmbuf[2], stats.read_time, 1) << ' '
<< std::setw(12) << std::right << stats.write << ' '
<< std::setw(12) << std::right << stats.write_merged << ' '
<< std::setw(12) << std::right << stats.write_sectors << ' '
<< std::setw(12) << std::right << pretty(tmbuf[3], stats.write_time, 1) << ' '
<< std::setw(12) << std::right << stats.discard << ' '
<< std::setw(12) << std::right << stats.discard_merged << ' '
<< std::setw(12) << std::right << stats.discard_sectors << ' '
<< std::setw(12) << std::right << pretty(tmbuf[4], stats.discard_time, 1) << ' '
<< std::setw(12) << std::right << stats.flush << ' '
<< std::setw(12) << std::right << pretty(tmbuf[5], stats.flush_time, 1) << ' '
<< '\n';
return !name;
});
out << std::endl;
return true;
}
bool
console_cmd__ls(opt &out, const string_view &line)
{