Skip to content

Commit

Permalink
plugins/amzn: add stats support
Browse files Browse the repository at this point in the history
this patch adds support to pull stats from amzn ebs nvme devices.

Signed-off-by: Swapnil Dinkar <[email protected]>
  • Loading branch information
Swapnil Dinkar authored and igaw committed Nov 11, 2024
1 parent 1425179 commit 5df679d
Show file tree
Hide file tree
Showing 2 changed files with 209 additions and 0 deletions.
208 changes: 208 additions & 0 deletions plugins/amzn/amzn-nvme.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
}
1 change: 1 addition & 0 deletions plugins/amzn/amzn-nvme.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
)
);

Expand Down

0 comments on commit 5df679d

Please sign in to comment.