From 677630ea56f8bd4b3a96e72d5d6cdeb0170d8c50 Mon Sep 17 00:00:00 2001
From: Jakub Wartak <jakub.wartak@enterprisedb.com>
Date: Fri, 24 Jul 2026 08:30:20 +0200
Subject: [PATCH v06082026 03/10] pg_basebackup: report average data transfer
 throughput in verbose mode

Add the average data transfer rate to the "base backup completed" message.
The transfer is timed with instr_time from just before the archive data is
received until all data has arrived (but before fsync is called)

Author: Jakub Wartak <jakub.wartak@enterprisedb.com>
Discussion:
---
 src/bin/pg_basebackup/pg_basebackup.c | 31 ++++++++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index 41cb3f26855..af579a967a0 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -36,6 +36,7 @@
 #include "fe_utils/recovery_gen.h"
 #include "getopt_long.h"
 #include "libpq/protocol.h"
+#include "portability/instr_time.h"
 #include "receivelog.h"
 #include "streamutil.h"
 
@@ -1795,6 +1796,8 @@ BaseBackup(char *compression_algorithm, char *compression_detail,
 	int			writing_to_stdout;
 	bool		use_new_option_syntax = false;
 	PQExpBufferData buf;
+	instr_time	transfer_start;
+	instr_time	transfer_elapsed;
 
 	Assert(conn != NULL);
 	initPQExpBuffer(&buf);
@@ -2150,6 +2153,9 @@ BaseBackup(char *compression_algorithm, char *compression_detail,
 						 wal_compress_level);
 	}
 
+	/* Start timing the data transfer, for the average rate report. */
+	INSTR_TIME_SET_CURRENT(transfer_start);
+
 	if (serverMajor >= 1500)
 	{
 		/* Receive a single tar stream with everything. */
@@ -2202,6 +2208,13 @@ BaseBackup(char *compression_algorithm, char *compression_detail,
 			ReceiveBackupManifest(conn);
 	}
 
+	/*
+	 * All backup data has been received, so measure how long the transfer
+	 * took for the average rate report shown at completion.
+	 */
+	INSTR_TIME_SET_CURRENT(transfer_elapsed);
+	INSTR_TIME_SUBTRACT(transfer_elapsed, transfer_start);
+
 	if (showprogress)
 	{
 		progress_update_filename(NULL);
@@ -2373,7 +2386,22 @@ BaseBackup(char *compression_algorithm, char *compression_detail,
 	}
 
 	if (verbose)
-		pg_log_info("base backup completed");
+	{
+		double		elapsed_sec = INSTR_TIME_GET_DOUBLE(transfer_elapsed);
+
+		/*
+		 * Avoids potential division by zero.
+		 *
+		 * Timing does not include potential fsync()/syncfs(), so data might be
+		 * still in-flight from pagecache when total_done was calculated, therefore
+		 * we make it clear to the user what we are measuring.
+		 */
+		if (elapsed_sec > 0.0)
+			pg_log_info("base backup completed (avg %.1f MB/s)",
+						(double) totaldone / (1024 * 1024) / elapsed_sec);
+		else
+			pg_log_info("base backup completed");
+	}
 }
 
 
@@ -2430,6 +2458,7 @@ main(int argc, char **argv)
 	pg_logging_init(argv[0]);
 	progname = get_progname(argv[0]);
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_basebackup"));
+	pg_initialize_timing();
 
 	if (argc > 1)
 	{
-- 
2.43.0

