All of lore.kernel.org
 help / color / mirror / Atom feed
From: Nilay Shroff <nilay@linux.ibm.com>
To: linux-nvme@lists.infradead.org
Cc: dwagner@suse.de, hare@suse.com, kbusch@kernel.org, hch@lst.de,
	gjoyce@linux.ibm.com, wenxiong@linux.ibm.com
Subject: [PATCHv2 5/9] libnvme: add support for retrieving namespace gendisk I/O statistics
Date: Sat,  4 Apr 2026 15:44:55 +0530	[thread overview]
Message-ID: <20260404101504.44539-6-nilay@linux.ibm.com> (raw)
In-Reply-To: <20260404101504.44539-1-nilay@linux.ibm.com>

Gendisk I/O statistics provide useful insight into disk activity,
including read/write/discard/flush operations, as well as information
about in-flight I/Os and I/O timing.

Parsing these statistics allows users to determine the number of I/Os
processed, time spent servicing I/O, number of sectors accessed, and
the count of in-flight requests.

Add support for retrieving namespace gendisk I/O statistics. Also add
support for computing deltas of these statistics between samples, such
as I/O ticks, number of sectors, and number of serviced I/Os.

These metrics can be used by tools such as nvme-top to display real-time
disk activity.

Signed-off-by: Nilay Shroff <nilay@linux.ibm.com>
---
 libnvme/src/libnvme.ld     |  11 +++
 libnvme/src/nvme/private.h |   5 ++
 libnvme/src/nvme/tree.c    | 140 +++++++++++++++++++++++++++++++++++++
 libnvme/src/nvme/tree.h    |  94 +++++++++++++++++++++++++
 4 files changed, 250 insertions(+)

diff --git a/libnvme/src/libnvme.ld b/libnvme/src/libnvme.ld
index 53b5f90e5..c32198324 100644
--- a/libnvme/src/libnvme.ld
+++ b/libnvme/src/libnvme.ld
@@ -131,6 +131,17 @@ LIBNVME_3 {
 		nvme_ns_get_serial;
 		nvme_ns_get_subsystem;
 		nvme_ns_get_uuid;
+		nvme_ns_reset_stat;
+		nvme_ns_update_stat;
+		nvme_ns_get_stat_interval;
+		nvme_ns_get_read_ios;
+		nvme_ns_get_write_ios;
+		nvme_ns_get_read_ticks;
+		nvme_ns_get_write_ticks;
+		nvme_ns_get_read_sectors;
+		nvme_ns_get_write_sectors;
+		nvme_ns_get_inflights;
+		nvme_ns_get_io_ticks;
 		nvme_ns_identify;
 		nvme_ns_read;
 		nvme_ns_verify;
diff --git a/libnvme/src/nvme/private.h b/libnvme/src/nvme/private.h
index 2e8e792b9..f09c0d83f 100644
--- a/libnvme/src/nvme/private.h
+++ b/libnvme/src/nvme/private.h
@@ -187,6 +187,11 @@ struct nvme_ns { /*!generate-accessors*/
 	struct nvme_ns_head *head;
 
 	struct nvme_global_ctx *ctx;
+
+	struct nvme_stat stat[2];	/* gendisk I/O stat */
+	unsigned int curr_idx;		/* current index into the stat[] */
+	bool diffstat;
+
 	struct nvme_transport_handle *hdl;
 	__u32 nsid;
 	char *name;
diff --git a/libnvme/src/nvme/tree.c b/libnvme/src/nvme/tree.c
index b5f8c219d..2949b5cf8 100644
--- a/libnvme/src/nvme/tree.c
+++ b/libnvme/src/nvme/tree.c
@@ -867,6 +867,21 @@ __public void nvme_path_reset_stat(nvme_path_t p)
 	memset(stat, 0, 2 * sizeof(struct nvme_stat));
 }
 
+static nvme_stat_t nvme_ns_get_stat(nvme_ns_t n, unsigned int idx)
+{
+	if (idx > 1)
+		return NULL;
+
+	return &n->stat[idx];
+}
+
+__public void nvme_ns_reset_stat(nvme_ns_t n)
+{
+	nvme_stat_t stat = &n->stat[0];
+
+	memset(stat, 0, 2 * sizeof(struct nvme_stat));
+}
+
 static int nvme_update_stat(const char *sysfs_stat_path, nvme_stat_t stat)
 {
 	int n;
@@ -941,6 +956,24 @@ __public int nvme_path_update_stat(nvme_path_t p, bool diffstat)
 	return nvme_update_stat(sysfs_stat_path, stat);
 }
 
+__public int nvme_ns_update_stat(nvme_ns_t n, bool diffstat)
+{
+	_cleanup_free_ char *sysfs_stat_path = NULL;
+	nvme_stat_t stat;
+
+	n->diffstat = diffstat;
+	n->curr_idx ^= 1;
+	stat = nvme_ns_get_stat(n, n->curr_idx);
+	if (!stat)
+		return -EINVAL;
+
+	sysfs_stat_path = nvme_get_ns_attr(n, "stat");
+	if (!sysfs_stat_path)
+		return -EINVAL;
+
+	return nvme_update_stat(sysfs_stat_path, stat);
+}
+
 static int nvme_stat_get_inflights(nvme_stat_t stat)
 {
 	return stat->inflights;
@@ -957,6 +990,17 @@ __public unsigned int nvme_path_get_inflights(nvme_path_t p)
 	return nvme_stat_get_inflights(curr);
 }
 
+__public unsigned int nvme_ns_get_inflights(nvme_ns_t n)
+{
+	nvme_stat_t curr;
+
+	curr = nvme_ns_get_stat(n, n->curr_idx);
+	if (!curr)
+		return 0;
+
+	return nvme_stat_get_inflights(curr);
+}
+
 static int nvme_stat_get_io_ticks(nvme_stat_t curr, nvme_stat_t prev,
 		bool diffstat)
 {
@@ -984,6 +1028,19 @@ __public unsigned int nvme_path_get_io_ticks(nvme_path_t p)
 	return nvme_stat_get_io_ticks(curr, prev, p->diffstat);
 }
 
+__public unsigned int nvme_ns_get_io_ticks(nvme_ns_t n)
+{
+	nvme_stat_t curr, prev;
+
+	curr = nvme_ns_get_stat(n, n->curr_idx);
+	prev = nvme_ns_get_stat(n, !n->curr_idx);
+
+	if (!curr || !prev)
+		return 0;
+
+	return nvme_stat_get_io_ticks(curr, prev, n->diffstat);
+}
+
 static unsigned int nvme_stat_get_ticks(nvme_stat_t curr,
 		nvme_stat_t prev, enum stat_group grp, bool diffstat)
 {
@@ -1021,6 +1078,29 @@ __public unsigned int nvme_path_get_write_ticks(nvme_path_t p)
 	return __nvme_path_get_ticks(p, WRITE);
 }
 
+static unsigned int __nvme_ns_get_ticks(nvme_ns_t n, enum stat_group grp)
+{
+	nvme_stat_t curr, prev;
+
+	curr = nvme_ns_get_stat(n, n->curr_idx);
+	prev = nvme_ns_get_stat(n, !n->curr_idx);
+
+	if (!curr || !prev)
+		return 0;
+
+	return nvme_stat_get_ticks(curr, prev, grp, n->diffstat);
+}
+
+__public unsigned int nvme_ns_get_read_ticks(nvme_ns_t n)
+{
+	return __nvme_ns_get_ticks(n, READ);
+}
+
+__public unsigned int nvme_ns_get_write_ticks(nvme_ns_t n)
+{
+	return __nvme_ns_get_ticks(n, WRITE);
+}
+
 static double nvme_stat_get_interval(nvme_stat_t curr, nvme_stat_t prev)
 {
 	double delta = 0.0;
@@ -1044,6 +1124,19 @@ __public double nvme_path_get_stat_interval(nvme_path_t p)
 	return nvme_stat_get_interval(curr, prev);
 }
 
+__public double nvme_ns_get_stat_interval(nvme_ns_t n)
+{
+	nvme_stat_t curr, prev;
+
+	curr = nvme_ns_get_stat(n, n->curr_idx);
+	prev = nvme_ns_get_stat(n, !n->curr_idx);
+
+	if (!curr || !prev)
+		return 0;
+
+	return nvme_stat_get_interval(curr, prev);
+}
+
 static unsigned long nvme_stat_get_ios(nvme_stat_t curr, nvme_stat_t prev,
 		enum stat_group grp, bool diffstat)
 {
@@ -1081,6 +1174,29 @@ __public unsigned long nvme_path_get_write_ios(nvme_path_t p)
 	return __nvme_path_get_ios(p, WRITE);
 }
 
+static unsigned long __nvme_ns_get_ios(nvme_ns_t n, enum stat_group grp)
+{
+	nvme_stat_t curr, prev;
+
+	curr = nvme_ns_get_stat(n, n->curr_idx);
+	prev = nvme_ns_get_stat(n, !n->curr_idx);
+
+	if (!curr || !prev)
+		return 0;
+
+	return nvme_stat_get_ios(curr, prev, grp, n->diffstat);
+}
+
+__public unsigned long nvme_ns_get_read_ios(nvme_ns_t n)
+{
+	return __nvme_ns_get_ios(n, READ);
+}
+
+__public unsigned long nvme_ns_get_write_ios(nvme_ns_t n)
+{
+	return __nvme_ns_get_ios(n, WRITE);
+}
+
 static unsigned long long nvme_stat_get_sectors(nvme_stat_t curr,
 		nvme_stat_t prev, enum stat_group grp, bool diffstat)
 {
@@ -1119,6 +1235,30 @@ __public unsigned long long nvme_path_get_write_sectors(nvme_path_t p)
 	return __nvme_path_get_sectors(p, WRITE);
 }
 
+static unsigned long long __nvme_ns_get_sectors(nvme_ns_t n,
+		enum stat_group grp)
+{
+	nvme_stat_t curr, prev;
+
+	curr = nvme_ns_get_stat(n, n->curr_idx);
+	prev = nvme_ns_get_stat(n, !n->curr_idx);
+
+	if (!curr || !prev)
+		return 0;
+
+	return nvme_stat_get_sectors(curr, prev, grp, n->diffstat);
+}
+
+__public unsigned long long nvme_ns_get_read_sectors(nvme_ns_t n)
+{
+	return __nvme_ns_get_sectors(n, READ);
+}
+
+__public unsigned long long nvme_ns_get_write_sectors(nvme_ns_t n)
+{
+	return __nvme_ns_get_sectors(n, WRITE);
+}
+
 void nvme_free_path(struct nvme_path *p)
 {
 	list_del_init(&p->entry);
diff --git a/libnvme/src/nvme/tree.h b/libnvme/src/nvme/tree.h
index 8c42edd71..01f7fda86 100644
--- a/libnvme/src/nvme/tree.h
+++ b/libnvme/src/nvme/tree.h
@@ -867,6 +867,100 @@ nvme_subsystem_t nvme_ctrl_get_subsystem(nvme_ctrl_t c);
  */
 const char *nvme_ns_head_get_sysfs_dir(nvme_ns_head_t head);
 
+/**
+ * nvme_ns_update_stat() - update the nvme namespace stat
+ * @n:		&nvme_ns_t object
+ * @diffstat:	If set to true then getters return the diff stat otherwise
+ *		return the current absolute stat
+ *
+ * Returns:	0 on success, -1 on error
+ */
+int nvme_ns_update_stat(nvme_ns_t n, bool diffstat);
+
+/**
+ * nvme_ns_reset_stat() - Resets nvme namespace stat
+ * @n:	&nvme_ns_t object
+ *
+ */
+void nvme_ns_reset_stat(nvme_ns_t n);
+
+/**
+ * nvme_ns_get_inflights() - Inflight IOs for nvme_ns_t object
+ *
+ * @n:		&nvme_ns_t object
+ *
+ * Return:	Inflight number of IOs
+ */
+unsigned int nvme_ns_get_inflights(nvme_ns_t n);
+
+/**
+ * nvme_ns_get_io_ticks() - Get IO ticks
+ * @n:		&nvme_ns_t object
+ *
+ * Return:	Time consumed, in milliseconds, processing I/O requests between
+ *		two stat samples
+ */
+unsigned int nvme_ns_get_io_ticks(nvme_ns_t n);
+
+/**
+ * nvme_ns_get_read_ticks() - Get read I/O ticks
+ * @n:		&nvme_ns_t object
+ *
+ * Return:	Time, in milliseconds, sepnt processing read I/O requests
+ *		between two stat samples
+ */
+unsigned int nvme_ns_get_read_ticks(nvme_ns_t n);
+
+/**
+ * nvme_ns_get_write_ticks() - Get write I/O ticks
+ * @n:		&nvme_ns_t object
+ *
+ * Return:	Time, in milliseconds, sepnt processing write I/O requests
+ *		between two stat samples
+ */
+unsigned int nvme_ns_get_write_ticks(nvme_ns_t n);
+
+/**
+ * nvme_ns_get_stat_interval() - Get interval between two stat samples
+ * @n:		&nvme_ns_t object
+ *
+ * Return:	Interval, in milliseconds, between collection of two consecutive
+ *		stat samples
+ */
+double nvme_ns_get_stat_interval(nvme_ns_t n);
+
+/**
+ * nvme_ns_get_read_ios() - Get num of read I/Os
+ * @n:		&nvme_ns_t object
+ *
+ * Return:	Num of read IOs processed between two stat samples
+ */
+unsigned long nvme_ns_get_read_ios(nvme_ns_t n);
+
+/**
+ * nvme_ns_get_write_ios() - Get num of write I/Os
+ * @n:		&nvme_ns_t object
+ *
+ * Return:	Num of write IOs processed between two consecutive stat samples
+ */
+unsigned long nvme_ns_get_write_ios(nvme_ns_t n);
+
+/**
+ * nvme_ns_get_read_sectors() - Get num of read sectors
+ * @n:		&nvme_ns_t object
+ *
+ * Return:	Num of sectors read from the device between two stat samples
+ */
+unsigned long long nvme_ns_get_read_sectors(nvme_ns_t n);
+
+/**
+ * nvme_ns_get_write_sectors() - Get num of write sectors
+ * @n:		&nvme_ns_t object
+ *
+ * Return:	Num of sectors written to the device between two stat samples
+ */
+unsigned long long nvme_ns_get_write_sectors(nvme_ns_t n);
+
 /**
  * nvme_ctrl_get_config() - Fabrics configuration of a controller
  * @c:	Controller instance
-- 
2.53.0



  parent reply	other threads:[~2026-04-04 10:15 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-04 10:14 [PATCHv2 0/9] libnvme: add support for retrieving additional NVMe stat Nilay Shroff
2026-04-04 10:14 ` [PATCHv2 1/9] libnvme: annotate nvme_path::ana_state with !accessors:none Nilay Shroff
2026-04-04 10:14 ` [PATCHv2 2/9] libnvme: annotate nvme_path::numa_nodes " Nilay Shroff
2026-04-04 10:14 ` [PATCHv2 3/9] libnvme: annotate nvme_subsystem::iopolicy " Nilay Shroff
2026-04-04 10:14 ` [PATCHv2 4/9] libnvme: add support for retrieving per-path gendisk I/O statistics Nilay Shroff
2026-04-04 10:14 ` Nilay Shroff [this message]
2026-04-04 10:14 ` [PATCHv2 6/9] libnvme: add support for per-path diagnostic counters Nilay Shroff
2026-04-04 10:14 ` [PATCHv2 7/9] libnvme: add support for namespace " Nilay Shroff
2026-04-04 10:14 ` [PATCHv2 8/9] libnvme: add support for nshead " Nilay Shroff
2026-04-04 10:14 ` [PATCHv2 9/9] libnvme: add support for ctrl " Nilay Shroff
2026-04-09  9:10 ` [PATCHv2 0/9] libnvme: add support for retrieving additional NVMe stat Daniel Wagner
2026-04-10  7:33   ` Nilay Shroff

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260404101504.44539-6-nilay@linux.ibm.com \
    --to=nilay@linux.ibm.com \
    --cc=dwagner@suse.de \
    --cc=gjoyce@linux.ibm.com \
    --cc=hare@suse.com \
    --cc=hch@lst.de \
    --cc=kbusch@kernel.org \
    --cc=linux-nvme@lists.infradead.org \
    --cc=wenxiong@linux.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.