diff --git a/c_src/bcachefs.c b/c_src/bcachefs.c index 77bf6215..db5acedb 100644 --- a/c_src/bcachefs.c +++ b/c_src/bcachefs.c @@ -52,6 +52,7 @@ void bcachefs_usage(void) #endif "Commands for managing a running filesystem:\n" " fs usage Show disk usage\n" + " fs top Show runtime performance information\n" "\n" "Commands for managing devices within a running filesystem:\n" " device add Add a new device to an existing filesystem\n" @@ -119,6 +120,8 @@ int fs_cmds(int argc, char *argv[]) } if (!strcmp(cmd, "usage")) return cmd_fs_usage(argc, argv); + if (!strcmp(cmd, "top")) + return cmd_fs_top(argc, argv); return 0; } diff --git a/c_src/cmd_top.c b/c_src/cmd_top.c new file mode 100644 index 00000000..05845340 --- /dev/null +++ b/c_src/cmd_top.c @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include +#include + +#include "cmds.h" +#include "libbcachefs.h" +#include "libbcachefs/sb-counters.h" + +static const u8 counters_to_stable_map[] = { +#define x(n, id, ...) [BCH_COUNTER_##n] = BCH_COUNTER_STABLE_##n, + BCH_PERSISTENT_COUNTERS() +#undef x +}; + +static struct bch_ioctl_query_counters *read_counters(struct bchfs_handle fs) +{ + struct bch_ioctl_query_counters *ret = + kzalloc(sizeof(*ret) + sizeof(ret->d[0]) * BCH_COUNTER_NR, GFP_KERNEL); + + ret->nr = BCH_COUNTER_NR; + + xioctl(fs.ioctl_fd, BCH_IOCTL_QUERY_COUNTERS, ret); + return ret; +} + +static void fs_top(const char *path, bool human_readable) +{ + struct bchfs_handle fs = bcache_fs_open(path); + + struct bch_ioctl_query_counters *curr, *prev = NULL; + + curr = read_counters(fs); + + while (true) { + sleep(1); + kfree(prev); + prev = curr; + curr = read_counters(fs); + + printf("\033[2J"); + printf("\033[H"); + + for (unsigned i = 0; i < BCH_COUNTER_NR; i++) { + unsigned stable = counters_to_stable_map[i]; + u64 v = stable < curr->nr + ? curr->d[stable] - prev->d[stable] + : 0; + printf("%-48s %llu\n", + bch2_counter_names[i], + v); + } + } + + bcache_fs_close(fs); +} + +static void fs_top_usage(void) +{ + puts("bcachefs fs top - display runtime perfomance info\n" + "Usage: bcachefs fs top [OPTION]... \n" + "\n" + "Options:\n" + " -h, --human-readable Human readable units\n" + " -H, --help Display this help and exit\n" + "Report bugs to "); +} + +int cmd_fs_top(int argc, char *argv[]) +{ + static const struct option longopts[] = { + { "help", no_argument, NULL, 'H' }, + { "human-readable", no_argument, NULL, 'h' }, + { NULL } + }; + bool human_readable = false; + int opt; + + while ((opt = getopt_long(argc, argv, "Hh", + longopts, NULL)) != -1) + switch (opt) { + case 'h': + human_readable = true; + break; + case 'H': + fs_top_usage(); + exit(EXIT_SUCCESS); + default: + fs_top_usage(); + exit(EXIT_FAILURE); + } + args_shift(optind); + + fs_top(arg_pop() ?: ".", human_readable) ; + return 0; +} diff --git a/c_src/cmds.h b/c_src/cmds.h index 64267dc4..bcbfb0d0 100644 --- a/c_src/cmds.h +++ b/c_src/cmds.h @@ -15,6 +15,7 @@ int cmd_reset_counters(int argc, char *argv[]); int cmd_set_option(int argc, char *argv[]); int cmd_fs_usage(int argc, char *argv[]); +int cmd_fs_top(int argc, char *argv[]); int device_usage(void); int cmd_device_add(int argc, char *argv[]);