-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Ben Cressey <bcressey@amazon.com>
- Loading branch information
Showing
2 changed files
with
257 additions
and
0 deletions.
There are no files selected for viewing
256 changes: 256 additions & 0 deletions
256
packages/nvme-cli/0001-plugins-amzn-add-stats-support.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters