Skip to content

Commit

Permalink
ping: fix standard deviation for small, consistent ping times
Browse files Browse the repository at this point in the history
Suppose we do 10 pings, and 5 take 10us, 5 take 11us.  tsum2 is 1105, tsum
is 105.  We divide them, getting 110 and 10 respectively.  tmdev is then
llsqrt(110 - 10 * 10) = llsqrt(10) = 3us.  But max-min is only 1us!

The exact solution is sqrt(110.5 - 110.25) which is sqrt(0.25) = 0.5.  The
new code will (more) correctly compute llsqrt(0) = 0 as the answer.  It
takes care not to do any horrendous integer overflows if there's a lot of
long pings (a few thousand >1s pings would overflow without this).

Addresses: https://bugs.debian.org/907327
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
  • Loading branch information
David Buckley authored and kerolasa committed Feb 2, 2019
1 parent 9ceff21 commit 6811953
Showing 1 changed file with 12 additions and 4 deletions.
16 changes: 12 additions & 4 deletions ping_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -956,14 +956,22 @@ void finish(void)

if (nreceived && timing) {
double tmdev;
long total = nreceived + nrepeats;
long tmavg = tsum / total;
long long tmvar;

if (tsum < INT_MAX)
/* This slightly clumsy computation order is important to avoid
* integer rounding errors for small ping times. */
tmvar = (tsum2 - ((tsum * tsum) / total)) / total;
else
tmvar = (tsum2 / total) - (tmavg * tmavg);

tsum /= nreceived + nrepeats;
tsum2 /= nreceived + nrepeats;
tmdev = llsqrt(tsum2 - tsum * tsum);
tmdev = llsqrt(tmvar);

printf(_("rtt min/avg/max/mdev = %ld.%03ld/%lu.%03ld/%ld.%03ld/%ld.%03ld ms"),
(long)tmin/1000, (long)tmin%1000,
(unsigned long)(tsum/1000), (long)tsum%1000,
(unsigned long)(tmavg/1000), (long)(tmavg%1000),
(long)tmax/1000, (long)tmax%1000,
(long)tmdev/1000, (long)tmdev%1000
);
Expand Down

0 comments on commit 6811953

Please sign in to comment.