diff --git a/SRC/echoping.c b/SRC/echoping.c index d09819c..b4fa1a6 100644 --- a/SRC/echoping.c +++ b/SRC/echoping.c @@ -26,11 +26,12 @@ char *progname; int return_code = 0; int rc; unsigned int number = 1; -struct timeval max, min, total, median, stddev, temp; +struct timeval max, min, total, median, stddev, temp, measured; struct timeval conntv, connectedtv, sendtv, recvtv; unsigned int successes, attempts = 0; unsigned int size = DEFLINE; unsigned int j = 0; +int n_stddev = 0; int family = PF_UNSPEC; @@ -99,6 +100,7 @@ main(argc, argv) boolean timeout_requested = 0; boolean size_requested = 0; char *url = ""; + boolean measure_data_transfer_only = FALSE; #if USE_SIGACTION struct sigaction mysigaction; #endif @@ -188,6 +190,9 @@ main(argc, argv) {"ipv6", '6', POPT_ARG_NONE, NULL, '6'}, {"module", 'm', POPT_ARG_STRING, &plugin_name, 'm', "Loads the given plugin"}, + {"dataonly", 'D', POPT_ARG_NONE, NULL, 'D'}, + {"numstddev", 'N', POPT_ARG_INT, &n_stddev, 'N', + "Number of stddeviations to classify outliers"}, POPT_TABLEEND }; poptContext poptcon; @@ -291,6 +296,12 @@ main(argc, argv) strcpy(port_name, "smtp"); port_to_use = USE_SMTP; break; + case 'D': + measure_data_transfer_only = TRUE; + break; + case 'N': + remaining--; + break; case 'p': remaining--; priority_requested = 1; @@ -905,6 +916,14 @@ main(argc, argv) alarm(timeout); } (void) gettimeofday(&oldtv, (struct timezone *) NULL); + /* work out the time it took... */ + if (measure_data_transfer_only) { + measured = recvtv; + tvsub(&measured, &sendtv); + } else { + measured = newtv; + tvsub(&measured, &oldtv); + } if (plugin) { plugin_result = plugin_execute(); if (plugin_result == -2) @@ -1392,7 +1411,10 @@ main(argc, argv) } #endif results[i - 1].valid = 1; - results[i - 1].timevalue = newtv; + if (measure_data_transfer_only) + results[i - 1].timevalue = measured; + else + results[i - 1].timevalue = newtv; successes++; } if (number > 1) { @@ -1497,6 +1519,13 @@ printstats() printf("Median time: %d.%06d seconds (%.0f bytes per sec.)\n", (int) median.tv_sec, (int) median.tv_usec, (double) size / tv2double(median)); + if (n_stddev) { + tvstddevavg(&stddev, successes, total, results, + (double) n_stddev); + printf + ("Average of values within %d standard deviations: %d.%06d\n", + n_stddev, (int) stddev.tv_sec, (int) stddev.tv_usec); + } } } diff --git a/SRC/echoping.h b/SRC/echoping.h index 0ff4f1c..3db1dc9 100644 --- a/SRC/echoping.h +++ b/SRC/echoping.h @@ -206,6 +206,7 @@ void tvmin (); void tvmax (); int tvcmp (); void tvstddev (); +void tvstddevavg (); double tv2double (); struct timeval double2tv (); /* http.c */ diff --git a/SRC/util.c b/SRC/util.c index 5cd4b37..1c4122c 100644 --- a/SRC/util.c +++ b/SRC/util.c @@ -102,7 +102,8 @@ tvstddev(out, number, average, results) { int i; struct timeval result, avg, var = null_timeval; - struct timeval square, large, small; + struct timeval large, small; + double d_offset, d_square, d_variance = 0; *out = null_timeval; for (i = 0; i < number; i++) { if (results[i].valid == 1) { @@ -119,16 +120,72 @@ tvstddev(out, number, average, results) } tvsub(&large, &small); /* printf ("abs offset is %f\n", tv2double (large)); */ - square = double2tv(pow(tv2double(large), 2)); - tvadd(&var, &square); + d_offset = tv2double(large); + d_square = d_offset * d_offset; + d_variance += d_square; /* printf ("variance is now %f\n", tv2double (var)); */ } } - result = double2tv(sqrt(tv2double(var) / number)); + result = double2tv(sqrt(d_variance / (double) number)); out->tv_sec = result.tv_sec; out->tv_usec = result.tv_usec; } + + /* tvstddevavg -- Computes the average of values within a set of results where the + * sample is within the given number of standard deviations from the average */ +void +tvstddevavg(out, number, average, results, n_stddev) + struct timeval *out; /* contains std dev on entry */ + int number; + struct timeval average; + struct result *results; + double n_stddev; +{ + int i, valid = 0; + struct timeval result; /* working value */ + struct timeval var = null_timeval; /* result accumulator */ + double x; + double maxdev = tv2double(*out) * n_stddev; + + if (tvcmp(out, &null_timeval) == 0) { + /* if the SD is 0 then we just return the average */ + *out = average; + return; + } + + for (i = 0; i < number; i++) { + if (results[i].valid == 1) { + result = results[i].timevalue; + tvsub(&result, &average); + /* printf ("value is %f (stddev is %f)\n", tv2double + * (result), tv2double (stddev)); */ + /* ensure that result (difference to average) is absolute + * value */ + if (tvcmp(&result, &null_timeval) == -1) { + result = average; + tvsub(&result, &results[i].timevalue); + } + x = tv2double(result); + /* printf("value is %g maxdev %g\n",x,maxdev); */ + if (x <= maxdev) { + /* deviation is less than stddev */ + tvadd(&var, &results[i].timevalue); + valid++; + } else { + /* printf("dropped\n"); */ + } + } + } + /* printf ("total is %f in %d samples\n", tv2double (var), valid); */ + if (valid > 0) { + *out = double2tv(tv2double(var) / valid); + } else { + *out = null_timeval; + } + +} + /* tvcmp -- Compares two timeval structs */ int tvcmp(left, right)