git: fc7febf483a4 - stable/13 - minidump: De-duplicate the progress bar

From: Mitchell Horne <mhorne_at_FreeBSD.org>
Date: Fri, 15 Oct 2021 15:26:12 UTC
The branch stable/13 has been updated by mhorne:

URL: https://cgit.FreeBSD.org/src/commit/?id=fc7febf483a4910b024b34ab8620e6ac14590c08

commit fc7febf483a4910b024b34ab8620e6ac14590c08
Author:     Mitchell Horne <mhorne@FreeBSD.org>
AuthorDate: 2021-09-29 17:44:27 +0000
Commit:     Mitchell Horne <mhorne@FreeBSD.org>
CommitDate: 2021-10-15 15:20:48 +0000

    minidump: De-duplicate the progress bar
    
    The implementation of the progress bar is simple, but duplicated for
    most minidump implementations. Extract the common bits to kern_dump.c.
    Ensure that the bar is reset with each subsequent dump; this was only
    done on some platforms previously.
    
    Reviewed by:    markj
    MFC after:      2 weeks
    Sponsored by:   Juniper Networks, Inc.
    Sponsored by:   Klara, Inc.
    Differential Revision:  https://reviews.freebsd.org/D31885
    
    (cherry picked from commit ab4ed843a303ea3e585f8ed3f79873e46d3b3ae3)
---
 sys/amd64/amd64/minidump_machdep.c     | 51 +++----------------------
 sys/arm/arm/minidump_machdep.c         | 13 +------
 sys/arm/include/dump.h                 |  3 ++
 sys/arm64/arm64/minidump_machdep.c     | 46 ++---------------------
 sys/arm64/include/dump.h               |  3 ++
 sys/i386/i386/minidump_machdep_base.c  | 13 +------
 sys/kern/kern_dump.c                   | 69 ++++++++++++++++++++++++++++++++++
 sys/mips/include/dump.h                |  3 ++
 sys/mips/mips/minidump_machdep.c       | 48 ++---------------------
 sys/powerpc/include/dump.h             |  3 ++
 sys/powerpc/powerpc/minidump_machdep.c | 54 +++-----------------------
 sys/riscv/include/dump.h               |  3 ++
 sys/riscv/riscv/minidump_machdep.c     | 46 ++---------------------
 sys/sys/kerneldump.h                   |  3 ++
 sys/x86/include/dump.h                 |  3 ++
 15 files changed, 113 insertions(+), 248 deletions(-)

diff --git a/sys/amd64/amd64/minidump_machdep.c b/sys/amd64/amd64/minidump_machdep.c
index 7c54c423bbaf..d6bdbfb7e633 100644
--- a/sys/amd64/amd64/minidump_machdep.c
+++ b/sys/amd64/amd64/minidump_machdep.c
@@ -60,14 +60,12 @@ static struct kerneldumpheader kdh;
 /* Handle chunked writes. */
 static size_t fragsz;
 static void *dump_va;
-static size_t counter, progress, dumpsize, wdog_next;
+static size_t progress, dumpsize, wdog_next;
 
 static int dump_retry_count = 5;
 SYSCTL_INT(_machdep, OID_AUTO, dump_retry_count, CTLFLAG_RWTUN,
     &dump_retry_count, 0, "Number of times dump has to retry before bailing out");
 
-#define PG2MB(pgs) (((pgs) + (1 << 8) - 1) >> 8)
-
 static int
 blk_flush(struct dumperinfo *di)
 {
@@ -81,41 +79,6 @@ blk_flush(struct dumperinfo *di)
 	return (error);
 }
 
-static struct {
-	int min_per;
-	int max_per;
-	int visited;
-} progress_track[10] = {
-	{  0,  10, 0},
-	{ 10,  20, 0},
-	{ 20,  30, 0},
-	{ 30,  40, 0},
-	{ 40,  50, 0},
-	{ 50,  60, 0},
-	{ 60,  70, 0},
-	{ 70,  80, 0},
-	{ 80,  90, 0},
-	{ 90, 100, 0}
-};
-
-static void
-report_progress(size_t progress, size_t dumpsize)
-{
-	int sofar, i;
-
-	sofar = 100 - ((progress * 100) / dumpsize);
-	for (i = 0; i < nitems(progress_track); i++) {
-		if (sofar < progress_track[i].min_per ||
-		    sofar > progress_track[i].max_per)
-			continue;
-		if (progress_track[i].visited)
-			return;
-		progress_track[i].visited = 1;
-		printf("..%d%%", sofar);
-		return;
-	}
-}
-
 /* Pat the watchdog approximately every 128MB of the dump. */
 #define	WDOG_DUMP_INTERVAL	(128 * 1024 * 1024)
 
@@ -152,12 +115,9 @@ blk_write(struct dumperinfo *di, char *ptr, vm_paddr_t pa, size_t sz)
 		len = maxdumpsz - fragsz;
 		if (len > sz)
 			len = sz;
-		counter += len;
 		progress -= len;
-		if (counter >> 24) {
-			report_progress(progress, dumpsize);
-			counter &= (1<<24) - 1;
-		}
+
+		dumpsys_pb_progress(len);
 		if (progress <= wdog_next) {
 			wdog_kern_pat(WD_LASTVAL);
 			if (wdog_next > WDOG_DUMP_INTERVAL)
@@ -213,9 +173,7 @@ minidumpsys(struct dumperinfo *di)
 	retry_count = 0;
  retry:
 	retry_count++;
-	counter = 0;
-	for (i = 0; i < nitems(progress_track); i++)
-		progress_track[i].visited = 0;
+
 	/* Walk page table pages, set bits in vm_page_dump */
 	pmapsize = 0;
 	for (va = VM_MIN_KERNEL_ADDRESS; va < MAX(KERNBASE + nkpt * NBPDR,
@@ -298,6 +256,7 @@ minidumpsys(struct dumperinfo *di)
 	dumpsize += PAGE_SIZE;
 
 	wdog_next = progress = dumpsize;
+	dumpsys_pb_init(dumpsize);
 
 	/* Initialize mdhdr */
 	bzero(&mdhdr, sizeof(mdhdr));
diff --git a/sys/arm/arm/minidump_machdep.c b/sys/arm/arm/minidump_machdep.c
index f760d774bfbb..83c607c839ee 100644
--- a/sys/arm/arm/minidump_machdep.c
+++ b/sys/arm/arm/minidump_machdep.c
@@ -63,9 +63,6 @@ static struct kerneldumpheader kdh;
 /* Handle chunked writes. */
 static size_t fragsz;
 static void *dump_va;
-static uint64_t counter, progress;
-
-#define PG2MB(pgs) (((pgs) + (1 << 8) - 1) >> 8)
 
 static int
 blk_flush(struct dumperinfo *di)
@@ -115,13 +112,8 @@ blk_write(struct dumperinfo *di, char *ptr, vm_paddr_t pa, size_t sz)
 		len = maxdumpsz - fragsz;
 		if (len > sz)
 			len = sz;
-		counter += len;
-		progress -= len;
-		if (counter >> 22) {
-			printf(" %lld", PG2MB(progress >> PAGE_SHIFT));
-			counter &= (1<<22) - 1;
-		}
 
+		dumpsys_pb_progress(len);
 #ifdef SW_WATCHDOG
 		wdog_kern_pat(WD_LASTVAL);
 #endif
@@ -182,7 +174,6 @@ minidumpsys(struct dumperinfo *di)
 	 */
 	dcache_wbinv_poc_all();
 
-	counter = 0;
 	/* Walk page table pages, set bits in vm_page_dump */
 	ptesize = 0;
 	for (va = KERNBASE; va < kernel_vm_end; va += PAGE_SIZE) {
@@ -206,7 +197,7 @@ minidumpsys(struct dumperinfo *di)
 	}
 	dumpsize += PAGE_SIZE;
 
-	progress = dumpsize;
+	dumpsys_pb_init(dumpsize);
 
 	/* Initialize mdhdr */
 	bzero(&mdhdr, sizeof(mdhdr));
diff --git a/sys/arm/include/dump.h b/sys/arm/include/dump.h
index 3a7432fd49d3..97db0a819701 100644
--- a/sys/arm/include/dump.h
+++ b/sys/arm/include/dump.h
@@ -36,6 +36,9 @@
 #define	DUMPSYS_MD_PA_NPAIRS	20
 #define	DUMPSYS_NUM_AUX_HDRS	1
 
+/* How often to check the dump progress bar? */
+#define	DUMPSYS_PB_CHECK_BITS	22	/* Every 4MB */
+
 void dumpsys_wbinv_all(void);
 int dumpsys_write_aux_headers(struct dumperinfo *di);
 
diff --git a/sys/arm64/arm64/minidump_machdep.c b/sys/arm64/arm64/minidump_machdep.c
index 98d0b50be4c6..92b172260ae0 100644
--- a/sys/arm64/arm64/minidump_machdep.c
+++ b/sys/arm64/arm64/minidump_machdep.c
@@ -62,7 +62,7 @@ static struct kerneldumpheader kdh;
 /* Handle chunked writes. */
 static size_t fragsz;
 static void *dump_va;
-static size_t counter, progress, dumpsize;
+static size_t dumpsize;
 
 static uint64_t tmpbuffer[Ln_ENTRIES];
 
@@ -79,41 +79,6 @@ blk_flush(struct dumperinfo *di)
 	return (error);
 }
 
-static struct {
-	int min_per;
-	int max_per;
-	int visited;
-} progress_track[10] = {
-	{  0,  10, 0},
-	{ 10,  20, 0},
-	{ 20,  30, 0},
-	{ 30,  40, 0},
-	{ 40,  50, 0},
-	{ 50,  60, 0},
-	{ 60,  70, 0},
-	{ 70,  80, 0},
-	{ 80,  90, 0},
-	{ 90, 100, 0}
-};
-
-static void
-report_progress(size_t progress, size_t dumpsize)
-{
-	int sofar, i;
-
-	sofar = 100 - ((progress * 100) / dumpsize);
-	for (i = 0; i < nitems(progress_track); i++) {
-		if (sofar < progress_track[i].min_per ||
-		    sofar > progress_track[i].max_per)
-			continue;
-		if (progress_track[i].visited)
-			return;
-		progress_track[i].visited = 1;
-		printf("..%d%%", sofar);
-		return;
-	}
-}
-
 static int
 blk_write(struct dumperinfo *di, char *ptr, vm_paddr_t pa, size_t sz)
 {
@@ -150,13 +115,8 @@ blk_write(struct dumperinfo *di, char *ptr, vm_paddr_t pa, size_t sz)
 		len = maxdumpsz - fragsz;
 		if (len > sz)
 			len = sz;
-		counter += len;
-		progress -= len;
-		if (counter >> 22) {
-			report_progress(progress, dumpsize);
-			counter &= (1 << 22) - 1;
-		}
 
+		dumpsys_pb_progress(len);
 		wdog_kern_pat(WD_LASTVAL);
 
 		if (ptr) {
@@ -245,7 +205,7 @@ minidumpsys(struct dumperinfo *di)
 	}
 	dumpsize += PAGE_SIZE;
 
-	progress = dumpsize;
+	dumpsys_pb_init(dumpsize);
 
 	/* Initialize mdhdr */
 	bzero(&mdhdr, sizeof(mdhdr));
diff --git a/sys/arm64/include/dump.h b/sys/arm64/include/dump.h
index 6f2537550c42..600cc5415970 100644
--- a/sys/arm64/include/dump.h
+++ b/sys/arm64/include/dump.h
@@ -40,6 +40,9 @@
 #define	DUMPSYS_MD_PA_NPAIRS	20
 #define	DUMPSYS_NUM_AUX_HDRS	1
 
+/* How often to check the dump progress bar? */
+#define	DUMPSYS_PB_CHECK_BITS	22	/* Every 4MB */
+
 void dumpsys_wbinv_all(void);
 int dumpsys_write_aux_headers(struct dumperinfo *di);
 
diff --git a/sys/i386/i386/minidump_machdep_base.c b/sys/i386/i386/minidump_machdep_base.c
index b8e9e4884552..e3e211bf9a46 100644
--- a/sys/i386/i386/minidump_machdep_base.c
+++ b/sys/i386/i386/minidump_machdep_base.c
@@ -60,9 +60,6 @@ static struct kerneldumpheader kdh;
 /* Handle chunked writes. */
 static size_t fragsz;
 static void *dump_va;
-static uint64_t counter, progress;
-
-#define PG2MB(pgs) (((pgs) + (1 << 8) - 1) >> 8)
 
 static int
 blk_flush(struct dumperinfo *di)
@@ -110,13 +107,8 @@ blk_write(struct dumperinfo *di, char *ptr, vm_paddr_t pa, size_t sz)
 		len = maxdumpsz - fragsz;
 		if (len > sz)
 			len = sz;
-		counter += len;
-		progress -= len;
-		if (counter >> 24) {
-			printf(" %lld", PG2MB(progress >> PAGE_SHIFT));
-			counter &= (1<<24) - 1;
-		}
 
+		dumpsys_pb_progress(len);
 		wdog_kern_pat(WD_LASTVAL);
 
 		if (ptr) {
@@ -173,7 +165,6 @@ minidumpsys(struct dumperinfo *di)
 	int j, k;
 	struct minidumphdr mdhdr;
 
-	counter = 0;
 	/* Walk page table pages, set bits in vm_page_dump */
 	ptesize = 0;
 	for (va = KERNBASE; va < kernel_vm_end; va += NBPDR) {
@@ -224,7 +215,7 @@ minidumpsys(struct dumperinfo *di)
 	}
 	dumpsize += PAGE_SIZE;
 
-	progress = dumpsize;
+	dumpsys_pb_init(dumpsize);
 
 	/* Initialize mdhdr */
 	bzero(&mdhdr, sizeof(mdhdr));
diff --git a/sys/kern/kern_dump.c b/sys/kern/kern_dump.c
index 7ba6847e405d..4c592f446f45 100644
--- a/sys/kern/kern_dump.c
+++ b/sys/kern/kern_dump.c
@@ -385,3 +385,72 @@ dumpsys_generic(struct dumperinfo *di)
 		printf("\n** DUMP FAILED (ERROR %d) **\n", error);
 	return (error);
 }
+
+/* Minidump progress bar */
+static struct {
+	const int min_per;
+	const int max_per;
+	bool visited;
+} progress_track[10] = {
+	{  0,  10, false},
+	{ 10,  20, false},
+	{ 20,  30, false},
+	{ 30,  40, false},
+	{ 40,  50, false},
+	{ 50,  60, false},
+	{ 60,  70, false},
+	{ 70,  80, false},
+	{ 80,  90, false},
+	{ 90, 100, false}
+};
+
+static uint64_t dumpsys_pb_size;
+static uint64_t dumpsys_pb_remaining;
+static uint64_t dumpsys_pb_check;
+
+/* Reset the progress bar for a dump of dumpsize. */
+void
+dumpsys_pb_init(uint64_t dumpsize)
+{
+	int i;
+
+	dumpsys_pb_size = dumpsys_pb_remaining = dumpsize;
+	dumpsys_pb_check = 0;
+
+	for (i = 0; i < nitems(progress_track); i++)
+		progress_track[i].visited = false;
+}
+
+/*
+ * Update the progress according to the delta bytes that were written out.
+ * Check and print the progress percentage.
+ */
+void
+dumpsys_pb_progress(size_t delta)
+{
+	int sofar, i;
+
+	dumpsys_pb_remaining -= delta;
+	dumpsys_pb_check += delta;
+
+	/*
+	 * To save time while dumping, only loop through progress_track
+	 * occasionally.
+	 */
+	if ((dumpsys_pb_check >> DUMPSYS_PB_CHECK_BITS) == 0)
+		return;
+	else
+		dumpsys_pb_check &= (1 << DUMPSYS_PB_CHECK_BITS) - 1;
+
+	sofar = 100 - ((dumpsys_pb_remaining * 100) / dumpsys_pb_size);
+	for (i = 0; i < nitems(progress_track); i++) {
+		if (sofar < progress_track[i].min_per ||
+		    sofar > progress_track[i].max_per)
+			continue;
+		if (!progress_track[i].visited) {
+			progress_track[i].visited = true;
+			printf("..%d%%", sofar);
+		}
+		break;
+	}
+}
diff --git a/sys/mips/include/dump.h b/sys/mips/include/dump.h
index 2224b6eea4b9..4e434861dfcc 100644
--- a/sys/mips/include/dump.h
+++ b/sys/mips/include/dump.h
@@ -36,6 +36,9 @@
 #define	DUMPSYS_MD_PA_NPAIRS	20
 #define	DUMPSYS_NUM_AUX_HDRS	0
 
+/* How often to check the dump progress bar? */
+#define	DUMPSYS_PB_CHECK_BITS	22	/* Every 4MB */
+
 void dumpsys_wbinv_all(void);
 
 static inline void
diff --git a/sys/mips/mips/minidump_machdep.c b/sys/mips/mips/minidump_machdep.c
index d35b1fd53068..691e1208e684 100644
--- a/sys/mips/mips/minidump_machdep.c
+++ b/sys/mips/mips/minidump_machdep.c
@@ -58,47 +58,12 @@ CTASSERT(sizeof(struct kerneldumpheader) == 512);
 static struct kerneldumpheader kdh;
 
 /* Handle chunked writes. */
-static uint64_t counter, progress, dumpsize;
+static uint64_t dumpsize;
 /* Just auxiliary bufffer */
 static char tmpbuffer[PAGE_SIZE] __aligned(sizeof(uint64_t));
 
 extern pd_entry_t *kernel_segmap;
 
-static struct {
-	int min_per;
-	int max_per;
-	int visited;
-} progress_track[10] = {
-	{  0,  10, 0},
-	{ 10,  20, 0},
-	{ 20,  30, 0},
-	{ 30,  40, 0},
-	{ 40,  50, 0},
-	{ 50,  60, 0},
-	{ 60,  70, 0},
-	{ 70,  80, 0},
-	{ 80,  90, 0},
-	{ 90, 100, 0}
-};
-
-static void
-report_progress(uint64_t progress, uint64_t dumpsize)
-{
-	int sofar, i;
-
-	sofar = 100 - ((progress * 100) / dumpsize);
-	for (i = 0; i < nitems(progress_track); i++) {
-		if (sofar < progress_track[i].min_per ||
-		    sofar > progress_track[i].max_per)
-			continue;
-		if (progress_track[i].visited)
-			return;
-		progress_track[i].visited = 1;
-		printf("..%d%%", sofar);
-		return;
-	}
-}
-
 static int
 write_buffer(struct dumperinfo *di, char *ptr, size_t sz)
 {
@@ -115,14 +80,8 @@ write_buffer(struct dumperinfo *di, char *ptr, size_t sz)
 
 	while (sz) {
 		len = min(maxdumpsz, sz);
-		counter += len;
-		progress -= len;
-
-		if (counter >> 22) {
-			report_progress(progress, dumpsize);
-			counter &= (1<<22) - 1;
-		}
 
+		dumpsys_pb_progress(len);
 		wdog_kern_pat(WD_LASTVAL);
 
 		if (ptr) {
@@ -163,7 +122,6 @@ minidumpsys(struct dumperinfo *di)
 	/* Flush cache */
 	mips_dcache_wbinv_all();
 
-	counter = 0;
 	/* Walk page table pages, set bits in vm_page_dump */
 	ptesize = 0;
 
@@ -203,7 +161,7 @@ minidumpsys(struct dumperinfo *di)
 	}
 	dumpsize += PAGE_SIZE;
 
-	progress = dumpsize;
+	dumpsys_pb_init(dumpsize);
 
 	/* Initialize mdhdr */
 	bzero(&mdhdr, sizeof(mdhdr));
diff --git a/sys/powerpc/include/dump.h b/sys/powerpc/include/dump.h
index f6ccb003c89b..3debbfbe25f9 100644
--- a/sys/powerpc/include/dump.h
+++ b/sys/powerpc/include/dump.h
@@ -35,6 +35,9 @@
 #define	DUMPSYS_MD_PA_NPAIRS	(PHYS_AVAIL_SZ + 1)
 #define	DUMPSYS_NUM_AUX_HDRS	0
 
+/* How often to check the dump progress bar? */
+#define	DUMPSYS_PB_CHECK_BITS	20	/* Every 1MB */
+
 void dumpsys_pa_init(void);
 void dumpsys_unmap_chunk(vm_paddr_t, size_t, void *);
 size_t dumpsys_scan_pmap(void);
diff --git a/sys/powerpc/powerpc/minidump_machdep.c b/sys/powerpc/powerpc/minidump_machdep.c
index e4d85fe95ed6..908e6f7a3fc7 100644
--- a/sys/powerpc/powerpc/minidump_machdep.c
+++ b/sys/powerpc/powerpc/minidump_machdep.c
@@ -69,24 +69,7 @@ SYSCTL_INT(_machdep, OID_AUTO, dump_retry_count, CTLFLAG_RWTUN,
 static struct kerneldumpheader kdh;
 static char pgbuf[PAGE_SIZE];
 
-static struct {
-	int min_per;
-	int max_per;
-	int visited;
-} progress_track[10] = {
-	{  0,  10, 0},
-	{ 10,  20, 0},
-	{ 20,  30, 0},
-	{ 30,  40, 0},
-	{ 40,  50, 0},
-	{ 50,  60, 0},
-	{ 60,  70, 0},
-	{ 70,  80, 0},
-	{ 80,  90, 0},
-	{ 90, 100, 0}
-};
-
-static size_t counter, dumpsize, progress;
+static size_t dumpsize;
 
 /* Handle chunked writes. */
 static size_t fragsz;
@@ -98,24 +81,6 @@ pmap_kenter_temporary(vm_offset_t va, vm_paddr_t pa)
 	pmap_kenter(va, pa);
 }
 
-static void
-report_progress(void)
-{
-	int sofar, i;
-
-	sofar = 100 - ((progress * 100) / dumpsize);
-	for (i = 0; i < nitems(progress_track); i++) {
-		if (sofar < progress_track[i].min_per ||
-		    sofar > progress_track[i].max_per)
-			continue;
-		if (progress_track[i].visited)
-			return;
-		progress_track[i].visited = 1;
-		printf("..%d%%", sofar);
-		return;
-	}
-}
-
 static int
 blk_flush(struct dumperinfo *di)
 {
@@ -165,12 +130,8 @@ blk_write(struct dumperinfo *di, char *ptr, vm_paddr_t pa, size_t sz)
 		len = maxdumpsz - fragsz;
 		if (len > sz)
 			len = sz;
-		counter += len;
-		progress -= len;
-		if (counter >> 20) {
-			report_progress();
-			counter &= (1<<20) - 1;
-		}
+
+		dumpsys_pb_progress(len);
 
 		if (ptr) {
 			error = dump_append(di, ptr, 0, len);
@@ -231,7 +192,7 @@ int
 minidumpsys(struct dumperinfo *di)
 {
 	vm_paddr_t pa;
-	int error, i, retry_count;
+	int error, retry_count;
 	uint32_t pmapsize;
 	struct minidumphdr mdhdr;
 
@@ -241,11 +202,6 @@ retry:
 	fragsz = 0;
 	DBG(total = dumptotal = 0;)
 
-	/* Reset progress */
-	counter = 0;
-	for (i = 0; i < nitems(progress_track); i++)
-		progress_track[i].visited = 0;
-
 	/* Build set of dumpable pages from kernel pmap */
 	pmapsize = dumpsys_scan_pmap();
 	if (pmapsize % PAGE_SIZE != 0) {
@@ -266,7 +222,7 @@ retry:
 		else
 			dump_drop_page(pa);
 	}
-	progress = dumpsize;
+	dumpsys_pb_init(dumpsize);
 
 	/* Initialize mdhdr */
 	bzero(&mdhdr, sizeof(mdhdr));
diff --git a/sys/riscv/include/dump.h b/sys/riscv/include/dump.h
index 182a89eb8f98..3c3152f150e9 100644
--- a/sys/riscv/include/dump.h
+++ b/sys/riscv/include/dump.h
@@ -37,6 +37,9 @@
 #define	DUMPSYS_MD_PA_NPAIRS	10
 #define	DUMPSYS_NUM_AUX_HDRS	0
 
+/* How often to check the dump progress bar? */
+#define	DUMPSYS_PB_CHECK_BITS	22	/* Every 4MB */
+
 static inline void
 dumpsys_pa_init(void)
 {
diff --git a/sys/riscv/riscv/minidump_machdep.c b/sys/riscv/riscv/minidump_machdep.c
index bcedfbdf2fb2..992ab097e1b3 100644
--- a/sys/riscv/riscv/minidump_machdep.c
+++ b/sys/riscv/riscv/minidump_machdep.c
@@ -60,45 +60,10 @@ static struct kerneldumpheader kdh;
 /* Handle chunked writes. */
 static size_t fragsz;
 static void *dump_va;
-static size_t counter, progress, dumpsize;
+static size_t dumpsize;
 
 static uint64_t tmpbuffer[PAGE_SIZE / sizeof(uint64_t)];
 
-static struct {
-	int min_per;
-	int max_per;
-	int visited;
-} progress_track[10] = {
-	{  0,  10, 0},
-	{ 10,  20, 0},
-	{ 20,  30, 0},
-	{ 30,  40, 0},
-	{ 40,  50, 0},
-	{ 50,  60, 0},
-	{ 60,  70, 0},
-	{ 70,  80, 0},
-	{ 80,  90, 0},
-	{ 90, 100, 0}
-};
-
-static void
-report_progress(size_t progress, size_t dumpsize)
-{
-	int sofar, i;
-
-	sofar = 100 - ((progress * 100) / dumpsize);
-	for (i = 0; i < nitems(progress_track); i++) {
-		if (sofar < progress_track[i].min_per ||
-		    sofar > progress_track[i].max_per)
-			continue;
-		if (progress_track[i].visited)
-			return;
-		progress_track[i].visited = 1;
-		printf("..%d%%", sofar);
-		return;
-	}
-}
-
 static int
 blk_flush(struct dumperinfo *di)
 {
@@ -156,13 +121,8 @@ blk_write(struct dumperinfo *di, char *ptr, vm_paddr_t pa, size_t sz)
 		len = maxdumpsz - fragsz;
 		if (len > sz)
 			len = sz;
-		counter += len;
-		progress -= len;
-		if (counter >> 22) {
-			report_progress(progress, dumpsize);
-			counter &= (1 << 22) - 1;
-		}
 
+		dumpsys_pb_progress(len);
 		wdog_kern_pat(WD_LASTVAL);
 
 		if (ptr) {
@@ -253,7 +213,7 @@ retry:
 	}
 	dumpsize += PAGE_SIZE;
 
-	progress = dumpsize;
+	dumpsys_pb_init(dumpsize);
 
 	/* Initialize mdhdr */
 	bzero(&mdhdr, sizeof(mdhdr));
diff --git a/sys/sys/kerneldump.h b/sys/sys/kerneldump.h
index 8ce6a7a47127..c4ce9d2f13ec 100644
--- a/sys/sys/kerneldump.h
+++ b/sys/sys/kerneldump.h
@@ -151,6 +151,9 @@ void dumpsys_gen_wbinv_all(void);
 void dumpsys_gen_unmap_chunk(vm_paddr_t, size_t, void *);
 int dumpsys_gen_write_aux_headers(struct dumperinfo *);
 
+void dumpsys_pb_init(uint64_t);
+void dumpsys_pb_progress(size_t);
+
 extern int do_minidump;
 
 #endif
diff --git a/sys/x86/include/dump.h b/sys/x86/include/dump.h
index 91c72acb4e5b..b8da0d50a6a4 100644
--- a/sys/x86/include/dump.h
+++ b/sys/x86/include/dump.h
@@ -42,6 +42,9 @@
 #define	DUMPSYS_MD_PA_NPAIRS	10
 #define	DUMPSYS_NUM_AUX_HDRS	0
 
+/* How often to check the dump progress bar? */
+#define	DUMPSYS_PB_CHECK_BITS	24	/* Every 16MB */
+
 static inline void
 dumpsys_pa_init(void)
 {