dd(1) uses gettimeofday(2) to compute the throughput statistics. However,

gettimeofday returns the system clock, which may jump forward or back,
especially if NTP is in use.  If the time jumps backwards, then dd will see
negative elapsed time, round it up to 1usec, and print an absurdly fast
transfer rate.

The solution is to use clock_gettime(2) with CLOCK_MONOTONIC_PRECISE as the
clock_id.  That clock advances steadily, regardless of changes to the system
clock.

Reviewed by:	delphij
MFC after:	3 days
Sponsored by:	Spectra Logic
This commit is contained in:
Alan Somers 2014-05-06 22:06:39 +00:00
parent 789a10b106
commit d1d66eac15
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=265472
2 changed files with 20 additions and 12 deletions

View File

@ -50,7 +50,6 @@ __FBSDID("$FreeBSD$");
#include <sys/conf.h>
#include <sys/disklabel.h>
#include <sys/filio.h>
#include <sys/time.h>
#include <ctype.h>
#include <err.h>
@ -61,6 +60,8 @@ __FBSDID("$FreeBSD$");
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <time.h>
#include <unistd.h>
#include "dd.h"
@ -123,7 +124,7 @@ static void
setup(void)
{
u_int cnt;
struct timeval tv;
struct timespec tv;
if (in.name == NULL) {
in.name = "stdin";
@ -240,8 +241,9 @@ setup(void)
ctab = casetab;
}
(void)gettimeofday(&tv, NULL);
st.start = tv.tv_sec + tv.tv_usec * 1e-6;
if (clock_gettime(CLOCK_MONOTONIC_PRECISE, &tv))
err(EX_OSERR, "clock_gettime");
st.start = tv.tv_sec + tv.tv_nsec * 1.0e-9;
}
static void

View File

@ -40,14 +40,16 @@ static char sccsid[] = "@(#)misc.c 8.3 (Berkeley) 4/2/94";
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/time.h>
#include <err.h>
#include <errno.h>
#include <inttypes.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <time.h>
#include <unistd.h>
#include "dd.h"
@ -56,16 +58,20 @@ __FBSDID("$FreeBSD$");
void
summary(void)
{
struct timeval tv;
double secs;
struct timespec tv, tv_res;
double secs, res;
if (ddflags & C_NOINFO)
return;
(void)gettimeofday(&tv, NULL);
secs = tv.tv_sec + tv.tv_usec * 1e-6 - st.start;
if (secs < 1e-6)
secs = 1e-6;
if (clock_gettime(CLOCK_MONOTONIC_PRECISE, &tv))
err(EX_OSERR, "clock_gettime");
if (clock_getres(CLOCK_MONOTONIC_PRECISE, &tv_res))
err(EX_OSERR, "clock_getres");
secs = tv.tv_sec + tv.tv_nsec * 1.0e-9 - st.start;
res = tv_res.tv_sec + tv_res.tv_nsec * 1.0e-9;
if (secs < res)
secs = res;
(void)fprintf(stderr,
"%ju+%ju records in\n%ju+%ju records out\n",
st.in_full, st.in_part, st.out_full, st.out_part);
@ -77,7 +83,7 @@ summary(void)
st.trunc, (st.trunc == 1) ? "block" : "blocks");
if (!(ddflags & C_NOXFER)) {
(void)fprintf(stderr,
"%ju bytes transferred in %.6f secs (%.0f bytes/sec)\n",
"%ju bytes transferred in %.9f secs (%.0f bytes/sec)\n",
st.bytes, secs, st.bytes / secs);
}
need_summary = 0;