diff --git a/include/ircd/fs/dev.h b/include/ircd/fs/dev.h index 6bf2da528..0bcfd8f69 100644 --- a/include/ircd/fs/dev.h +++ b/include/ircd/fs/dev.h @@ -14,6 +14,7 @@ namespace ircd::fs::dev { struct blk; + struct stats; using major_minor = std::pair; @@ -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; + + 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 diff --git a/ircd/fs_dev.cc b/ircd/fs_dev.cc index 2b0e9a061..3c684d8d4 100644 --- a/ircd/fs_dev.cc +++ b/ircd/fs_dev.cc @@ -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(item[0]); + id.second = lex_cast(item[1]); + strlcpy(name, item[2]); + + read = lex_cast(item[3]); + read_merged = lex_cast(item[4]); + read_sectors = lex_cast(item[5]); + read_time = lex_cast(item[6]); + + write = lex_cast(item[7]); + write_merged = lex_cast(item[8]); + write_sectors = lex_cast(item[9]); + write_time = lex_cast(item[10]); + + io_current = lex_cast(item[11]); + io_time = lex_cast(item[12]); + io_weighted_time = lex_cast(item[13]); + + if(items <= 14) + return; + + discard = lex_cast(item[14]); + discard_merged = lex_cast(item[15]); + discard_sectors = lex_cast(item[16]); + discard_time = lex_cast(item[17]); + + if(items <= 18) + return; + + flush = lex_cast(item[18]); + flush_time = lex_cast(item[19]); + + if(items <= 20) + return; +} diff --git a/modules/console.cc b/modules/console.cc index 64100f19a..c8dbdb07c 100644 --- a/modules/console.cc +++ b/modules/console.cc @@ -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) {