From patchwork Fri May 26 01:50:53 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13256159 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 46C78C7EE29 for ; Fri, 26 May 2023 01:50:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233928AbjEZBu5 (ORCPT ); Thu, 25 May 2023 21:50:57 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40572 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229523AbjEZBu5 (ORCPT ); Thu, 25 May 2023 21:50:57 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F065F19A for ; Thu, 25 May 2023 18:50:54 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 5E2D460B6C for ; Fri, 26 May 2023 01:50:54 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id C0C47C433D2; Fri, 26 May 2023 01:50:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1685065853; bh=5H/8WvOaADKzOns3FfWCMA7NIHimVxkNSYbfYfePZ+s=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=UzUaBObbyP+GGwXaTxmkBR+CNdaGpNL2NoBg8TBczp/xoca4zzjxRhR0tKXGpXitK zzOnW/N21q4U93+U3AtEeruFyFQmh+dA5fVLqxQqtBOqoxJeUCyBozHbu7ugjIyLqp z6DCsnE+d+QivUrg/YnBTFyK8o3yAzlextfcAs0fC2snJi69h5LYtMWKxv5q1iR/us dGHGceIxD1Dbgi9ttFZ0QlZvt66OQHA/bHTxNDuWC58z7k3EYJke7CMGhdMjQFjDgo YlZe3N5JoeXWdXTvzr0AxcmK+cFpPxOy+qhFZ3QTX3aJ0RON74MY2luQRHmn+JfOfc /tNN/2vzyHgxw== Date: Thu, 25 May 2023 18:50:53 -0700 Subject: [PATCH 1/7] libfrog: hoist free space histogram code From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <168506073481.3745433.8196427478440084323.stgit@frogsfrogsfrogs> In-Reply-To: <168506073466.3745433.1072164718437572976.stgit@frogsfrogsfrogs> References: <168506073466.3745433.1072164718437572976.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Darrick J. Wong Combine the two free space histograms in xfs_db and xfs_spaceman into a single implementation. Signed-off-by: Darrick J. Wong --- db/freesp.c | 83 +++++-------------------------- libfrog/Makefile | 2 + libfrog/histogram.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++ libfrog/histogram.h | 50 +++++++++++++++++++ spaceman/freesp.c | 93 +++++++++-------------------------- 5 files changed, 225 insertions(+), 138 deletions(-) create mode 100644 libfrog/histogram.c create mode 100644 libfrog/histogram.h diff --git a/db/freesp.c b/db/freesp.c index 6f234666584..7e71bf47a16 100644 --- a/db/freesp.c +++ b/db/freesp.c @@ -12,14 +12,7 @@ #include "output.h" #include "init.h" #include "malloc.h" - -typedef struct histent -{ - int low; - int high; - long long count; - long long blocks; -} histent_t; +#include "libfrog/histogram.h" static void addhistent(int h); static void addtohist(xfs_agnumber_t agno, xfs_agblock_t agbno, @@ -46,13 +39,10 @@ static int alignment; static int countflag; static int dumpflag; static int equalsize; -static histent_t *hist; -static int histcount; +static struct histogram freesp_hist; static int multsize; static int seen1; static int summaryflag; -static long long totblocks; -static long long totexts; static const cmdinfo_t freesp_cmd = { "freesp", NULL, freesp_f, 0, -1, 0, @@ -93,18 +83,13 @@ freesp_f( if (inaglist(agno)) scan_ag(agno); } - if (histcount) + if (hist_buckets(&freesp_hist)) printhist(); - if (summaryflag) { - dbprintf(_("total free extents %lld\n"), totexts); - dbprintf(_("total free blocks %lld\n"), totblocks); - dbprintf(_("average free extent size %g\n"), - (double)totblocks / (double)totexts); - } + if (summaryflag) + hist_summarize(&freesp_hist); if (aglist) xfree(aglist); - if (hist) - xfree(hist); + hist_free(&freesp_hist); return 0; } @@ -132,10 +117,9 @@ init( int speced = 0; agcount = countflag = dumpflag = equalsize = multsize = optind = 0; - histcount = seen1 = summaryflag = 0; - totblocks = totexts = 0; + seen1 = summaryflag = 0; aglist = NULL; - hist = NULL; + while ((c = getopt(argc, argv, "A:a:bcde:h:m:s")) != EOF) { switch (c) { case 'A': @@ -163,7 +147,7 @@ init( speced = 1; break; case 'h': - if (speced && !histcount) + if (speced && hist_buckets(&freesp_hist) == 0) return usage(); addhistent(atoi(optarg)); speced = 1; @@ -339,14 +323,7 @@ static void addhistent( int h) { - hist = xrealloc(hist, (histcount + 1) * sizeof(*hist)); - if (h == 0) - h = 1; - hist[histcount].low = h; - hist[histcount].count = hist[histcount].blocks = 0; - histcount++; - if (h == 1) - seen1 = 1; + hist_add_bucket(&freesp_hist, h); } static void @@ -355,30 +332,12 @@ addtohist( xfs_agblock_t agbno, xfs_extlen_t len) { - int i; - if (alignment && (XFS_AGB_TO_FSB(mp,agno,agbno) % alignment)) return; if (dumpflag) dbprintf("%8d %8d %8d\n", agno, agbno, len); - totexts++; - totblocks += len; - for (i = 0; i < histcount; i++) { - if (hist[i].high >= len) { - hist[i].count++; - hist[i].blocks += len; - break; - } - } -} - -static int -hcmp( - const void *a, - const void *b) -{ - return ((histent_t *)a)->low - ((histent_t *)b)->low; + hist_add(&freesp_hist, len); } static void @@ -387,6 +346,7 @@ histinit( { int i; + hist_init(&freesp_hist); if (equalsize) { for (i = 1; i < maxlen; i += equalsize) addhistent(i); @@ -396,27 +356,12 @@ histinit( } else { if (!seen1) addhistent(1); - qsort(hist, histcount, sizeof(*hist), hcmp); - } - for (i = 0; i < histcount; i++) { - if (i < histcount - 1) - hist[i].high = hist[i + 1].low - 1; - else - hist[i].high = maxlen; } + hist_prepare(&freesp_hist, maxlen); } static void printhist(void) { - int i; - - dbprintf("%7s %7s %7s %7s %6s\n", - _("from"), _("to"), _("extents"), _("blocks"), _("pct")); - for (i = 0; i < histcount; i++) { - if (hist[i].count) - dbprintf("%7d %7d %7lld %7lld %6.2f\n", hist[i].low, - hist[i].high, hist[i].count, hist[i].blocks, - hist[i].blocks * 100.0 / totblocks); - } + hist_print(&freesp_hist); } diff --git a/libfrog/Makefile b/libfrog/Makefile index e14e62e4d1b..ad32b0674b2 100644 --- a/libfrog/Makefile +++ b/libfrog/Makefile @@ -20,6 +20,7 @@ convert.c \ crc32.c \ file_exchange.c \ fsgeom.c \ +histogram.c \ list_sort.c \ linux.c \ logging.c \ @@ -44,6 +45,7 @@ crc32table.h \ dahashselftest.h \ file_exchange.h \ fsgeom.h \ +histogram.h \ logging.h \ paths.h \ projects.h \ diff --git a/libfrog/histogram.c b/libfrog/histogram.c new file mode 100644 index 00000000000..e854ac5e467 --- /dev/null +++ b/libfrog/histogram.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. + * Copyright (c) 2012 Red Hat, Inc. + * Copyright (c) 2017-2023 Oracle. + * All Rights Reserved. + */ +#include "xfs.h" +#include +#include +#include "platform_defs.h" +#include "libfrog/histogram.h" + +/* Create a new bucket with the given low value. */ +int +hist_add_bucket( + struct histogram *hs, + long long bucket_low) +{ + struct histent *buckets; + + if (hs->nr_buckets == INT_MAX) + return EFBIG; + + buckets = realloc(hs->buckets, + (hs->nr_buckets + 1) * sizeof(struct histent)); + if (!buckets) + return errno; + + hs->buckets = buckets; + hs->buckets[hs->nr_buckets].low = bucket_low; + hs->buckets[hs->nr_buckets].count = buckets[hs->nr_buckets].blocks = 0; + hs->nr_buckets++; + return 0; +} + +/* Add an observation to the histogram. */ +void +hist_add( + struct histogram *hs, + long long len) +{ + unsigned int i; + + hs->totexts++; + hs->totblocks += len; + for (i = 0; i < hs->nr_buckets; i++) { + if (hs->buckets[i].high >= len) { + hs->buckets[i].count++; + hs->buckets[i].blocks += len; + break; + } + } +} + +static int +histent_cmp( + const void *a, + const void *b) +{ + const struct histent *ha = a; + const struct histent *hb = b; + + if (ha->low < hb->low) + return -1; + if (ha->low > hb->low) + return 1; + return 0; +} + +/* Prepare a histogram for bucket configuration. */ +void +hist_init( + struct histogram *hs) +{ + memset(hs, 0, sizeof(struct histogram)); +} + +/* Prepare a histogram to receive data observations. */ +void +hist_prepare( + struct histogram *hs, + long long maxlen) +{ + unsigned int i; + + qsort(hs->buckets, hs->nr_buckets, sizeof(struct histent), histent_cmp); + + for (i = 0; i < hs->nr_buckets; i++) { + if (i < hs->nr_buckets - 1) + hs->buckets[i].high = hs->buckets[i + 1].low - 1; + else + hs->buckets[i].high = maxlen; + } +} + +/* Free all data associated with a histogram. */ +void +hist_free( + struct histogram *hs) +{ + free(hs->buckets); + memset(hs, 0, sizeof(struct histogram)); +} + +/* Dump a histogram to stdout. */ +void +hist_print( + const struct histogram *hs) +{ + unsigned int i; + + printf("%7s %7s %7s %7s %6s\n", + _("from"), _("to"), _("extents"), _("blocks"), _("pct")); + for (i = 0; i < hs->nr_buckets; i++) { + if (hs->buckets[i].count == 0) + continue; + + printf("%7lld %7lld %7lld %7lld %6.2f\n", + hs->buckets[i].low, hs->buckets[i].high, + hs->buckets[i].count, hs->buckets[i].blocks, + hs->buckets[i].blocks * 100.0 / hs->totblocks); + } +} + +/* Summarize the contents of the histogram. */ +void +hist_summarize( + const struct histogram *hs) +{ + printf(_("total free extents %lld\n"), hs->totexts); + printf(_("total free blocks %lld\n"), hs->totblocks); + printf(_("average free extent size %g\n"), + (double)hs->totblocks / (double)hs->totexts); +} diff --git a/libfrog/histogram.h b/libfrog/histogram.h new file mode 100644 index 00000000000..c215bdaa98c --- /dev/null +++ b/libfrog/histogram.h @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. + * Copyright (c) 2012 Red Hat, Inc. + * Copyright (c) 2017-2023 Oracle. + * All Rights Reserved. + */ +#ifndef __LIBFROG_HISTOGRAM_H__ +#define __LIBFROG_HISTOGRAM_H__ + +struct histent +{ + /* Low and high size of this bucket */ + long long low; + long long high; + + /* Count of observations recorded */ + long long count; + + /* Sum of blocks recorded */ + long long blocks; +}; + +struct histogram { + /* Sum of all blocks recorded */ + long long totblocks; + + /* Count of all observations recorded */ + long long totexts; + + struct histent *buckets; + + /* Number of buckets */ + unsigned int nr_buckets; +}; + +int hist_add_bucket(struct histogram *hs, long long bucket_low); +void hist_add(struct histogram *hs, long long len); +void hist_init(struct histogram *hs); +void hist_prepare(struct histogram *hs, long long maxlen); +void hist_free(struct histogram *hs); +void hist_print(const struct histogram *hs); +void hist_summarize(const struct histogram *hs); + +static inline unsigned int hist_buckets(const struct histogram *hs) +{ + return hs->nr_buckets; +} + +#endif /* __LIBFROG_HISTOGRAM_H__ */ diff --git a/spaceman/freesp.c b/spaceman/freesp.c index 70dcdb5c923..996cbb7e2c0 100644 --- a/spaceman/freesp.c +++ b/spaceman/freesp.c @@ -15,76 +15,52 @@ #include "libfrog/paths.h" #include "space.h" #include "input.h" - -struct histent -{ - long long low; - long long high; - long long count; - long long blocks; -}; +#include "libfrog/histogram.h" static int agcount; static xfs_agnumber_t *aglist; -static struct histent *hist; +static struct histogram freesp_hist; static int dumpflag; static long long equalsize; static long long multsize; -static int histcount; static int seen1; static int summaryflag; static int gflag; static bool rtflag; -static long long totblocks; -static long long totexts; static cmdinfo_t freesp_cmd; -static void +static inline void addhistent( long long h) { - if (histcount == INT_MAX) { + int error; + + error = hist_add_bucket(&freesp_hist, h); + if (error == EFBIG) { printf(_("Too many histogram buckets.\n")); return; } - hist = realloc(hist, (histcount + 1) * sizeof(*hist)); + if (error) { + printf("%s\n", strerror(error)); + return; + } + if (h == 0) h = 1; - hist[histcount].low = h; - hist[histcount].count = hist[histcount].blocks = 0; - histcount++; if (h == 1) seen1 = 1; } -static void +static inline void addtohist( xfs_agnumber_t agno, xfs_agblock_t agbno, off64_t len) { - long i; - if (dumpflag) printf("%8d %8d %8"PRId64"\n", agno, agbno, len); - totexts++; - totblocks += len; - for (i = 0; i < histcount; i++) { - if (hist[i].high >= len) { - hist[i].count++; - hist[i].blocks += len; - break; - } - } -} - -static int -hcmp( - const void *a, - const void *b) -{ - return ((struct histent *)a)->low - ((struct histent *)b)->low; + hist_add(&freesp_hist, len); } static void @@ -93,6 +69,7 @@ histinit( { long long i; + hist_init(&freesp_hist); if (equalsize) { for (i = 1; i < maxlen; i += equalsize) addhistent(i); @@ -102,29 +79,14 @@ histinit( } else { if (!seen1) addhistent(1); - qsort(hist, histcount, sizeof(*hist), hcmp); - } - for (i = 0; i < histcount; i++) { - if (i < histcount - 1) - hist[i].high = hist[i + 1].low - 1; - else - hist[i].high = maxlen; } + hist_prepare(&freesp_hist, maxlen); } -static void +static inline void printhist(void) { - int i; - - printf("%7s %7s %7s %7s %6s\n", - _("from"), _("to"), _("extents"), _("blocks"), _("pct")); - for (i = 0; i < histcount; i++) { - if (hist[i].count) - printf("%7lld %7lld %7lld %7lld %6.2f\n", hist[i].low, - hist[i].high, hist[i].count, hist[i].blocks, - hist[i].blocks * 100.0 / totblocks); - } + hist_print(&freesp_hist); } static int @@ -255,10 +217,8 @@ init( int speced = 0; /* only one of -b -e -h or -m */ agcount = dumpflag = equalsize = multsize = optind = gflag = 0; - histcount = seen1 = summaryflag = 0; - totblocks = totexts = 0; + seen1 = summaryflag = 0; aglist = NULL; - hist = NULL; rtflag = false; while ((c = getopt(argc, argv, "a:bde:gh:m:rs")) != EOF) { @@ -287,7 +247,7 @@ init( gflag++; break; case 'h': - if (speced && !histcount) + if (speced && hist_buckets(&freesp_hist) == 0) goto many_spec; /* addhistent increments histcount */ x = cvt_s64(optarg, 0); @@ -345,18 +305,13 @@ freesp_f( if (inaglist(agno)) scan_ag(agno); } - if (histcount && !gflag) + if (hist_buckets(&freesp_hist) > 0 && !gflag) printhist(); - if (summaryflag) { - printf(_("total free extents %lld\n"), totexts); - printf(_("total free blocks %lld\n"), totblocks); - printf(_("average free extent size %g\n"), - (double)totblocks / (double)totexts); - } + if (summaryflag) + hist_summarize(&freesp_hist); if (aglist) free(aglist); - if (hist) - free(hist); + hist_free(&freesp_hist); return 0; } From patchwork Fri May 26 01:51:08 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13256160 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2BAF0C7EE29 for ; Fri, 26 May 2023 01:51:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229523AbjEZBvL (ORCPT ); Thu, 25 May 2023 21:51:11 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40804 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233533AbjEZBvL (ORCPT ); Thu, 25 May 2023 21:51:11 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 55909199 for ; Thu, 25 May 2023 18:51:10 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id E7B5F64868 for ; Fri, 26 May 2023 01:51:09 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 53A8AC433EF; Fri, 26 May 2023 01:51:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1685065869; bh=Qc30zDkAdAS3qOXbgCHR4Ti+ENVvKs2N8Pj4RQalnBQ=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=gj0Ue39gRZaWJO7uay16UMCejvWosL7oyfzayOaBUEopbIA7LEFZ2Bok1QkndE6wZ Nwebm1BDFkrDfNOsbzofJ3BvNv6F+Cyw1yUQfZIrWkxdLrlGEArcDsWKnsD/KgVtKK KSXf1SfNAEMZ+mrqHk9rVQTKMdZTlLKhUuRGxYBWDn9L5dKA+TzfirSwIJv+/mK+l3 3oGltsc97EwQZ33J/tF+S4B2wv4LPyDC71CUbVlFmBg4qQg67EUbaW+d2JSbfag+qi SO83gtbWYyeXIOttgr2YKMghhdlaQDen8lCuCsiaWczAsl9EHa+jcG7rUbT1qqnukD gtOiQgw0gnkIA== Date: Thu, 25 May 2023 18:51:08 -0700 Subject: [PATCH 2/7] libfrog: print wider columns for free space histogram From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <168506073494.3745433.15976752668175255977.stgit@frogsfrogsfrogs> In-Reply-To: <168506073466.3745433.1072164718437572976.stgit@frogsfrogsfrogs> References: <168506073466.3745433.1072164718437572976.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Darrick J. Wong The values reported here can reach very large values, so compute the column width dynamically. Signed-off-by: Darrick J. Wong --- libfrog/histogram.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/libfrog/histogram.c b/libfrog/histogram.c index e854ac5e467..458b414d0f9 100644 --- a/libfrog/histogram.c +++ b/libfrog/histogram.c @@ -108,17 +108,41 @@ void hist_print( const struct histogram *hs) { + unsigned int from_w, to_w, extents_w, blocks_w; unsigned int i; - printf("%7s %7s %7s %7s %6s\n", - _("from"), _("to"), _("extents"), _("blocks"), _("pct")); + from_w = to_w = extents_w = blocks_w = 7; + for (i = 0; i < hs->nr_buckets; i++) { + char buf[256]; + + if (!hs->buckets[i].count) + continue; + + snprintf(buf, sizeof(buf) - 1, "%lld", hs->buckets[i].low); + from_w = max(from_w, strlen(buf)); + + snprintf(buf, sizeof(buf) - 1, "%lld", hs->buckets[i].high); + to_w = max(to_w, strlen(buf)); + + snprintf(buf, sizeof(buf) - 1, "%lld", hs->buckets[i].count); + extents_w = max(extents_w, strlen(buf)); + + snprintf(buf, sizeof(buf) - 1, "%lld", hs->buckets[i].blocks); + blocks_w = max(blocks_w, strlen(buf)); + } + + printf("%*s %*s %*s %*s %6s\n", + from_w, _("from"), to_w, _("to"), extents_w, _("extents"), + blocks_w, _("blocks"), _("pct")); for (i = 0; i < hs->nr_buckets; i++) { if (hs->buckets[i].count == 0) continue; - printf("%7lld %7lld %7lld %7lld %6.2f\n", - hs->buckets[i].low, hs->buckets[i].high, - hs->buckets[i].count, hs->buckets[i].blocks, + printf("%*lld %*lld %*lld %*lld %6.2f\n", + from_w, hs->buckets[i].low, + to_w, hs->buckets[i].high, + extents_w, hs->buckets[i].count, + blocks_w, hs->buckets[i].blocks, hs->buckets[i].blocks * 100.0 / hs->totblocks); } } From patchwork Fri May 26 01:51:24 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13256161 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id ED2B8C7EE29 for ; Fri, 26 May 2023 01:51:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229646AbjEZBv3 (ORCPT ); Thu, 25 May 2023 21:51:29 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40872 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233533AbjEZBv2 (ORCPT ); Thu, 25 May 2023 21:51:28 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F39BE194 for ; Thu, 25 May 2023 18:51:25 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 7FD5164C3E for ; Fri, 26 May 2023 01:51:25 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id DB535C433EF; Fri, 26 May 2023 01:51:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1685065884; bh=v3KGvNRjafQ76kx7nPUxMJ+AX9i7Z8wd4tep/ZXPELg=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=iowXNVfFLDaTVH+5EUT6i5YJqW3P12VGdGgPfW9suRH1BQKXV3DOkSEkWsgjAW6go TKQ2tyuoK8+/v3sGl2b7OQI+ZZgTKjAOc5QpX6d1bOBB+h0xkk1qMG+Slulh1ccHNX b6DN78yfL6o/EuxFpTsBpoOnL6bx1MsEfSK0wGh0cCyP+/dRHxHqmFH3dLPthzSfP6 Z35LpwVGTm5i/pohWfVFPa5xHwDzEjuwCdXBH5N+jDMwbZR9JRkwKd8095JlEQ3FKu 7XP2H0wMeHfFDvpjegK5ZSAWoAW2prZM1xbqxR00yEBHU6Ixk301lYETd/XtKe6BJf fX5ARIMXfvdqg== Date: Thu, 25 May 2023 18:51:24 -0700 Subject: [PATCH 3/7] libfrog: print cdf of free space buckets From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <168506073507.3745433.8242934070876734847.stgit@frogsfrogsfrogs> In-Reply-To: <168506073466.3745433.1072164718437572976.stgit@frogsfrogsfrogs> References: <168506073466.3745433.1072164718437572976.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Darrick J. Wong Print the cumulative distribution function of the free space buckets in reverse order. Signed-off-by: Darrick J. Wong --- libfrog/histogram.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/libfrog/histogram.c b/libfrog/histogram.c index 458b414d0f9..ff780606011 100644 --- a/libfrog/histogram.c +++ b/libfrog/histogram.c @@ -103,13 +103,64 @@ hist_free( memset(hs, 0, sizeof(struct histogram)); } +/* + * Compute the CDF of the free space in decreasing order of extent length. + * This enables users to determine how much free space is not in the long tail + * of small extents, e.g. 98% of the free space extents are larger than 31 + * blocks. + */ +static int +hist_cdf( + const struct histogram *hs, + struct histogram *cdf) +{ + struct histent *buckets; + int i = hs->nr_buckets - 1; + + ASSERT(cdf->nr_buckets == 0); + ASSERT(hs->nr_buckets < INT_MAX); + + if (hs->nr_buckets == 0) + return 0; + + buckets = calloc(hs->nr_buckets, sizeof(struct histent)); + if (!buckets) + return errno; + + memset(cdf, 0, sizeof(struct histogram)); + cdf->buckets = buckets; + + cdf->buckets[i].count = hs->buckets[i].count; + cdf->buckets[i].blocks = hs->buckets[i].blocks; + i--; + + while (i >= 0) { + cdf->buckets[i].count = hs->buckets[i].count + + cdf->buckets[i + 1].count; + + cdf->buckets[i].blocks = hs->buckets[i].blocks + + cdf->buckets[i + 1].blocks; + i--; + } + + return 0; +} + /* Dump a histogram to stdout. */ void hist_print( const struct histogram *hs) { + struct histogram cdf = { }; unsigned int from_w, to_w, extents_w, blocks_w; unsigned int i; + int error; + + error = hist_cdf(hs, &cdf); + if (error) { + printf(_("histogram cdf: %s\n"), strerror(error)); + return; + } from_w = to_w = extents_w = blocks_w = 7; for (i = 0; i < hs->nr_buckets; i++) { @@ -131,20 +182,24 @@ hist_print( blocks_w = max(blocks_w, strlen(buf)); } - printf("%*s %*s %*s %*s %6s\n", + printf("%*s %*s %*s %*s %6s %6s %6s\n", from_w, _("from"), to_w, _("to"), extents_w, _("extents"), - blocks_w, _("blocks"), _("pct")); + blocks_w, _("blocks"), _("pct"), _("blkcdf"), _("extcdf")); for (i = 0; i < hs->nr_buckets; i++) { if (hs->buckets[i].count == 0) continue; - printf("%*lld %*lld %*lld %*lld %6.2f\n", + printf("%*lld %*lld %*lld %*lld %6.2f %6.2f %6.2f\n", from_w, hs->buckets[i].low, to_w, hs->buckets[i].high, extents_w, hs->buckets[i].count, blocks_w, hs->buckets[i].blocks, - hs->buckets[i].blocks * 100.0 / hs->totblocks); + hs->buckets[i].blocks * 100.0 / hs->totblocks, + cdf.buckets[i].blocks * 100.0 / hs->totblocks, + cdf.buckets[i].count * 100.0 / hs->totexts); } + + hist_free(&cdf); } /* Summarize the contents of the histogram. */ From patchwork Fri May 26 01:51:40 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13256162 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BDCF2C77B7E for ; Fri, 26 May 2023 01:51:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233533AbjEZBvm (ORCPT ); Thu, 25 May 2023 21:51:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40912 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229865AbjEZBvm (ORCPT ); Thu, 25 May 2023 21:51:42 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 76D4A189 for ; Thu, 25 May 2023 18:51:41 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 1DA6364C3E for ; Fri, 26 May 2023 01:51:41 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 779AFC433EF; Fri, 26 May 2023 01:51:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1685065900; bh=O1HZRM1sF7vpjikCvNtQlHI5+noMrzUOouoYC1QnqRc=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=o+bPo+VjZoG3R1siGSrrMf/qqfic4I5SGh6et1djTVuxKN9EIqlRac2dwTelFXqVW z/hu2b0ODBwXiV3CjmfgdfDQCm18HijhjqsiT4rbho2P9dZ7wjpznKo9wWl6ZZQkcS YuCj1vZE2rU5DOn0bloRjFpPwJztjhNDdkMQhGgkc/V5kc4AIb2lWEvgPhjxjaeGyf /ITLJcmYKf5L/XzQ2Tv+BBYMde/x6IHfAm7IqWXy/uvoiPGh1Ply7JzvYQErBz5SSS RGwoDVbh9MHNamVYnmREA1XnXdVVKpCxxvuDeH9MhiAp0zQLp4W8960hkNuZtCb3LL kT04gO3MQRGCA== Date: Thu, 25 May 2023 18:51:40 -0700 Subject: [PATCH 4/7] xfs_scrub: don't close stdout when closing the progress bar From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <168506073520.3745433.11580917963734545850.stgit@frogsfrogsfrogs> In-Reply-To: <168506073466.3745433.1072164718437572976.stgit@frogsfrogsfrogs> References: <168506073466.3745433.1072164718437572976.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Darrick J. Wong When we're tearing down the progress bar file stream, check that it's not an alias of stdout before closing it. Signed-off-by: Darrick J. Wong --- scrub/xfs_scrub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scrub/xfs_scrub.c b/scrub/xfs_scrub.c index 73f82ef0c8d..f07a1960e57 100644 --- a/scrub/xfs_scrub.c +++ b/scrub/xfs_scrub.c @@ -835,7 +835,7 @@ main( if (ctx.runtime_errors) ret |= SCRUB_RET_OPERROR; phase_end(&all_pi, 0); - if (progress_fp) + if (progress_fp && fileno(progress_fp) != 1) fclose(progress_fp); unicrash_unload(); From patchwork Fri May 26 01:51:55 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13256163 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BCBCBC77B7E for ; Fri, 26 May 2023 01:51:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229865AbjEZBv6 (ORCPT ); Thu, 25 May 2023 21:51:58 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40974 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233833AbjEZBv6 (ORCPT ); Thu, 25 May 2023 21:51:58 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3D853189 for ; Thu, 25 May 2023 18:51:57 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id C637364C3E for ; Fri, 26 May 2023 01:51:56 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 32DDAC433EF; Fri, 26 May 2023 01:51:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1685065916; bh=2d+9p106mN0bS6FZ8X9Ba+GMTdZ2SrmU8dgpnogqyUU=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=jwkCy2ze5ObbVjXmjGJaXx0ndeE1+fPNFzua+GedlrrR31WwER36xaMPGP40nAIjX M/zMUxHiF3uoSxRH2quTmllm6VjidEg5DqgPa1sgTbMMRhG8jI7EuBYF9wBgnDLV/t itOvZeCEzo3XBCFYZ5PGrlour/cZWht9OM/cI89EvYOuNAnYPIr5PI2Z9DkTxRI/lc 8O41dzpW3fDKYuNhN4LYQTvRMj6PyrDYTgnp2eIXfjS8LkmCQqoVmIfBebLriJRw+F uuU5mRUSw79uDU9CP3qCoW/fA21FG9/BhgcZO6HmEAYO1dqFlrlyh3mw2k+JYH3mj4 JIqx0VFp/d9Jg== Date: Thu, 25 May 2023 18:51:55 -0700 Subject: [PATCH 5/7] xfs_scrub: remove pointless spacemap.c arguments From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <168506073533.3745433.7207577103762464307.stgit@frogsfrogsfrogs> In-Reply-To: <168506073466.3745433.1072164718437572976.stgit@frogsfrogsfrogs> References: <168506073466.3745433.1072164718437572976.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Darrick J. Wong Remove unused parameters from the full-device spacemap scan functions. Signed-off-by: Darrick J. Wong --- scrub/spacemap.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/scrub/spacemap.c b/scrub/spacemap.c index 2c0b6d7bad1..4bac0ba48de 100644 --- a/scrub/spacemap.c +++ b/scrub/spacemap.c @@ -132,7 +132,6 @@ scan_ag_rmaps( static void scan_dev_rmaps( struct scrub_ctx *ctx, - int idx, dev_t dev, struct scan_blocks *sbx) { @@ -170,7 +169,7 @@ scan_rt_rmaps( { struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx; - scan_dev_rmaps(ctx, agno, ctx->fsinfo.fs_rtdev, arg); + scan_dev_rmaps(ctx, ctx->fsinfo.fs_rtdev, arg); } /* Iterate all the reverse mappings of the log device. */ @@ -182,7 +181,7 @@ scan_log_rmaps( { struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx; - scan_dev_rmaps(ctx, agno, ctx->fsinfo.fs_logdev, arg); + scan_dev_rmaps(ctx, ctx->fsinfo.fs_logdev, arg); } /* @@ -210,8 +209,7 @@ scrub_scan_all_spacemaps( return ret; } if (ctx->fsinfo.fs_rt) { - ret = -workqueue_add(&wq, scan_rt_rmaps, - ctx->mnt.fsgeom.agcount + 1, &sbx); + ret = -workqueue_add(&wq, scan_rt_rmaps, 0, &sbx); if (ret) { sbx.aborted = true; str_liberror(ctx, ret, _("queueing rtdev fsmap work")); @@ -219,8 +217,7 @@ scrub_scan_all_spacemaps( } } if (ctx->fsinfo.fs_log) { - ret = -workqueue_add(&wq, scan_log_rmaps, - ctx->mnt.fsgeom.agcount + 2, &sbx); + ret = -workqueue_add(&wq, scan_log_rmaps, 0, &sbx); if (ret) { sbx.aborted = true; str_liberror(ctx, ret, _("queueing logdev fsmap work")); From patchwork Fri May 26 01:52:11 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13256164 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7DA73C7EE29 for ; Fri, 26 May 2023 01:52:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233833AbjEZBwP (ORCPT ); Thu, 25 May 2023 21:52:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41058 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230140AbjEZBwO (ORCPT ); Thu, 25 May 2023 21:52:14 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DC7A4E7 for ; Thu, 25 May 2023 18:52:12 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 63C2A64C3E for ; Fri, 26 May 2023 01:52:12 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id C46A0C433EF; Fri, 26 May 2023 01:52:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1685065931; bh=/Evkk1YJw1NkzcLGKVy6nVDT8c/7UfOLcn82fITsUxs=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=A36vTiQnRN0uVL+/YOoW0z4gr66hHLFUu1k4r1jB2C8KA7CCFXPfcDfWRg13XNy0r uayYHauWcbAXfR8g8eI2iiWswiFqpaUfOdC8zUMEWjOHVlrEvfadxJVZzE9JiwiFh7 vaMIiuE2GGzaHshtgUxbjRA+5i/b6IEwNQaRrWUkw73GizHtnFl+bu/+DfqL6WTu8T sHY2P5YXpozG1YhrlsQJvwjzYxapXuMhnqU5N/SAXUlqqV7zr7LLWQdCCVUWviWoGE zdjUrRbwNwRtu3cG61TZYgEhVb4YtbLQKEsCy7733C0zmVrJBg93OW46RhHBbzW3tL NLiCBwZ4fFlcA== Date: Thu, 25 May 2023 18:52:11 -0700 Subject: [PATCH 6/7] xfs_scrub: collect free space histograms during phase 7 From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <168506073547.3745433.10565461223123845594.stgit@frogsfrogsfrogs> In-Reply-To: <168506073466.3745433.1072164718437572976.stgit@frogsfrogsfrogs> References: <168506073466.3745433.1072164718437572976.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Darrick J. Wong Collect a histogram of free space observed during phase 7. We'll put this information to use in the next patch. Signed-off-by: Darrick J. Wong --- libfrog/histogram.c | 38 ++++++++++++++++++++++++++++++++++++++ libfrog/histogram.h | 3 +++ scrub/phase7.c | 47 +++++++++++++++++++++++++++++++++++++++++++++-- scrub/xfs_scrub.c | 5 +++++ scrub/xfs_scrub.h | 4 ++++ 5 files changed, 95 insertions(+), 2 deletions(-) diff --git a/libfrog/histogram.c b/libfrog/histogram.c index ff780606011..1f6c490b66e 100644 --- a/libfrog/histogram.c +++ b/libfrog/histogram.c @@ -212,3 +212,41 @@ hist_summarize( printf(_("average free extent size %g\n"), (double)hs->totblocks / (double)hs->totexts); } + +/* Copy the contents of src to dest. */ +void +hist_import( + struct histogram *dest, + const struct histogram *src) +{ + unsigned int i; + + ASSERT(dest->nr_buckets == src->nr_buckets); + + dest->totblocks += src->totblocks; + dest->totexts += src->totexts; + + for (i = 0; i < dest->nr_buckets; i++) { + ASSERT(dest->buckets[i].low == src->buckets[i].low); + ASSERT(dest->buckets[i].high == src->buckets[i].high); + + dest->buckets[i].count += src->buckets[i].count; + dest->buckets[i].blocks += src->buckets[i].blocks; + } +} + +/* + * Move the contents of src to dest and reinitialize src. dst must not + * contain any observations or buckets. + */ +void +hist_move( + struct histogram *dest, + struct histogram *src) +{ + ASSERT(dest->nr_buckets == 0); + ASSERT(dest->totexts == 0); + + memcpy(dest, src, sizeof(struct histogram)); + hist_init(src); +} diff --git a/libfrog/histogram.h b/libfrog/histogram.h index c215bdaa98c..0cda747bc98 100644 --- a/libfrog/histogram.h +++ b/libfrog/histogram.h @@ -47,4 +47,7 @@ static inline unsigned int hist_buckets(const struct histogram *hs) return hs->nr_buckets; } +void hist_import(struct histogram *dest, const struct histogram *src); +void hist_move(struct histogram *dest, struct histogram *src); + #endif /* __LIBFROG_HISTOGRAM_H__ */ diff --git a/scrub/phase7.c b/scrub/phase7.c index ad9cba92bfd..77e9574f4f8 100644 --- a/scrub/phase7.c +++ b/scrub/phase7.c @@ -12,6 +12,7 @@ #include "libfrog/ptvar.h" #include "libfrog/fsgeom.h" #include "libfrog/scrub.h" +#include "libfrog/histogram.h" #include "list.h" #include "xfs_scrub.h" #include "common.h" @@ -27,8 +28,36 @@ struct summary_counts { unsigned long long rbytes; /* rt dev bytes */ unsigned long long next_phys; /* next phys bytes we see? */ unsigned long long agbytes; /* freespace bytes */ + + /* Free space histogram, in fsb */ + struct histogram datadev_hist; }; +/* + * Initialize a free space histogram. Unsharded realtime volumes can be up to + * 2^52 blocks long, so we allocate enough buckets to handle that. + */ +static inline void +init_freesp_hist( + struct histogram *hs) +{ + unsigned int i; + + hist_init(hs); + for (i = 0; i < 53; i++) + hist_add_bucket(hs, 1ULL << i); + hist_prepare(hs, 1ULL << 53); +} + +static void +summary_count_init( + void *data) +{ + struct summary_counts *counts = data; + + init_freesp_hist(&counts->datadev_hist); +} + /* Record block usage. */ static int count_block_summary( @@ -48,8 +77,14 @@ count_block_summary( if (fsmap->fmr_device == ctx->fsinfo.fs_logdev) return 0; if ((fsmap->fmr_flags & FMR_OF_SPECIAL_OWNER) && - fsmap->fmr_owner == XFS_FMR_OWN_FREE) + fsmap->fmr_owner == XFS_FMR_OWN_FREE) { + uint64_t blocks; + + blocks = cvt_b_to_off_fsbt(&ctx->mnt, fsmap->fmr_length); + if (fsmap->fmr_device == ctx->fsinfo.fs_datadev) + hist_add(&counts->datadev_hist, blocks); return 0; + } len = fsmap->fmr_length; @@ -87,6 +122,9 @@ add_summaries( total->dbytes += item->dbytes; total->rbytes += item->rbytes; total->agbytes += item->agbytes; + + hist_import(&total->datadev_hist, &item->datadev_hist); + hist_free(&item->datadev_hist); return 0; } @@ -118,6 +156,8 @@ phase7_func( int ip; int error; + summary_count_init(&totalcount); + /* Check and fix the summary metadata. */ scrub_item_init_fs(&sri); scrub_item_schedule_group(&sri, XFROG_SCRUB_GROUP_SUMMARY); @@ -136,7 +176,7 @@ phase7_func( } error = -ptvar_alloc(scrub_nproc(ctx), sizeof(struct summary_counts), - NULL, &ptvar); + summary_count_init, &ptvar); if (error) { str_liberror(ctx, error, _("setting up block counter")); return error; @@ -153,6 +193,9 @@ phase7_func( } ptvar_free(ptvar); + /* Preserve free space histograms for phase 8. */ + hist_move(&ctx->datadev_hist, &totalcount.datadev_hist); + /* Scan the whole fs. */ error = scrub_count_all_inodes(ctx, &counted_inodes); if (error) { diff --git a/scrub/xfs_scrub.c b/scrub/xfs_scrub.c index f07a1960e57..e59e478a674 100644 --- a/scrub/xfs_scrub.c +++ b/scrub/xfs_scrub.c @@ -18,6 +18,7 @@ #include "descr.h" #include "unicrash.h" #include "progress.h" +#include "libfrog/histogram.h" /* * XFS Online Metadata Scrub (and Repair) @@ -629,6 +630,8 @@ main( int ret = SCRUB_RET_SUCCESS; int error; + hist_init(&ctx.datadev_hist); + fprintf(stdout, "EXPERIMENTAL xfs_scrub program in use! Use at your own risk!\n"); fflush(stdout); @@ -839,6 +842,8 @@ main( fclose(progress_fp); unicrash_unload(); + hist_free(&ctx.datadev_hist); + /* * If we're being run as a service, the return code must fit the LSB * init script action error guidelines, which is to say that we diff --git a/scrub/xfs_scrub.h b/scrub/xfs_scrub.h index 4f1e7e02d87..b001a074a8f 100644 --- a/scrub/xfs_scrub.h +++ b/scrub/xfs_scrub.h @@ -7,6 +7,7 @@ #define XFS_SCRUB_XFS_SCRUB_H_ #include "libfrog/fsgeom.h" +#include "libfrog/histogram.h" extern char *progname; @@ -85,6 +86,9 @@ struct scrub_ctx { unsigned long long preens; bool scrub_setup_succeeded; bool preen_triggers[XFS_SCRUB_TYPE_NR]; + + /* Free space histograms, in fsb */ + struct histogram datadev_hist; }; /* Phase helper functions */ From patchwork Fri May 26 01:52:26 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13256165 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id ABB96C77B7E for ; Fri, 26 May 2023 01:52:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234388AbjEZBwb (ORCPT ); Thu, 25 May 2023 21:52:31 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41248 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229890AbjEZBwa (ORCPT ); Thu, 25 May 2023 21:52:30 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 58619189 for ; Thu, 25 May 2023 18:52:28 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id E893B64C45 for ; Fri, 26 May 2023 01:52:27 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 527D2C433D2; Fri, 26 May 2023 01:52:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1685065947; bh=RpHMKSqSW/JeqZRst8T+eJDOyW4X3z5YKa/msbv/h0o=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=R1gUZHZvcxnh26ox1hxtjiATRhRr7mdUhL9l+pRGRRyCFIwE767xPrQAeH1do0shn f0zjuiYvAMkXO0564rpwq8aVaPvtUBf5MsGTohbd2uc6nPMCG5cQqYKdw967WNVt8Z ILYjX4KKLCSTjwfpy8tysMWOgbOh/3WPPvk0bmpAoS/C6tLpC/Qd//A1I3/Naqrhrb uHtIxQkiUjr0HpIqsQravxP71NMhMx7Tqxh7WUgxnVuRQeehvgA4mxriDtN5LXlHhc smmhNDoSH0PYjcjymgTj9QNyEeEtCaug1k/KByirTjiI8BQVfDyTH8Qa5ABik5/e9n 4PDpKnomxv8sA== Date: Thu, 25 May 2023 18:52:26 -0700 Subject: [PATCH 7/7] xfs_scrub: tune fstrim minlen parameter based on free space histograms From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <168506073559.3745433.7362514369666970378.stgit@frogsfrogsfrogs> In-Reply-To: <168506073466.3745433.1072164718437572976.stgit@frogsfrogsfrogs> References: <168506073466.3745433.1072164718437572976.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Darrick J. Wong Currently, phase 8 runs very slowly on filesystems with a lot of small free space extents. To reduce the amount of time spent on fstrim activities during phase 8, we want to balance estimated runtime against completeness of the trim. In short, the goal is to reduce runtime by avoiding small trim requests. At the start of phase 8, a CDF is computed in decreasing order of extent length from the histogram buckets created during the fsmap scan in phase 7. A point corresponding to the fstrim percentage target is chosen from the CDF and mapped back to a histogram bucket, and free space extents smaller than that amount are ommitted from fstrim. On my aging /home filesystem, the free space histogram reported by xfs_spaceman looks like this: from to extents blocks pct blkcdf extcdf 1 1 121953 121953 0.04 100.00 100.00 2 3 124741 299694 0.09 99.96 81.16 4 7 113492 593763 0.18 99.87 61.89 8 15 109215 1179524 0.36 99.69 44.36 16 31 76972 1695455 0.52 99.33 27.48 32 63 48655 2219667 0.68 98.82 15.59 64 127 31398 2876898 0.88 98.14 8.08 128 255 8014 1447920 0.44 97.27 3.23 256 511 4142 1501758 0.46 96.82 1.99 512 1023 2433 1768732 0.54 96.37 1.35 1024 2047 1795 2648460 0.81 95.83 0.97 2048 4095 1429 4206103 1.28 95.02 0.69 4096 8191 1045 6162111 1.88 93.74 0.47 8192 16383 791 9242745 2.81 91.87 0.31 16384 32767 473 10883977 3.31 89.06 0.19 32768 65535 272 12385566 3.77 85.74 0.12 65536 131071 192 18098739 5.51 81.98 0.07 131072 262143 108 20675199 6.29 76.47 0.04 262144 524287 80 29061285 8.84 70.18 0.03 524288 1048575 39 29002829 8.83 61.33 0.02 1048576 2097151 25 36824985 11.21 52.51 0.01 2097152 4194303 32 101727192 30.95 41.30 0.01 4194304 8388607 7 34007410 10.35 10.35 0.00 From this table, we see that free space extents that are 16 blocks or longer constitute 99.3% of the free space in the filesystem but only 27.5% of the extents. If we set the fstrim minlen parameter to 16 blocks, that means that we can trim over 99% of the space in one third of the time it would take to trim everything. Add a new -o fstrim_pct= option to xfs_scrub just in case there are users out there who want a different percentage. For example, accepting a 95% trim would net us a speed increase of nearly two orders of magnitude, ignoring system call overhead. Setting it to 100% will trim everything, just like fstrim(8). Signed-off-by: Darrick J. Wong --- libfrog/histogram.c | 2 + libfrog/histogram.h | 1 + man/man8/xfs_scrub.8 | 31 +++++++++++++++++++++ scrub/phase8.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++--- scrub/vfs.c | 4 ++- scrub/vfs.h | 2 + scrub/xfs_scrub.c | 70 +++++++++++++++++++++++++++++++++++++++++++++-- scrub/xfs_scrub.h | 12 ++++++++ 8 files changed, 187 insertions(+), 10 deletions(-) diff --git a/libfrog/histogram.c b/libfrog/histogram.c index 1f6c490b66e..6fece03a378 100644 --- a/libfrog/histogram.c +++ b/libfrog/histogram.c @@ -109,7 +109,7 @@ hist_free( * of small extents, e.g. 98% of the free space extents are larger than 31 * blocks. */ -static int +int hist_cdf( const struct histogram *hs, struct histogram *cdf) diff --git a/libfrog/histogram.h b/libfrog/histogram.h index 0cda747bc98..76b3dd41890 100644 --- a/libfrog/histogram.h +++ b/libfrog/histogram.h @@ -39,6 +39,7 @@ void hist_add(struct histogram *hs, long long len); void hist_init(struct histogram *hs); void hist_prepare(struct histogram *hs, long long maxlen); void hist_free(struct histogram *hs); +int hist_cdf(const struct histogram *hs, struct histogram *cdf); void hist_print(const struct histogram *hs); void hist_summarize(const struct histogram *hs); diff --git a/man/man8/xfs_scrub.8 b/man/man8/xfs_scrub.8 index e881ae76acb..eb0235af9e0 100644 --- a/man/man8/xfs_scrub.8 +++ b/man/man8/xfs_scrub.8 @@ -85,6 +85,37 @@ Search this file for mounted filesystems instead of /etc/mtab. .B \-n Only check filesystem metadata. Do not repair or optimize anything. +.HP +.B \-o +.I subopt\c +[\c +.B =\c +.IR value ] +.br +Override what the program might conclude about the filesystem +if left to its own devices. +.IP +The +.IR subopt ions +supported are: +.RS 1.0i +.TP +.BI fstrim_pct= percentage +To constrain the amount of time spent on fstrim activities during phase 8, +this program tries to balance estimated runtime against completeness of the +trim. +In short, the program avoids small trim requests to save time. + +During phase 7, a log-scale histogram of free space extents is constructed. +At the start of phase 8, a CDF is computed in decreasing order of extent +length from the histogram buckets. +A point corresponding to the fstrim percentage target is chosen from the CDF +and mapped back to a histogram bucket. +Free space extents at least as long as the bucket size are trimmed. +Smaller extents are ignored. + +By default, the percentage threshold is 99%. +.RE .TP .BI \-T Print timing and memory usage information for each phase. diff --git a/scrub/phase8.c b/scrub/phase8.c index 5d2a57c83f9..1a2462476c7 100644 --- a/scrub/phase8.c +++ b/scrub/phase8.c @@ -11,6 +11,7 @@ #include "list.h" #include "libfrog/paths.h" #include "libfrog/workqueue.h" +#include "libfrog/histogram.h" #include "xfs_scrub.h" #include "common.h" #include "progress.h" @@ -57,10 +58,12 @@ static int fstrim_fsblocks( struct scrub_ctx *ctx, uint64_t start_fsb, - uint64_t fsbcount) + uint64_t fsbcount, + uint64_t minlen_fsb) { uint64_t start = cvt_off_fsb_to_b(&ctx->mnt, start_fsb); uint64_t len = cvt_off_fsb_to_b(&ctx->mnt, fsbcount); + uint64_t minlen = cvt_off_fsb_to_b(&ctx->mnt, minlen_fsb); int error; while (len > 0) { @@ -68,7 +71,7 @@ fstrim_fsblocks( run = min(len, FSTRIM_MAX_BYTES); - error = fstrim(ctx, start, run); + error = fstrim(ctx, start, run, minlen); if (error == EOPNOTSUPP) { /* Pretend we finished all the work. */ progress_add(len); @@ -78,9 +81,10 @@ fstrim_fsblocks( char descr[DESCR_BUFSZ]; snprintf(descr, sizeof(descr) - 1, - _("fstrim start 0x%llx run 0x%llx"), + _("fstrim start 0x%llx run 0x%llx minlen 0x%llx"), (unsigned long long)start, - (unsigned long long)run); + (unsigned long long)run, + (unsigned long long)minlen); str_liberror(ctx, error, descr); return error; } @@ -93,6 +97,64 @@ fstrim_fsblocks( return 0; } +/* Compute a suitable minlen parameter for fstrim. */ +static uint64_t +fstrim_compute_minlen( + const struct scrub_ctx *ctx, + const struct histogram *freesp_hist) +{ + struct histogram cdf; + uint64_t ret = 0; + double blk_threshold = 0; + unsigned int i; + unsigned int ag_max_usable; + int error; + + /* + * The kernel will reject a minlen that's larger than m_ag_max_usable. + * We can't calculate or query that value directly, so we guesstimate + * that it's 95% of the AG size. + */ + ag_max_usable = ctx->mnt.fsgeom.agblocks * 95 / 100; + + if (freesp_hist->totexts == 0) + goto out; + + if (debug > 1) + hist_print(freesp_hist); + + /* Insufficient samples to make a meaningful histogram */ + if (freesp_hist->totexts < freesp_hist->nr_buckets * 10) + goto out; + + hist_init(&cdf); + error = hist_cdf(freesp_hist, &cdf); + if (error) + goto out_free; + + blk_threshold = freesp_hist->totblocks * ctx->fstrim_block_pct; + for (i = 1; i < freesp_hist->nr_buckets; i++) { + if (cdf.buckets[i].blocks < blk_threshold) { + ret = freesp_hist->buckets[i - 1].low; + break; + } + } + +out_free: + hist_free(&cdf); +out: + if (debug > 1) + printf(_("fstrim minlen %lld threshold %lld ag_max_usable %u\n"), + (unsigned long long)ret, + (unsigned long long)blk_threshold, + ag_max_usable); + if (ret > ag_max_usable) + ret = ag_max_usable; + if (ret == 1) + ret = 0; + return ret; +} + /* Trim each AG on the data device. */ static int fstrim_datadev( @@ -100,8 +162,11 @@ fstrim_datadev( { struct xfs_fsop_geom *geo = &ctx->mnt.fsgeom; uint64_t fsbno; + uint64_t minlen_fsb; int error; + minlen_fsb = fstrim_compute_minlen(ctx, &ctx->datadev_hist); + for (fsbno = 0; fsbno < geo->datablocks; fsbno += geo->agblocks) { uint64_t fsbcount; @@ -112,7 +177,7 @@ fstrim_datadev( */ progress_add(geo->blocksize); fsbcount = min(geo->datablocks - fsbno + 1, geo->agblocks); - error = fstrim_fsblocks(ctx, fsbno + 1, fsbcount); + error = fstrim_fsblocks(ctx, fsbno + 1, fsbcount, minlen_fsb); if (error) return error; } diff --git a/scrub/vfs.c b/scrub/vfs.c index c47db5890a5..69b4a22d211 100644 --- a/scrub/vfs.c +++ b/scrub/vfs.c @@ -300,11 +300,13 @@ int fstrim( struct scrub_ctx *ctx, uint64_t start, - uint64_t len) + uint64_t len, + uint64_t minlen) { struct fstrim_range range = { .start = start, .len = len, + .minlen = minlen, }; if (ioctl(ctx->mnt.fd, FITRIM, &range) == 0) diff --git a/scrub/vfs.h b/scrub/vfs.h index db222d9c7ee..88b052f335f 100644 --- a/scrub/vfs.h +++ b/scrub/vfs.h @@ -24,6 +24,6 @@ typedef int (*scan_fs_tree_dirent_fn)(struct scrub_ctx *, const char *, int scan_fs_tree(struct scrub_ctx *ctx, scan_fs_tree_dir_fn dir_fn, scan_fs_tree_dirent_fn dirent_fn, void *arg); -int fstrim(struct scrub_ctx *ctx, uint64_t start, uint64_t len); +int fstrim(struct scrub_ctx *ctx, uint64_t start, uint64_t len, uint64_t minlen); #endif /* XFS_SCRUB_VFS_H_ */ diff --git a/scrub/xfs_scrub.c b/scrub/xfs_scrub.c index e59e478a674..04b423c7211 100644 --- a/scrub/xfs_scrub.c +++ b/scrub/xfs_scrub.c @@ -614,12 +614,75 @@ report_outcome( # define XFS_SCRUB_HAVE_UNICODE "-" #endif +/* + * -o: user-supplied override options + */ +enum o_opt_nums { + FSTRIM_PCT = 0, + O_MAX_OPTS, +}; + +static char *o_opts[] = { + [FSTRIM_PCT] = "fstrim_pct", + [O_MAX_OPTS] = NULL, +}; + +static void +parse_o_opts( + struct scrub_ctx *ctx, + char *p) +{ + double dval; + + while (*p != '\0') { + char *val; + char *endp; + + switch (getsubopt(&p, o_opts, &val)) { + case FSTRIM_PCT: + if (!val) { + fprintf(stderr, + _("-o fstrim_pct requires a parameter\n")); + usage(); + } + + errno = 0; + dval = strtod(val, &endp); + + if (*endp) { + fprintf(stderr, + _("-o fstrim_pct must be a floating point number\n")); + usage(); + } + if (errno) { + fprintf(stderr, + _("-o fstrim_pct: %s\n"), + strerror(errno)); + usage(); + } + if (dval <= 0 || dval > 100) { + fprintf(stderr, + _("-o fstrim_pct must be larger than 0 and less than 100\n")); + usage(); + } + + ctx->fstrim_block_pct = dval / 100.0; + break; + default: + usage(); + break; + } + } +} + int main( int argc, char **argv) { - struct scrub_ctx ctx = {0}; + struct scrub_ctx ctx = { + .fstrim_block_pct = FSTRIM_BLOCK_PCT_DEFAULT, + }; struct phase_rusage all_pi; char *mtab = NULL; FILE *progress_fp = NULL; @@ -649,7 +712,7 @@ main( pthread_mutex_init(&ctx.lock, NULL); ctx.mode = SCRUB_MODE_REPAIR; ctx.error_action = ERRORS_CONTINUE; - while ((c = getopt(argc, argv, "a:bC:de:km:nTvxV")) != EOF) { + while ((c = getopt(argc, argv, "a:bC:de:km:no:TvxV")) != EOF) { switch (c) { case 'a': ctx.max_errors = cvt_u64(optarg, 10); @@ -699,6 +762,9 @@ main( case 'n': ctx.mode = SCRUB_MODE_DRY_RUN; break; + case 'o': + parse_o_opts(&ctx, optarg); + break; case 'T': display_rusage = true; break; diff --git a/scrub/xfs_scrub.h b/scrub/xfs_scrub.h index b001a074a8f..dc45e486719 100644 --- a/scrub/xfs_scrub.h +++ b/scrub/xfs_scrub.h @@ -89,8 +89,20 @@ struct scrub_ctx { /* Free space histograms, in fsb */ struct histogram datadev_hist; + + /* + * Pick the largest value for fstrim minlen such that we trim at least + * this much space per volume. + */ + double fstrim_block_pct; }; +/* + * Trim only enough free space extents (in order of decreasing length) to + * ensure that this percentage of the free space is trimmed. + */ +#define FSTRIM_BLOCK_PCT_DEFAULT (99.0 / 100.0) + /* Phase helper functions */ void xfs_shutdown_fs(struct scrub_ctx *ctx); int scrub_cleanup(struct scrub_ctx *ctx);