Skip to content

Commit

Permalink
nvme-cli: add patch for EBS stats
Browse files Browse the repository at this point in the history
Signed-off-by: Ben Cressey <bcressey@amazon.com>
  • Loading branch information
bcressey committed Nov 15, 2024
1 parent ba050f8 commit c940f6a
Show file tree
Hide file tree
Showing 2 changed files with 257 additions and 0 deletions.
256 changes: 256 additions & 0 deletions packages/nvme-cli/0001-plugins-amzn-add-stats-support.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
From 5df679d03106dd793b0d777425696a8b8724b389 Mon Sep 17 00:00:00 2001
From: Swapnil Dinkar <sddinkar@amazon.com>
Date: Thu, 7 Nov 2024 03:32:30 +0000
Subject: [PATCH] plugins/amzn: add stats support

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 | 208 +++++++++++++++++++++++++++++++++++++++
plugins/amzn/amzn-nvme.h | 1 +
2 files changed, 209 insertions(+)

diff --git a/plugins/amzn/amzn-nvme.c b/plugins/amzn/amzn-nvme.c
index d359cc34..54afb0dd 100644
--- a/plugins/amzn/amzn-nvme.c
+++ b/plugins/amzn/amzn-nvme.c
@@ -14,11 +14,54 @@
#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;
+}
diff --git a/plugins/amzn/amzn-nvme.h b/plugins/amzn/amzn-nvme.h
index f6c4f8bb..19f209bd 100644
--- a/plugins/amzn/amzn-nvme.h
+++ b/plugins/amzn/amzn-nvme.h
@@ -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)
)
);

--
2.47.0

1 change: 1 addition & 0 deletions packages/nvme-cli/nvme-cli.spec
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Summary: CLI to interact with NVMe devices
License: LGPL-2.1-only AND GPL-2.0-only AND CC0-1.0 AND MIT
URL: /~https://github.com/linux-nvme/nvme-cli
Source0: /~https://github.com/linux-nvme/nvme-cli/archive/v%{version}/nvme-cli-%{version}.tar.gz
Patch1: 0001-plugins-amzn-add-stats-support.patch

BuildRequires: meson
BuildRequires: %{_cross_os}glibc-devel
Expand Down

0 comments on commit c940f6a

Please sign in to comment.