mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Ahmad Fatoum <a.fatoum@pengutronix.de>
To: barebox@lists.infradead.org
Cc: Ahmad Fatoum <a.fatoum@pengutronix.de>
Subject: [PATCH v2 10/10] commands: blkstats: add command to print block device statistics
Date: Wed, 31 Jul 2024 10:05:10 +0200	[thread overview]
Message-ID: <20240731080510.364706-11-a.fatoum@pengutronix.de> (raw)
In-Reply-To: <20240731080510.364706-1-a.fatoum@pengutronix.de>

To test proper operations of block device operations, add a command that
prints how many sectors were read/written/erased for a device so far.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
  - print header only once
  - increase width of device name to 16 characters
---
 commands/Kconfig    | 11 ++++++++
 commands/Makefile   |  1 +
 commands/blkstats.c | 66 +++++++++++++++++++++++++++++++++++++++++++++
 common/Kconfig      |  3 +++
 common/block.c      | 46 +++++++++++++++++++++++++------
 include/block.h     | 10 +++++++
 6 files changed, 129 insertions(+), 8 deletions(-)
 create mode 100644 commands/blkstats.c

diff --git a/commands/Kconfig b/commands/Kconfig
index a8b7037618cc..64e834d95a8f 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -255,6 +255,17 @@ config CMD_REGINFO
 	help
 	  Print register information.
 
+config CMD_BLKSTATS
+	bool
+	depends on BLOCK
+	select BLOCK_STATS
+	prompt "blkstats command"
+	help
+	  The blkstats displays statistics about a block devices' number of
+	  sectors read, written and erased. This should only be needed for
+	  development. Saying y here will start to collect these statistics
+	  and enable a command for querying them.
+
 config CMD_REGULATOR
 	bool
 	depends on REGULATOR
diff --git a/commands/Makefile b/commands/Makefile
index a9dbead4389f..ff5d713ca72c 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -125,6 +125,7 @@ obj-$(CONFIG_CMD_DRVINFO)	+= drvinfo.o
 obj-$(CONFIG_CMD_READF)		+= readf.o
 obj-$(CONFIG_CMD_MENUTREE)	+= menutree.o
 obj-$(CONFIG_CMD_2048)		+= 2048.o
+obj-$(CONFIG_CMD_BLKSTATS)	+= blkstats.o
 obj-$(CONFIG_CMD_REGULATOR)	+= regulator.o
 obj-$(CONFIG_CMD_PM_DOMAIN)	+= pm_domain.o
 obj-$(CONFIG_CMD_LSPCI)		+= lspci.o
diff --git a/commands/blkstats.c b/commands/blkstats.c
new file mode 100644
index 000000000000..6af9da765ebe
--- /dev/null
+++ b/commands/blkstats.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <common.h>
+#include <command.h>
+#include <block.h>
+#include <getopt.h>
+#include <fs.h>
+
+static int do_blkstats(int argc, char *argv[])
+{
+	struct block_device *blk;
+	const char *name;
+	bool first = false;
+	int opt;
+
+	while ((opt = getopt(argc, argv, "l")) > 0) {
+		switch (opt) {
+		case 'l':
+			for_each_block_device(blk) {
+				printf("%s\n", blk->cdev.name);
+			}
+		default:
+			return COMMAND_ERROR_USAGE;
+		}
+	}
+
+	argv += optind;
+	argc -= optind;
+
+	name = argv[0];
+
+	for_each_block_device(blk) {
+		struct block_device_stats *stats;
+
+		if (name && strcmp(name, blk->cdev.name))
+			continue;
+
+		if (first) {
+			printf("%-16s %10s %10s %10s\n",
+			       "Device", "Read", "Write", "Erase");
+			first = true;
+		}
+
+		stats = &blk->stats;
+
+		printf("%-16s %10llu %10llu %10llu\n", blk->cdev.name,
+		       stats->read_sectors, stats->write_sectors, stats->erase_sectors);
+	}
+
+	return 0;
+}
+
+BAREBOX_CMD_HELP_START(blkstats)
+BAREBOX_CMD_HELP_TEXT("Display a block device's number of read, written and erased sectors")
+BAREBOX_CMD_HELP_TEXT("")
+BAREBOX_CMD_HELP_TEXT("Options:")
+BAREBOX_CMD_HELP_OPT("-l",  "list all currently registered block devices")
+BAREBOX_CMD_HELP_END
+
+BAREBOX_CMD_START(blkstats)
+	.cmd		= do_blkstats,
+	BAREBOX_CMD_DESC("display block layer statistics")
+	BAREBOX_CMD_OPTS("[-l] [DEVICE]")
+	BAREBOX_CMD_GROUP(CMD_GRP_INFO)
+	BAREBOX_CMD_HELP(cmd_blkstats_help)
+BAREBOX_CMD_END
diff --git a/common/Kconfig b/common/Kconfig
index fea26262da86..4500feb66c92 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -41,6 +41,9 @@ config BLOCK
 config BLOCK_WRITE
 	bool
 
+config BLOCK_STATS
+	bool
+
 config FILETYPE
 	bool
 
diff --git a/common/block.c b/common/block.c
index eaec454ecbb2..3101fceea761 100644
--- a/common/block.c
+++ b/common/block.c
@@ -32,19 +32,40 @@ static int writebuffer_io_len(struct block_device *blk, struct chunk *chunk)
 	return min_t(blkcnt_t, blk->rdbufsize, blk->num_blocks - chunk->block_start);
 }
 
+#ifdef CONFIG_BLOCK_STATS
+static void blk_stats_record_read(struct block_device *blk, blkcnt_t count)
+{
+	blk->stats.read_sectors += count;
+}
+static void blk_stats_record_write(struct block_device *blk, blkcnt_t count)
+{
+	blk->stats.write_sectors += count;
+}
+static void blk_stats_record_erase(struct block_device *blk, blkcnt_t count)
+{
+	blk->stats.erase_sectors += count;
+}
+#else
+static void blk_stats_record_read(struct block_device *blk, blkcnt_t count) { }
+static void blk_stats_record_write(struct block_device *blk, blkcnt_t count) { }
+static void blk_stats_record_erase(struct block_device *blk, blkcnt_t count) { }
+#endif
+
 static int chunk_flush(struct block_device *blk, struct chunk *chunk)
 {
+	size_t len;
 	int ret;
 
 	if (!chunk->dirty)
 		return 0;
 
-	ret = blk->ops->write(blk, chunk->data,
-			      chunk->block_start,
-			      writebuffer_io_len(blk, chunk));
+	len = writebuffer_io_len(blk, chunk);
+	ret = blk->ops->write(blk, chunk->data, chunk->block_start, len);
 	if (ret < 0)
 		return ret;
 
+	blk_stats_record_write(blk, len);
+
 	chunk->dirty = 0;
 
 	return 0;
@@ -145,6 +166,7 @@ static struct chunk *get_chunk(struct block_device *blk)
 static int block_cache(struct block_device *blk, sector_t block)
 {
 	struct chunk *chunk;
+	size_t len;
 	int ret;
 
 	chunk = get_chunk(blk);
@@ -156,20 +178,22 @@ static int block_cache(struct block_device *blk, sector_t block)
 	dev_dbg(blk->dev, "%s: %llu to %d\n", __func__, chunk->block_start,
 		chunk->num);
 
+	len = writebuffer_io_len(blk, chunk);
 	if (chunk->block_start * BLOCKSIZE(blk) >= blk->discard_start &&
-	    chunk->block_start * BLOCKSIZE(blk) + writebuffer_io_len(blk, chunk)
+	    chunk->block_start * BLOCKSIZE(blk) + len
 	    <= blk->discard_start + blk->discard_size) {
-		memset(chunk->data, 0, writebuffer_io_len(blk, chunk));
+		memset(chunk->data, 0, len);
 		list_add(&chunk->list, &blk->buffered_blocks);
 		return 0;
 	}
 
-	ret = blk->ops->read(blk, chunk->data, chunk->block_start,
-			     writebuffer_io_len(blk, chunk));
+	ret = blk->ops->read(blk, chunk->data, chunk->block_start, len);
 	if (ret) {
 		list_add_tail(&chunk->list, &blk->idle_blocks);
 		return ret;
 	}
+
+	blk_stats_record_read(blk, len);
 	list_add(&chunk->list, &blk->buffered_blocks);
 
 	return 0;
@@ -402,7 +426,13 @@ static __maybe_unused int block_op_erase(struct cdev *cdev, loff_t count, loff_t
 		}
 	}
 
-	return blk->ops->erase(blk, offset, count);
+	ret = blk->ops->erase(blk, offset, count);
+	if (ret)
+		return ret;
+
+	blk_stats_record_erase(blk, count);
+
+	return 0;
 }
 
 static struct cdev_operations block_ops = {
diff --git a/include/block.h b/include/block.h
index eb319b953d32..b57d99a3fc08 100644
--- a/include/block.h
+++ b/include/block.h
@@ -31,6 +31,12 @@ enum blk_type {
 
 const char *blk_type_str(enum blk_type);
 
+struct block_device_stats {
+	blkcnt_t read_sectors;
+	blkcnt_t write_sectors;
+	blkcnt_t erase_sectors;
+};
+
 struct block_device {
 	struct device *dev;
 	struct list_head list;
@@ -50,6 +56,10 @@ struct block_device {
 	struct cdev cdev;
 
 	bool need_reparse;
+
+#ifdef CONFIG_BLOCK_STATS
+	struct block_device_stats stats;
+#endif
 };
 
 #define BLOCKSIZE(blk)	(1u << (blk)->blockbits)
-- 
2.39.2




  parent reply	other threads:[~2024-07-31  8:16 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-07-31  8:05 [PATCH v2 00/10] mmc: add SD/eMMC erase support Ahmad Fatoum
2024-07-31  8:05 ` [PATCH v2 01/10] fs: give erase() a new erase_type parameter Ahmad Fatoum
2024-08-01 10:51   ` Sascha Hauer
2024-08-01 10:54     ` Ahmad Fatoum
2024-07-31  8:05 ` [PATCH v2 02/10] cdev: factor out range identical/overlap check Ahmad Fatoum
2024-07-31  8:05 ` [PATCH v2 03/10] block: factor out chunk_flush helper Ahmad Fatoum
2024-07-31  8:05 ` [PATCH v2 04/10] block: allow block devices to implement the cdev erase operation Ahmad Fatoum
2024-07-31  8:05 ` [PATCH v2 05/10] mci: turn bool members into bitfield in struct mci Ahmad Fatoum
2024-07-31  8:05 ` [PATCH v2 06/10] mci: describe more command structure in mci.h Ahmad Fatoum
2024-07-31  8:05 ` [PATCH v2 07/10] mci: core: use CONFIG_MCI_WRITE, not CONFIG_BLOCK_WRITE Ahmad Fatoum
2024-07-31  8:05 ` [PATCH v2 08/10] mci: add support for discarding write blocks Ahmad Fatoum
2024-08-01 11:27   ` Sascha Hauer
2024-07-31  8:05 ` [PATCH v2 09/10] commands: sync: add new command to flush cached writes Ahmad Fatoum
2024-07-31  8:05 ` Ahmad Fatoum [this message]
2024-08-01 10:49 ` [PATCH v2 00/10] mmc: add SD/eMMC erase support Sascha Hauer

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=20240731080510.364706-11-a.fatoum@pengutronix.de \
    --to=a.fatoum@pengutronix.de \
    --cc=barebox@lists.infradead.org \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox