]> www.infradead.org Git - users/sagi/nvme-cli.git/commitdiff
plugins/amzn: add stats support
authorSwapnil Dinkar <sddinkar@amazon.com>
Thu, 7 Nov 2024 03:32:30 +0000 (03:32 +0000)
committerDaniel Wagner <wagi@monom.org>
Mon, 11 Nov 2024 12:39:28 +0000 (13:39 +0100)
this patch adds support to pull stats from amzn ebs nvme devices.

Signed-off-by: Swapnil Dinkar <sddinkar@amazon.com>
plugins/amzn/amzn-nvme.c
plugins/amzn/amzn-nvme.h

index d359cc34975c9febec6e633cf5184d3a917779ea..54afb0dde764041b274748d0e1b8490bd8976dbf 100644 (file)
 #define CREATE_CMD
 #include "amzn-nvme.h"
 
+#define AMZN_NVME_STATS_LOGPAGE_ID 0xD0
+#define AMZN_NVME_STATS_MAGIC 0x3C23B510
+
+#define array_add_obj json_array_add_value_object
+#define obj_add_array json_object_add_value_array
+#define obj_add_obj json_object_add_value_object
+#define obj_add_uint json_object_add_value_uint
+#define obj_add_uint64 json_object_add_value_uint64
+
 struct nvme_vu_id_ctrl_field {
        __u8                    bdev[32];
        __u8                    reserved0[992];
 };
 
+struct amzn_latency_histogram_bin {
+       __u64 lower;
+       __u64 upper;
+       __u32 count;
+       __u32 reserved;
+} __packed;
+
+struct amzn_latency_histogram {
+       __u64 num_bins;
+       struct amzn_latency_histogram_bin bins[64];
+} __packed;
+
+struct amzn_latency_log_page {
+       __u32 magic;
+       __u32 reserved0;
+       __u64 total_read_ops;
+       __u64 total_write_ops;
+       __u64 total_read_bytes;
+       __u64 total_write_bytes;
+       __u64 total_read_time;
+       __u64 total_write_time;
+       __u64 ebs_volume_performance_exceeded_iops;
+       __u64 ebs_volume_performance_exceeded_tp;
+       __u64 ec2_instance_ebs_performance_exceeded_iops;
+       __u64 ec2_instance_ebs_performance_exceeded_tp;
+       __u64 volume_queue_length;
+       __u8 reserved1[416];
+
+       struct amzn_latency_histogram read_io_latency_histogram;
+       struct amzn_latency_histogram write_io_latency_histogram;
+
+       __u8 reserved2[496];
+} __packed;
+
 static void json_amzn_id_ctrl(struct nvme_vu_id_ctrl_field *id,
        char *bdev,
        struct json_object *root)
@@ -52,3 +95,168 @@ static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *pl
 {
        return __id_ctrl(argc, argv, cmd, plugin, amzn_id_ctrl);
 }
+
+static void amzn_print_latency_histogram(struct amzn_latency_histogram *hist)
+{
+       printf("=================================\n");
+       printf("Lower       Upper        IO Count\n");
+       printf("=================================\n");
+
+       for (int b = 0; b < hist->num_bins && b < 64; b++) {
+               struct amzn_latency_histogram_bin *bin = &hist->bins[b];
+
+               printf("[%-8llu - %-8llu] => %-8u\n",
+                      bin->lower, bin->upper, bin->count);
+       }
+
+       printf("=================================\n\n");
+}
+
+static void amzn_json_add_histogram(struct json_object *root,
+                                   struct amzn_latency_histogram *hist)
+{
+       struct json_object *bins = json_create_array();
+
+       obj_add_uint64(root, "num_bins", hist->num_bins);
+       obj_add_array(root, "bins", bins);
+
+       for (int b = 0; b < hist->num_bins && b < 64; b++) {
+               struct amzn_latency_histogram_bin *bin = &hist->bins[b];
+               struct json_object *json_bin = json_create_object();
+
+               obj_add_uint64(json_bin, "lower", bin->lower);
+               obj_add_uint64(json_bin, "upper", bin->upper);
+               obj_add_uint(json_bin, "count", bin->count);
+
+               array_add_obj(bins, json_bin);
+       }
+}
+
+static void amzn_print_json_stats(struct amzn_latency_log_page *log)
+{
+       struct json_object *root = json_create_object();
+       struct json_object *r_hist = json_create_object();
+       struct json_object *w_hist = json_create_object();
+
+       obj_add_uint64(root, "total_read_ops", log->total_read_ops);
+       obj_add_uint64(root, "total_write_ops", log->total_write_ops);
+       obj_add_uint64(root, "total_read_bytes", log->total_read_bytes);
+       obj_add_uint64(root, "total_write_bytes", log->total_write_bytes);
+       obj_add_uint64(root, "total_read_time", log->total_read_time);
+       obj_add_uint64(root, "total_write_time", log->total_write_time);
+       obj_add_uint64(root, "ebs_volume_performance_exceeded_iops",
+                      log->ebs_volume_performance_exceeded_iops);
+       obj_add_uint64(root, "ebs_volume_performance_exceeded_tp",
+                      log->ebs_volume_performance_exceeded_tp);
+       obj_add_uint64(root,
+                      "ec2_instance_ebs_performance_exceeded_iops",
+                      log->ec2_instance_ebs_performance_exceeded_iops);
+       obj_add_uint64(root, "ec2_instance_ebs_performance_exceeded_tp",
+                      log->ec2_instance_ebs_performance_exceeded_tp);
+       obj_add_uint64(root, "volume_queue_length", log->volume_queue_length);
+
+       amzn_json_add_histogram(r_hist, &log->read_io_latency_histogram);
+       obj_add_obj(root, "read_io_latency_histogram", r_hist);
+       amzn_json_add_histogram(w_hist, &log->write_io_latency_histogram);
+       obj_add_obj(root, "write_io_latency_histogram", w_hist);
+
+       json_print_object(root, NULL);
+       printf("\n");
+
+       json_free_object(root);
+}
+
+static void amzn_print_normal_stats(struct amzn_latency_log_page *log)
+{
+       printf("Total Ops:\n");
+       printf("  Read: %llu\n", log->total_read_ops);
+       printf("  Write: %llu\n", log->total_write_ops);
+       printf("Total Bytes:\n");
+       printf("  Read: %llu\n", log->total_read_bytes);
+       printf("  Write: %llu\n", log->total_write_bytes);
+       printf("Total Time (us):\n");
+       printf("  Read: %llu\n", log->total_read_time);
+       printf("  Write: %llu\n\n", log->total_write_time);
+
+       printf("EBS Volume Performance Exceeded (us):\n");
+       printf("  IOPS: %llu\n", log->ebs_volume_performance_exceeded_iops);
+       printf("  Throughput: %llu\n\n",
+              log->ebs_volume_performance_exceeded_tp);
+       printf("EC2 Instance EBS Performance Exceeded (us):\n");
+       printf("  IOPS: %llu\n",
+              log->ec2_instance_ebs_performance_exceeded_iops);
+       printf("  Throughput: %llu\n\n",
+              log->ec2_instance_ebs_performance_exceeded_tp);
+
+       printf("Queue Length (point in time): %llu\n\n",
+              log->volume_queue_length);
+
+       printf("Read IO Latency Histogram\n");
+       amzn_print_latency_histogram(&log->read_io_latency_histogram);
+
+       printf("Write IO Latency Histogram\n");
+       amzn_print_latency_histogram(&log->write_io_latency_histogram);
+}
+
+static int get_stats(int argc, char **argv, struct command *cmd,
+                    struct plugin *plugin)
+{
+       const char *desc = "display command latency statistics";
+       struct nvme_dev *dev;
+       struct amzn_latency_log_page log = { 0 };
+       int rc;
+
+       struct config {
+               char *output_format;
+       };
+
+       struct config cfg = {
+               .output_format = "normal",
+       };
+
+       OPT_ARGS(opts) = {
+               OPT_FMT("output-format", 'o', &cfg.output_format,
+                       "Output Format: normal|json"),
+               OPT_END()};
+
+       rc = parse_and_open(&dev, argc, argv, desc, opts);
+       if (rc)
+               return rc;
+
+       struct nvme_get_log_args args = {
+               .args_size = sizeof(args),
+               .fd = dev_fd(dev),
+               .lid = AMZN_NVME_STATS_LOGPAGE_ID,
+               .nsid = 1,
+               .lpo = 0,
+               .lsp = NVME_LOG_LSP_NONE,
+               .lsi = 0,
+               .rae = false,
+               .uuidx = 0,
+               .csi = NVME_CSI_NVM,
+               .ot = false,
+               .len = sizeof(log),
+               .log = &log,
+               .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+               .result = NULL,
+       };
+
+       rc = nvme_get_log(&args);
+       if (rc != 0) {
+               fprintf(stderr, "[ERROR] %s: Failed to get log page, rc = %d",
+                       __func__, rc);
+               return rc;
+       }
+
+       if (log.magic != AMZN_NVME_STATS_MAGIC) {
+               fprintf(stderr, "[ERROR] %s: Not an EBS device", __func__);
+               return -ENOTSUP;
+       }
+
+       if (!strcmp(cfg.output_format, "json"))
+               amzn_print_json_stats(&log);
+       else
+               amzn_print_normal_stats(&log);
+
+       return 0;
+}
index f6c4f8bbba35a40bd01077e128c9ab3b21f59892..19f209bd069695954e70d5c5e47d7b73f9258ee5 100644 (file)
@@ -10,6 +10,7 @@
 PLUGIN(NAME("amzn", "Amazon vendor specific extensions", NVME_VERSION),
        COMMAND_LIST(
                ENTRY("id-ctrl", "Send NVMe Identify Controller", id_ctrl)
+               ENTRY("stats", "Get EBS volume stats", get_stats)
        )
 );