summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libbcachefs.c14
-rw-r--r--tools-util.c126
-rw-r--r--tools-util.h2
3 files changed, 142 insertions, 0 deletions
diff --git a/libbcachefs.c b/libbcachefs.c
index 499badb..e55d8ec 100644
--- a/libbcachefs.c
+++ b/libbcachefs.c
@@ -258,6 +258,20 @@ struct bch_sb *bch2_format(struct bch_opt_strs fs_opt_strs,
SET_BCH_MEMBER_GROUP(m, idx + 1);
}
+ for (i = devs; i < devs + nr_devs; i++) {
+ struct bch_member *m = bch2_members_v2_get_mut(sb.sb, (i - devs));
+
+ for (unsigned j = 0; j < ARRAY_SIZE(m->iops); j++) {
+ int iops = benchmark_device(i->bdev, j);
+
+ if (iops < 0)
+ die("error benchmarking device %s", i->path);
+ if (!iops)
+ fprintf(stderr, "Warning device not performing any operations");
+ m->iops[j] = cpu_to_le32(iops);
+ }
+ }
+
SET_BCH_SB_FOREGROUND_TARGET(sb.sb,
parse_target(&sb, devs, nr_devs, fs_opt_strs.foreground_target));
SET_BCH_SB_BACKGROUND_TARGET(sb.sb,
diff --git a/tools-util.c b/tools-util.c
index f6e9a47..2f138c0 100644
--- a/tools-util.c
+++ b/tools-util.c
@@ -17,6 +17,7 @@
#include <blkid.h>
#include <uuid/uuid.h>
+#include <linux/random.h>
#include "libbcachefs.h"
#include "libbcachefs/bcachefs_ioctl.h"
#include "linux/sort.h"
@@ -681,3 +682,128 @@ struct bbpos bbpos_parse(char *buf)
ret.pos = bpos_parse(s);
return ret;
}
+
+struct benchmark_bios;
+
+struct benchmark_bio {
+ struct benchmark_bios *bios;
+ bool complete;
+ void *p;
+ size_t nr_bio_vecs;
+ struct bio bio;
+ struct bio_vec *bv;
+};
+
+struct benchmark_bios {
+ struct block_device *bdev;
+ enum bch_iops_measurement mode;
+ unsigned blocksize;
+ u64 nr_blocks;
+ u64 nr_done;
+ wait_queue_head_t wait;
+ struct benchmark_bio bios[64];
+};
+
+static void benchmark_device_endio(struct bio *bio)
+{
+ struct benchmark_bio *bbio = container_of(bio, struct benchmark_bio, bio);
+ struct benchmark_bios *bios = bbio->bios;
+
+ bbio->complete = true;
+
+ wake_up(&bios->wait);
+}
+
+static bool benchmark_submit(struct benchmark_bios *bios)
+{
+ bool submitted = false;
+
+ for (unsigned i = 0; i < ARRAY_SIZE(bios->bios); i++) {
+ struct bio *bio = &bios->bios[i].bio;
+
+ if (!bios->bios[i].complete)
+ continue;
+
+ bios->bios[i].complete = false;
+ bio_init(&bios->bios[i].bio, bios->bdev, bios->bios[i].bv, bios->bios[i].nr_bio_vecs, 0);
+ bio->bi_end_io = benchmark_device_endio;
+
+ bch2_bio_map(bio, bios->bios[i].p, bios->blocksize << 9);
+
+ switch (bios->mode) {
+ case BCH_IOPS_seqread:
+ bio->bi_opf = REQ_OP_READ;
+ bio->bi_iter.bi_sector = bios->nr_done * bios->blocksize;
+ break;
+ case BCH_IOPS_seqwrite:
+ bio->bi_opf = REQ_OP_WRITE;
+ bio->bi_iter.bi_sector = bios->nr_done * bios->blocksize;
+ break;
+ case BCH_IOPS_randread:
+ bio->bi_opf = REQ_OP_READ;
+ bio->bi_iter.bi_sector = get_random_u64() % bios->nr_blocks * bios->blocksize;// get random number
+ break;
+ case BCH_IOPS_randwrite:
+ bio->bi_opf = REQ_OP_WRITE;
+ bio->bi_iter.bi_sector = get_random_u64() % bios->nr_blocks * bios->blocksize;// get random number * bios->blocksize
+ break;
+ default:
+ BUG();
+ }
+
+ submit_bio(bio);
+
+ submitted = true;
+ bios->nr_done++;
+ }
+
+ return submitted;
+}
+
+static bool bios_are(struct benchmark_bios *bios, bool completed)
+{
+ for (unsigned i = 0; i < ARRAY_SIZE(bios->bios); i++)
+ if (bios->bios[i].complete == completed)
+ return true;
+ return false;
+}
+
+int benchmark_device(struct block_device *bdev, enum bch_iops_measurement mode)
+{
+ struct benchmark_bios bios;
+ unsigned i;
+
+ bios.bdev = bdev;
+ bios.mode = mode;
+ bios.blocksize = get_blocksize(bios.bdev->bd_buffered_fd) >> 9;
+ bios.nr_blocks = (get_size(bios.bdev->bd_buffered_fd) >> 9)/bios.blocksize;
+ bios.nr_done = 0;
+ init_waitqueue_head(&bios.wait);
+
+ for (i = 0; i < ARRAY_SIZE(bios.bios); i++) {
+ bios.bios[i].bios = &bios;
+ bios.bios[i].complete = true;
+ bios.bios[i].p = kmalloc(bios.blocksize << 9, GFP_KERNEL);
+ bios.bios[i].nr_bio_vecs = buf_pages(bios.bios[i].p, bios.blocksize << 9);
+ bios.bios[i].bv = kmalloc(bios.bios[i].nr_bio_vecs * sizeof(struct bio_vec), GFP_KERNEL);
+ }
+
+ struct timespec start_ts, now_ts;
+ clock_gettime(CLOCK_MONOTONIC, &start_ts);
+
+ u64 start = timespec_to_ns(&start_ts);
+
+ while (true) {
+ wait_event(bios.wait, bios_are(&bios, true));
+ benchmark_submit(&bios);
+
+ clock_gettime(CLOCK_MONOTONIC, &now_ts);
+ u64 now = timespec_to_ns(&now_ts);
+
+ if (now - start > 5 * NSEC_PER_SEC)
+ break;
+ }
+
+ wait_event(bios.wait, !bios_are(&bios, false));
+ return bios.nr_done / 5;
+}
diff --git a/tools-util.h b/tools-util.h
index 7a04c10..f807dbd 100644
--- a/tools-util.h
+++ b/tools-util.h
@@ -172,4 +172,6 @@ do { \
struct bpos bpos_parse(char *);
struct bbpos bbpos_parse(char *);
+int benchmark_device(struct block_device *bdev, enum bch_iops_measurement mode);
+
#endif /* _TOOLS_UTIL_H */