[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
dd patch to output transfer rate, byte count, and time
From: |
Paul Eggert |
Subject: |
dd patch to output transfer rate, byte count, and time |
Date: |
Sun, 14 Nov 2004 22:57:51 -0800 |
User-agent: |
Gnus/5.1006 (Gnus v5.10.6) Emacs/21.3 (gnu/linux) |
The Debian unstable version of "dd" also outputs a total byte count,
seconds taken, and transfer rate. This is an often-asked-for feature,
and seems useful. I installed this implementation instead, which I
wrote from scratch. The Debian version suppresses this new output if
POSIXLY_CORRECT is set, but I just checked POSIX and it allows this
behavior so I turned it on unconditionally.
In theory this change might break some scripts. Does anybody think
this will be a problem in practice? If so, I suppose we could enable
the new behavior only conditionally.
2004-11-14 Paul Eggert <address@hidden>
* NEWS: dd now outputs total bytes, seconds, and bytes per second.
* src/Makefile.am (dd_LDADD): Add $(LIB_CLOCK_GETTIME).
* src/dd.c: Include "human.h".
(w_bytes, start_time): New vars.
(usage): Document new I/O statistics output
(print_stats): Output new I/O statistics.
(cleanup): Do statistics after closing stdin and stdout, so that
the times are more accurate.
(write_output, dd_copy): Count output bytes.
(main): Get initial value of clock.
* doc/coreutils.texi (dd invocation): dd now outputs total bytes,
seconds, and bytes per second.
Index: NEWS
===================================================================
RCS file: /fetish/cu/NEWS,v
retrieving revision 1.248
diff -p -u -r1.248 NEWS
--- NEWS 13 Nov 2004 00:52:32 -0000 1.248
+++ NEWS 15 Nov 2004 06:47:53 -0000
@@ -182,6 +182,9 @@ GNU coreutils NEWS
copying or moving multiple times to the same destination in a file
system with a coarse time stamp resolution.
+ dd now also prints the number of bytes copied, the time, and the
+ transfer rate.
+
dd has new conversions for the conv= option:
nocreat do not create the output file
Index: src/Makefile.am
===================================================================
RCS file: /fetish/cu/src/Makefile.am,v
retrieving revision 1.45
diff -p -u -r1.45 Makefile.am
--- src/Makefile.am 3 Nov 2004 23:12:55 -0000 1.45
+++ src/Makefile.am 15 Nov 2004 06:47:53 -0000
@@ -41,7 +41,7 @@ rm_LDADD = $(LDADD) $(LIB_EACCESS)
test_LDADD = $(LDADD) $(LIB_EACCESS)
# for clock_gettime and fdatasync
-dd_LDADD = $(LDADD) $(LIB_FDATASYNC)
+dd_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_FDATASYNC)
dir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME)
ls_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME)
shred_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_FDATASYNC)
Index: src/dd.c
===================================================================
RCS file: /fetish/cu/src/dd.c,v
retrieving revision 1.167
diff -p -u -r1.167 dd.c
--- src/dd.c 21 Sep 2004 22:07:51 -0000 1.167
+++ src/dd.c 15 Nov 2004 06:47:53 -0000
@@ -30,6 +30,7 @@
#include "error.h"
#include "full-write.h"
#include "getpagesize.h"
+#include "human.h"
#include "inttostr.h"
#include "long-options.h"
#include "quote.h"
@@ -140,6 +141,12 @@ static uintmax_t r_partial = 0;
/* Number of full blocks read. */
static uintmax_t r_full = 0;
+/* Number of bytes written. */
+static uintmax_t w_bytes = 0;
+
+/* Time that dd started. */
+static struct timespec start_time;
+
/* True if input is seekable. */
static bool input_seekable;
@@ -402,14 +409,14 @@ Each FLAG symbol may be:\n\
fputs (_(" nofollow do not follow symlinks\n"), stdout);
fputs (_("\
\n\
-Note that sending a SIGUSR1 signal to a running `dd' process makes it\n\
-print to standard error the number of records read and written so far,\n\
-then to resume copying.\n\
+Sending a SIGUSR1 signal to a running `dd' process makes it\n\
+print I/O statistics to standard error, then to resume copying.\n\
\n\
$ dd if=/dev/zero of=/dev/null& pid=$!\n\
$ kill -USR1 $pid; sleep 1; kill $pid\n\
- 10899206+0 records in\n\
- 10899206+0 records out\n\
+ 10807656+0 records in\n\
+ 10807656+0 records out\n\
+ 5.5GB copied in 20.8225s (266MB/s)\n\
\n\
Options are:\n\
\n\
@@ -442,7 +449,16 @@ multiple_bits_set (int i)
static void
print_stats (void)
{
- char buf[2][INT_BUFSIZE_BOUND (uintmax_t)];
+ char buf[2][MAX (INT_BUFSIZE_BOUND (uintmax_t), LONGEST_HUMAN_READABLE + 1)];
+ struct timespec now;
+ int human_opts =
+ human_autoscale | human_round_to_nearest | human_SI | human_B;
+ uintmax_t start_sec = start_time.tv_sec;
+ enum { BILLION = 1000000000 };
+ double delta_s;
+ char const *bytes_per_second;
+
+ gettime (&now);
fprintf (stderr, _("%s+%s records in\n"),
umaxtostr (r_full, buf[0]), umaxtostr (r_partial, buf[1]));
fprintf (stderr, _("%s+%s records out\n"),
@@ -455,18 +471,49 @@ print_stats (void)
? _("truncated record")
: _("truncated records")));
}
+
+ /* Use integer arithmetic to compute the transfer rate if possible,
+ since that makes it easy to use SI abbreviations; otherwise, fall
+ back on floating-point without abbreviations. */
+
+ if ((start_time.tv_sec < now.tv_sec
+ || (start_time.tv_sec == now.tv_sec
+ && start_time.tv_nsec < now.tv_nsec))
+ && now.tv_sec - start_sec < UINTMAX_MAX / BILLION)
+ {
+ uintmax_t delta_ns = (BILLION * (now.tv_sec - start_sec)
+ + now.tv_nsec - start_time.tv_nsec);
+ delta_s = delta_ns / 1e9;
+ bytes_per_second = human_readable (w_bytes, buf[1], human_opts,
+ BILLION, delta_ns);
+ }
+ else
+ {
+ delta_s = now.tv_sec;
+ delta_s -= start_time.tv_sec;
+ delta_s += 1e-9 * (now.tv_nsec - start_time.tv_nsec);
+ if (0 < delta_s)
+ sprintf (buf[1], "%gB", w_bytes / delta_s);
+ else
+ sprintf (buf[1], "%s B", _("Infinity"));
+ bytes_per_second = buf[1];
+ }
+
+ fprintf (stderr, _("%s copied in %gs (%s/s)\n"),
+ human_readable (w_bytes, buf[0], human_opts, 1, 1),
+ delta_s, bytes_per_second);
}
static void
cleanup (void)
{
- print_stats ();
if (close (STDIN_FILENO) < 0)
error (EXIT_FAILURE, errno,
_("closing input file %s"), quote (input_file));
if (close (STDOUT_FILENO) < 0)
error (EXIT_FAILURE, errno,
_("closing output file %s"), quote (output_file));
+ print_stats ();
}
static inline void
@@ -548,6 +595,7 @@ static void
write_output (void)
{
size_t nwritten = full_write (STDOUT_FILENO, obuf, output_blocksize);
+ w_bytes += nwritten;
if (nwritten != output_blocksize)
{
error (0, errno, _("writing to %s"), quote (output_file));
@@ -1238,6 +1286,7 @@ dd_copy (void)
if (ibuf == obuf) /* If not C_TWOBUFS. */
{
size_t nwritten = full_write (STDOUT_FILENO, obuf, n_bytes_read);
+ w_bytes += nwritten;
if (nwritten != n_bytes_read)
{
error (0, errno, _("writing %s"), quote (output_file));
@@ -1297,6 +1346,7 @@ dd_copy (void)
if (oc != 0)
{
size_t nwritten = full_write (STDOUT_FILENO, obuf, oc);
+ w_bytes += nwritten;
if (nwritten != 0)
w_partial++;
if (nwritten != oc)
@@ -1450,6 +1500,8 @@ main (int argc, char **argv)
install_handler (SIGPIPE, interrupt_handler);
install_handler (SIGINFO, siginfo_handler);
+ gettime (&start_time);
+
exit_status = dd_copy ();
quit (exit_status);
Index: doc/coreutils.texi
===================================================================
RCS file: /fetish/cu/doc/coreutils.texi,v
retrieving revision 1.224
diff -p -u -r1.224 coreutils.texi
--- doc/coreutils.texi 29 Oct 2004 23:22:09 -0000 1.224
+++ doc/coreutils.texi 15 Nov 2004 06:47:55 -0000
@@ -6863,20 +6863,21 @@ tape=/dev/rmt/0
@end example
Note that sending a @samp{SIGUSR1} signal to a running @command{dd}
-process makes it print to standard error the number of records read
-and written so far, then to resume copying. In the example below,
+process makes it print I/O statistics to standard error,
+then to resume copying. In the example below,
@command{dd} is run in the background to copy 10 million blocks.
-The @command{kill} command makes it output the first pair of
-intermediate record counts,
-and when @command{dd} completes, it outputs the final pair.
+The @command{kill} command makes it output intermediate I/O statistics,
+and when @command{dd} completes, it outputs the final statistics.
@example
-$ dd if=/dev/zero of=/dev/null count=10M & pid=$!
-$ kill -s USR1 $pid; sleep 99
-5403604+0 records in
-5403604+0 records out
-10485760+0 records in
-10485760+0 records out
+$ dd if=/dev/zero of=/dev/null count=10MB & pid=$!
+$ kill -s USR1 $pid; wait $pid
+4111640+0 records in
+4111639+0 records out
+2.1GB copied in 7.95411s (265MB/s)
+10000000+0 records in
+10000000+0 records out
+5.1GB copied in 19.3794s (264MB/s)
@end example
@exitstatus
- dd patch to output transfer rate, byte count, and time,
Paul Eggert <=