Skip to content

Commit 2b0b76e

Browse files
author
Swapnil Dinkar
committed
plugins/amzn: add stats support
this patch adds support to pull stats from amzn ebs nvme devices. Signed-off-by: Swapnil Dinkar <[email protected]>
1 parent 10e3119 commit 2b0b76e

File tree

2 files changed

+217
-0
lines changed

2 files changed

+217
-0
lines changed

plugins/amzn/amzn-nvme.c

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,57 @@
1414
#define CREATE_CMD
1515
#include "amzn-nvme.h"
1616

17+
#define AMZN_NVME_STATS_LOGPAGE_ID 0xD0
18+
#define AMZN_NVME_STATS_MAGIC 0x3C23B510
19+
20+
#define array_add_obj json_array_add_value_object
21+
#define obj_add_array json_object_add_value_array
22+
#define obj_add_obj json_object_add_value_object
23+
#define obj_add_uint json_object_add_value_uint
24+
#define obj_add_uint64 json_object_add_value_uint64
25+
1726
struct nvme_vu_id_ctrl_field {
1827
__u8 bdev[32];
1928
__u8 reserved0[992];
2029
};
2130

31+
struct amzn_latency_histogram_bin
32+
{
33+
__u64 lower;
34+
__u64 upper;
35+
__u32 count;
36+
__u32 reserved;
37+
} __attribute__((packed));
38+
39+
struct amzn_latency_histogram
40+
{
41+
__u64 num_bins;
42+
struct amzn_latency_histogram_bin bins[64];
43+
} __attribute__((packed));
44+
45+
struct amzn_latency_log_page
46+
{
47+
__u32 magic;
48+
__u32 reserved0;
49+
__u64 total_read_ops;
50+
__u64 total_write_ops;
51+
__u64 total_read_bytes;
52+
__u64 total_write_bytes;
53+
__u64 total_read_time;
54+
__u64 total_write_time;
55+
__u64 ebs_volume_performance_exceeded_iops;
56+
__u64 ebs_volume_performance_exceeded_tp;
57+
__u64 ec2_instance_ebs_performance_exceeded_iops;
58+
__u64 ec2_instance_ebs_performance_exceeded_tp;
59+
__u64 volume_queue_length;
60+
__u8 reserved1[416];
61+
62+
struct amzn_latency_histogram read_io_latency_histogram;
63+
struct amzn_latency_histogram write_io_latency_histogram;
64+
65+
__u8 reserved2[496];
66+
} __attribute__((packed));
67+
2268
static void json_amzn_id_ctrl(struct nvme_vu_id_ctrl_field *id,
2369
char *bdev,
2470
struct json_object *root)
@@ -52,3 +98,173 @@ static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *pl
5298
{
5399
return __id_ctrl(argc, argv, cmd, plugin, amzn_id_ctrl);
54100
}
101+
102+
static void amzn_print_latency_histogram(struct amzn_latency_histogram *hist)
103+
{
104+
printf("=================================\n");
105+
printf("Lower Upper IO Count\n");
106+
printf("=================================\n");
107+
108+
for (int b = 0; b < hist->num_bins && b < 64; b++)
109+
{
110+
struct amzn_latency_histogram_bin *bin = &hist->bins[b];
111+
112+
printf("[%-8llu - %-8llu] => %-8u \n",
113+
bin->lower, bin->upper, bin->count);
114+
}
115+
116+
printf("=================================\n\n");
117+
}
118+
119+
static void amzn_json_add_histogram(struct json_object *root,
120+
struct amzn_latency_histogram *hist)
121+
{
122+
struct json_object *bins = json_create_array();
123+
124+
obj_add_uint64(root, "num_bins", hist->num_bins);
125+
obj_add_array(root, "bins", bins);
126+
127+
for (int b = 0; b < hist->num_bins && b < 64; b++)
128+
{
129+
struct amzn_latency_histogram_bin *bin = &hist->bins[b];
130+
struct json_object *json_bin = json_create_object();
131+
132+
obj_add_uint64(json_bin, "lower", bin->lower);
133+
obj_add_uint64(json_bin, "upper", bin->upper);
134+
obj_add_uint(json_bin, "count", bin->count);
135+
136+
array_add_obj(bins, json_bin);
137+
}
138+
}
139+
140+
static void amzn_print_json_stats(struct amzn_latency_log_page *log)
141+
{
142+
struct json_object *root = json_create_object();
143+
struct json_object *r_hist = json_create_object();
144+
struct json_object *w_hist = json_create_object();
145+
146+
obj_add_uint64(root, "total_read_ops", log->total_read_ops);
147+
obj_add_uint64(root, "total_write_ops", log->total_write_ops);
148+
obj_add_uint64(root, "total_read_bytes", log->total_read_bytes);
149+
obj_add_uint64(root, "total_write_bytes", log->total_write_bytes);
150+
obj_add_uint64(root, "total_read_time", log->total_read_time);
151+
obj_add_uint64(root, "total_write_time", log->total_write_time);
152+
obj_add_uint64(root, "ebs_volume_performance_exceeded_iops",
153+
log->ebs_volume_performance_exceeded_iops);
154+
obj_add_uint64(root, "ebs_volume_performance_exceeded_tp",
155+
log->ebs_volume_performance_exceeded_tp);
156+
obj_add_uint64(root,
157+
"ec2_instance_ebs_performance_exceeded_iops",
158+
log->ec2_instance_ebs_performance_exceeded_iops);
159+
obj_add_uint64(root, "ec2_instance_ebs_performance_exceeded_tp",
160+
log->ec2_instance_ebs_performance_exceeded_tp);
161+
obj_add_uint64(root, "volume_queue_length", log->volume_queue_length);
162+
163+
amzn_json_add_histogram(r_hist, &log->read_io_latency_histogram);
164+
obj_add_obj(root, "read_io_latency_histogram", r_hist);
165+
amzn_json_add_histogram(w_hist, &log->write_io_latency_histogram);
166+
obj_add_obj(root, "write_io_latency_histogram", w_hist);
167+
168+
json_print_object(root, NULL);
169+
printf("\n");
170+
171+
json_free_object(root);
172+
}
173+
174+
static void amzn_print_normal_stats(struct amzn_latency_log_page *log)
175+
{
176+
printf("Total Ops:\n");
177+
printf(" Read: %llu\n", log->total_read_ops);
178+
printf(" Write: %llu\n", log->total_write_ops);
179+
printf("Total Bytes:\n");
180+
printf(" Read: %llu\n", log->total_read_bytes);
181+
printf(" Write: %llu\n", log->total_write_bytes);
182+
printf("Total Time (us):\n");
183+
printf(" Read: %llu\n", log->total_read_time);
184+
printf(" Write: %llu\n\n", log->total_write_time);
185+
186+
printf("EBS Volume Performance Exceeded (us):\n");
187+
printf(" IOPS: %llu\n", log->ebs_volume_performance_exceeded_iops);
188+
printf(" Throughput: %llu\n\n",
189+
log->ebs_volume_performance_exceeded_tp);
190+
printf("EC2 Instance EBS Performance Exceeded (us):\n");
191+
printf(" IOPS: %llu\n",
192+
log->ec2_instance_ebs_performance_exceeded_iops);
193+
printf(" Throughput: %llu\n\n",
194+
log->ec2_instance_ebs_performance_exceeded_tp);
195+
196+
printf("Queue Length (point in time): %llu\n\n",
197+
log->volume_queue_length);
198+
199+
printf("Read IO Latency Histogram\n");
200+
amzn_print_latency_histogram(&log->read_io_latency_histogram);
201+
202+
printf("Write IO Latency Histogram\n");
203+
amzn_print_latency_histogram(&log->write_io_latency_histogram);
204+
}
205+
206+
static int get_stats(int argc, char **argv, struct command *cmd,
207+
struct plugin *plugin)
208+
{
209+
const char *desc = "display command latency statistics";
210+
struct nvme_dev *dev;
211+
struct amzn_latency_log_page log = { 0 };
212+
int rc;
213+
214+
struct config
215+
{
216+
char *output_format;
217+
};
218+
219+
struct config cfg = {
220+
.output_format = "normal",
221+
};
222+
223+
OPT_ARGS(opts) = {
224+
OPT_FMT("output-format", 'o', &cfg.output_format,
225+
"Output Format: normal|json"),
226+
OPT_END()};
227+
228+
rc = parse_and_open(&dev, argc, argv, desc, opts);
229+
if (rc)
230+
return rc;
231+
232+
struct nvme_get_log_args args = {
233+
.args_size = sizeof(args),
234+
.fd = dev_fd(dev),
235+
.lid = AMZN_NVME_STATS_LOGPAGE_ID,
236+
.nsid = 1,
237+
.lpo = 0,
238+
.lsp = NVME_LOG_LSP_NONE,
239+
.lsi = 0,
240+
.rae = false,
241+
.uuidx = 0,
242+
.csi = NVME_CSI_NVM,
243+
.ot = false,
244+
.len = sizeof(log),
245+
.log = &log,
246+
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
247+
.result = NULL,
248+
};
249+
250+
rc = nvme_get_log(&args);
251+
if (rc != 0)
252+
{
253+
fprintf(stderr, "[ERROR] %s: Failed to get log page, rc = %d",
254+
__func__, rc);
255+
return rc;
256+
}
257+
258+
if (log.magic != AMZN_NVME_STATS_MAGIC)
259+
{
260+
fprintf(stderr, "[ERROR] %s: Not an EBS device", __func__);
261+
return -ENOTSUP;
262+
}
263+
264+
if (!strcmp(cfg.output_format, "json"))
265+
amzn_print_json_stats(&log);
266+
else
267+
amzn_print_normal_stats(&log);
268+
269+
return 0;
270+
}

plugins/amzn/amzn-nvme.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
PLUGIN(NAME("amzn", "Amazon vendor specific extensions", NVME_VERSION),
1111
COMMAND_LIST(
1212
ENTRY("id-ctrl", "Send NVMe Identify Controller", id_ctrl)
13+
ENTRY("stats", "Get EBS volume stats", get_stats)
1314
)
1415
);
1516

0 commit comments

Comments
 (0)