From 627b530059e07ce527750b9ea6cea4a48f155ff1 Mon Sep 17 00:00:00 2001 From: Ivan Shapovalov Date: Tue, 10 Dec 2024 04:44:19 +0400 Subject: [PATCH] zdb: add `--bin=(lsize|psize|asize)` arg to control histogram binning When counting blocks to generate block size histograms (`-bb`), accept a `--bin=` argument to force placing blocks into all three bins based on *this* size. E.g. with `--bin=lsize`, a block with lsize=512K, psize=128K, asize=256K will be placed into the "512K" bin in all three output columns. This way, by looking at the "512K" row the user will be able to determine how well was ZFS able to compress blocks of this logical size. Conversely, with `--bin=psize`, by looking at the "128K" row the user will be able to determine how much overhead was incurred for storage of blocks of this physical size. Reviewed-by: Brian Behlendorf Signed-off-by: Ivan Shapovalov Closes #16999 --- cmd/zdb/zdb.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++--- man/man8/zdb.8 | 10 +++++++++ 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/cmd/zdb/zdb.c b/cmd/zdb/zdb.c index ab3b9191a..38439241b 100644 --- a/cmd/zdb/zdb.c +++ b/cmd/zdb/zdb.c @@ -108,6 +108,7 @@ extern uint_t zfs_btree_verify_intensity; enum { ARG_ALLOCATED = 256, + ARG_BLOCK_BIN_MODE, }; static const char cmdname[] = "zdb"; @@ -133,6 +134,13 @@ static objset_t *os; static boolean_t kernel_init_done; static boolean_t corruption_found = B_FALSE; +static enum { + BIN_AUTO = 0, + BIN_PSIZE, + BIN_LSIZE, + BIN_ASIZE, +} block_bin_mode = BIN_AUTO; + static void snprintf_blkptr_compact(char *, size_t, const blkptr_t *, boolean_t); static void mos_obj_refd(uint64_t); @@ -751,6 +759,8 @@ usage(void) (void) fprintf(stderr, " Options to control amount of output:\n"); (void) fprintf(stderr, " -b --block-stats " "block statistics\n"); + (void) fprintf(stderr, " --bin=(lsize|psize|asize) " + "bin blocks based on this size in all three columns\n"); (void) fprintf(stderr, " -B --backup " "backup stream\n"); (void) fprintf(stderr, " -c --checksum " @@ -5816,6 +5826,20 @@ dump_size_histograms(zdb_cb_t *zcb) (void) printf("\nBlock Size Histogram\n"); + switch (block_bin_mode) { + case BIN_PSIZE: + printf("(note: all categories are binned by %s)\n", "psize"); + break; + case BIN_LSIZE: + printf("(note: all categories are binned by %s)\n", "lsize"); + break; + case BIN_ASIZE: + printf("(note: all categories are binned by %s)\n", "asize"); + break; + default: + printf("(note: all categories are binned separately)\n"); + break; + } /* * Print the first line titles */ @@ -6164,24 +6188,38 @@ skipped: [BPE_GET_PSIZE(bp)]++; return; } + /* * The binning histogram bins by powers of two up to * SPA_MAXBLOCKSIZE rather than creating bins for * every possible blocksize found in the pool. */ - int bin = highbit64(BP_GET_PSIZE(bp)) - 1; + int bin; + + switch (block_bin_mode) { + case BIN_PSIZE: bin = highbit64(BP_GET_PSIZE(bp)) - 1; break; + case BIN_LSIZE: bin = highbit64(BP_GET_LSIZE(bp)) - 1; break; + case BIN_ASIZE: bin = highbit64(BP_GET_ASIZE(bp)) - 1; break; + case BIN_AUTO: break; + default: PANIC("bad block_bin_mode"); abort(); + } + + if (block_bin_mode == BIN_AUTO) + bin = highbit64(BP_GET_PSIZE(bp)) - 1; zcb->zcb_psize_count[bin]++; zcb->zcb_psize_len[bin] += BP_GET_PSIZE(bp); zcb->zcb_psize_total += BP_GET_PSIZE(bp); - bin = highbit64(BP_GET_LSIZE(bp)) - 1; + if (block_bin_mode == BIN_AUTO) + bin = highbit64(BP_GET_LSIZE(bp)) - 1; zcb->zcb_lsize_count[bin]++; zcb->zcb_lsize_len[bin] += BP_GET_LSIZE(bp); zcb->zcb_lsize_total += BP_GET_LSIZE(bp); - bin = highbit64(BP_GET_ASIZE(bp)) - 1; + if (block_bin_mode == BIN_AUTO) + bin = highbit64(BP_GET_ASIZE(bp)) - 1; zcb->zcb_asize_count[bin]++; zcb->zcb_asize_len[bin] += BP_GET_ASIZE(bp); @@ -9429,6 +9467,8 @@ main(int argc, char **argv) {"zstd-headers", no_argument, NULL, 'Z'}, {"allocated-map", no_argument, NULL, ARG_ALLOCATED}, + {"bin", required_argument, NULL, + ARG_BLOCK_BIN_MODE}, {0, 0, 0, 0} }; @@ -9542,6 +9582,20 @@ main(int argc, char **argv) case 'x': vn_dumpdir = optarg; break; + case ARG_BLOCK_BIN_MODE: + if (strcmp(optarg, "lsize") == 0) { + block_bin_mode = BIN_LSIZE; + } else if (strcmp(optarg, "psize") == 0) { + block_bin_mode = BIN_PSIZE; + } else if (strcmp(optarg, "asize") == 0) { + block_bin_mode = BIN_ASIZE; + } else { + (void) fprintf(stderr, + "--bin=\"%s\" must be one of \"lsize\", " + "\"psize\" or \"asize\"\n", optarg); + usage(); + } + break; default: usage(); break; diff --git a/man/man8/zdb.8 b/man/man8/zdb.8 index c3290ea14..c0ec2c81e 100644 --- a/man/man8/zdb.8 +++ b/man/man8/zdb.8 @@ -144,6 +144,16 @@ subcommand. Display statistics regarding the number, size .Pq logical, physical and allocated and deduplication of blocks. +.It Fl -bin Ns = Ns ( Li lsize Ns | Ns Li psize Ns | Ns Li asize ) +When used with +.Fl bb , +sort blocks into all three bins according to the given size (instead of binning +a block for each size separately). +.Pp +For instance, with +.Fl -bin Ns = Ns Li lsize , +a block with lsize of 16K and psize of 4K will be added to the 16K bin +in all three columns. .It Fl B , -backup Generate a backup stream, similar to .Nm zfs Cm send ,