Merge pull request #136 from tycho/high-resolution-clock-sources

Move to 1us resolution for latency measurements
pull/187/head
David Schweikert 5 years ago committed by GitHub
commit 721af135db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -41,8 +41,8 @@ $cmd->stderr_like(qr{localhost : \d\.\d+ \d\.\d+
{ {
my $cmd = Test::Command->new(cmd => "fping -D -c 2 -p 100 127.0.0.1"); my $cmd = Test::Command->new(cmd => "fping -D -c 2 -p 100 127.0.0.1");
$cmd->exit_is_num(0); $cmd->exit_is_num(0);
$cmd->stdout_like(qr{\[\d{10}\.\d+\] 127\.0\.0\.1 : \[0\], 84 bytes, \d\.\d+ ms \(\d\.\d+ avg, 0% loss\) $cmd->stdout_like(qr{\[\d+\.\d+\] 127\.0\.0\.1 : \[0\], 84 bytes, \d\.\d+ ms \(\d\.\d+ avg, 0% loss\)
\[\d{10}\.\d+\] 127\.0\.0\.1 : \[1\], 84 bytes, \d\.\d+ ms \(\d\.\d+ avg, 0% loss\) \[\d+\.\d+\] 127\.0\.0\.1 : \[1\], 84 bytes, \d\.\d+ ms \(\d\.\d+ avg, 0% loss\)
}); });
$cmd->stderr_like(qr{127\.0\.0\.1 : xmt/rcv/%loss = 2/2/0%, min/avg/max = \d\.\d+/\d\.\d+/\d\.\d+ $cmd->stderr_like(qr{127\.0\.0\.1 : xmt/rcv/%loss = 2/2/0%, min/avg/max = \d\.\d+/\d\.\d+/\d\.\d+

@ -22,13 +22,13 @@ BEGIN fping\.127_0_0_1_quality
SET returned = 100 SET returned = 100
END END
CHART fping\.127_0_0_1_latency '' 'FPing Latency for host 127\.0\.0\.1' ms '127_0_0_1' fping\.latency area 110000 1 CHART fping\.127_0_0_1_latency '' 'FPing Latency for host 127\.0\.0\.1' ms '127_0_0_1' fping\.latency area 110000 1
DIMENSION min minimum absolute 10 1000 DIMENSION min minimum absolute 1 1000000
DIMENSION max maximum absolute 10 1000 DIMENSION max maximum absolute 1 1000000
DIMENSION avg average absolute 10 1000 DIMENSION avg average absolute 1 1000000
BEGIN fping\.127_0_0_1_latency BEGIN fping\.127_0_0_1_latency
SET min = \d{1,2} SET min = \d+
SET avg = \d{1,2} SET avg = \d+
SET max = \d{1,2} SET max = \d+
END} END}
); );
$cmd->stderr_like(qr{127.0.0.1 : xmt/rcv/%loss = 2/2/0%, min/avg/max = \d\.\d+/\d\.\d+/\d\.\d+}); $cmd->stderr_like(qr{127.0.0.1 : xmt/rcv/%loss = 2/2/0%, min/avg/max = \d\.\d+/\d\.\d+/\d\.\d+});

@ -34,9 +34,9 @@ AM_CONDITIONAL([IPV6], [test "x$have_ipv6" = "xyes"])
AM_COND_IF([IPV6], [AC_DEFINE([IPV6], [1], [IPv6 enabled])]) AM_COND_IF([IPV6], [AC_DEFINE([IPV6], [1], [IPv6 enabled])])
AC_ARG_ENABLE([timestamp], AC_ARG_ENABLE([timestamp],
AS_HELP_STRING([--disable-timestamp], [Disable kernel-based packet timestaping (SO_TIMESTAMP)])) AS_HELP_STRING([--disable-timestamp], [Disable kernel-based packet timestaping (SO_TIMESTAMPNS)]))
AS_IF([test "x$enable_timestamp" != "xno"], [ AS_IF([test "x$enable_timestamp" != "xno"], [
AC_CHECK_DECL([SO_TIMESTAMP], [AC_DEFINE(HAVE_SO_TIMESTAMP, [1], [SO_TIMESTAMP is defined])], [have_so_timestamp="no"], [#include <sys/types.h> AC_CHECK_DECL([SO_TIMESTAMPNS], [AC_DEFINE(HAVE_SO_TIMESTAMPNS, [1], [SO_TIMESTAMPNS is defined])], [have_so_timestamp="no"], [#include <sys/types.h>
#include <sys/socket.h>]) #include <sys/socket.h>])
]) ])
dnl Test if --enable-timestamp is explicitely enabled and make an error if this platform doesn't support it dnl Test if --enable-timestamp is explicitely enabled and make an error if this platform doesn't support it

@ -39,10 +39,12 @@ extern "C" {
#include "options.h" #include "options.h"
#include "optparse.h" #include "optparse.h"
#include <inttypes.h>
#include <errno.h> #include <errno.h>
#include <signal.h> #include <signal.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h>
#include <time.h> #include <time.h>
#include "seqmap.h" #include "seqmap.h"
@ -58,6 +60,8 @@ extern "C" {
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
#include <time.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/types.h> #include <sys/types.h>
@ -107,6 +111,18 @@ extern int h_errno;
#define EMAIL "david@schweikert.ch" #define EMAIL "david@schweikert.ch"
#if HAVE_SO_TIMESTAMPNS
#define CLOCKID CLOCK_REALTIME
#endif
#if !defined(CLOCKID)
#if defined(CLOCK_MONOTONIC)
#define CLOCKID CLOCK_MONOTONIC
#else
#define CLOCKID CLOCK_REALTIME
#endif
#endif
/*** Ping packet defines ***/ /*** Ping packet defines ***/
#define MAX_IP_PACKET 65536 /* (theoretical) max IP packet size */ #define MAX_IP_PACKET 65536 /* (theoretical) max IP packet size */
@ -198,7 +214,7 @@ typedef struct host_entry {
* to be sent, or the timeout, if the last ping was sent */ * to be sent, or the timeout, if the last ping was sent */
struct host_entry* ev_prev; /* double linked list for the event-queue */ struct host_entry* ev_prev; /* double linked list for the event-queue */
struct host_entry* ev_next; /* double linked list for the event-queue */ struct host_entry* ev_next; /* double linked list for the event-queue */
struct timeval ev_time; /* time, after which this event should happen */ struct timespec ev_time; /* time, after which this event should happen */
int ev_type; /* event type */ int ev_type; /* event type */
int i; /* index into array */ int i; /* index into array */
@ -210,7 +226,7 @@ typedef struct host_entry {
int timeout; /* time to wait for response */ int timeout; /* time to wait for response */
unsigned char running; /* unset when through sending */ unsigned char running; /* unset when through sending */
unsigned char waiting; /* waiting for response */ unsigned char waiting; /* waiting for response */
struct timeval last_send_time; /* time of last packet sent */ struct timespec last_send_time; /* time of last packet sent */
int num_sent; /* number of ping packets sent */ int num_sent; /* number of ping packets sent */
int num_recv; /* number of pings received (duplicates ignored) */ int num_recv; /* number of pings received (duplicates ignored) */
int num_recv_total; /* number of pings received, including duplicates */ int num_recv_total; /* number of pings received, including duplicates */
@ -224,9 +240,9 @@ typedef struct host_entry {
int min_reply_i; /* shortest response time */ int min_reply_i; /* shortest response time */
int total_time_i; /* sum of response times */ int total_time_i; /* sum of response times */
int discard_next_recv_i; /* don't count next received reply for split reporting */ int discard_next_recv_i; /* don't count next received reply for split reporting */
int* resp_times; /* individual response times */ int64_t* resp_times; /* individual response times */
#if defined(DEBUG) || defined(_DEBUG) #if defined(DEBUG) || defined(_DEBUG)
int* sent_times; /* per-sent-ping timestamp */ int64_t* sent_times; /* per-sent-ping timestamp */
#endif /* DEBUG || _DEBUG */ #endif /* DEBUG || _DEBUG */
} HOST_ENTRY; } HOST_ENTRY;
@ -290,11 +306,11 @@ int num_timeout = 0, /* number of times select timed out */
num_pingreceived = 0, /* total pings received */ num_pingreceived = 0, /* total pings received */
num_othericmprcvd = 0; /* total non-echo-reply ICMP received */ num_othericmprcvd = 0; /* total non-echo-reply ICMP received */
struct timeval current_time; /* current time (pseudo) */ struct timespec current_time; /* current time (pseudo) */
struct timeval start_time; struct timespec start_time;
struct timeval end_time; struct timespec end_time;
struct timeval last_send_time; /* time last ping was sent */ struct timespec last_send_time; /* time last ping was sent */
struct timeval next_report_time; /* time next -Q report is expected */ struct timespec next_report_time; /* time next -Q report is expected */
/* switches */ /* switches */
int generate_flag = 0; /* flag for IP list generation */ int generate_flag = 0; /* flag for IP list generation */
@ -322,8 +338,11 @@ void errno_crash_and_burn(char* message);
char* get_host_by_address(struct in_addr in); char* get_host_by_address(struct in_addr in);
void remove_job(HOST_ENTRY* h); void remove_job(HOST_ENTRY* h);
int send_ping(HOST_ENTRY* h); int send_ping(HOST_ENTRY* h);
long timeval_diff(struct timeval* a, struct timeval* b); void timespec_from_ns(struct timespec* a, uint64_t ns);
void timeval_add(struct timeval* a, long t_10u); int64_t timespec_ns(struct timespec* a);
int64_t timespec_diff(struct timespec* a, struct timespec* b);
long timespec_diff_10us(struct timespec* a, struct timespec* b);
void timespec_add_10us(struct timespec* a, long t_10u);
void usage(int); void usage(int);
int wait_for_reply(long); int wait_for_reply(long);
void print_per_system_stats(void); void print_per_system_stats(void);
@ -333,7 +352,7 @@ void print_global_stats(void);
void main_loop(); void main_loop();
void sigstatus(); void sigstatus();
void finish(); void finish();
char* sprint_tm(int t); const char* sprint_tm(int64_t t);
void ev_enqueue(HOST_ENTRY* h); void ev_enqueue(HOST_ENTRY* h);
HOST_ENTRY* ev_dequeue(); HOST_ENTRY* ev_dequeue();
void ev_remove(HOST_ENTRY* h); void ev_remove(HOST_ENTRY* h);
@ -344,6 +363,19 @@ int addr_cmp(struct sockaddr* a, struct sockaddr* b);
/*** function definitions ***/ /*** function definitions ***/
static inline void copy_timespec(struct timespec *dst, const struct timespec *src)
{
dst->tv_sec = src->tv_sec;
dst->tv_nsec = src->tv_nsec;
}
static inline long ns_to_tick(int64_t ns)
{
ns /= 1000; // ns -> us
ns /= 10; // us -> 10us ticks
return (long)ns;
}
/************************************************************ /************************************************************
Function: main Function: main
@ -440,6 +472,9 @@ int main(int argc, char** argv)
{ "unreach", 'u', OPTPARSE_NONE }, { "unreach", 'u', OPTPARSE_NONE },
{ "version", 'v', OPTPARSE_NONE }, { "version", 'v', OPTPARSE_NONE },
{ "reachable", 'x', OPTPARSE_REQUIRED }, { "reachable", 'x', OPTPARSE_REQUIRED },
#if defined(DEBUG) || defined(_DEBUG)
{ NULL, 'z', OPTPARSE_REQUIRED },
#endif
{ 0, 0, 0 } { 0, 0, 0 }
}; };
@ -635,8 +670,9 @@ int main(int argc, char** argv)
#if defined(DEBUG) || defined(_DEBUG) #if defined(DEBUG) || defined(_DEBUG)
case 'z': case 'z':
if (!(debugging = (unsigned int)atoi(optparse_state.optarg))) if (sscanf(optparse_state.optarg, "0x%x", &debugging) != 1)
usage(1); if (sscanf(optparse_state.optarg, "%u", &debugging) != 1)
usage(1);
break; break;
#endif /* DEBUG || _DEBUG */ #endif /* DEBUG || _DEBUG */
@ -899,18 +935,18 @@ int main(int argc, char** argv)
#endif #endif
} }
#if HAVE_SO_TIMESTAMP #if HAVE_SO_TIMESTAMPNS
{ {
int opt = 1; int opt = 1;
if (socket4 >= 0) { if (socket4 >= 0) {
if (setsockopt(socket4, SOL_SOCKET, SO_TIMESTAMP, &opt, sizeof(opt))) { if (setsockopt(socket4, SOL_SOCKET, SO_TIMESTAMPNS, &opt, sizeof(opt))) {
perror("setting SO_TIMESTAMP option"); perror("setting SO_TIMESTAMPNS option");
} }
} }
#ifdef IPV6 #ifdef IPV6
if (socket6 >= 0) { if (socket6 >= 0) {
if (setsockopt(socket6, SOL_SOCKET, SO_TIMESTAMP, &opt, sizeof(opt))) { if (setsockopt(socket6, SOL_SOCKET, SO_TIMESTAMPNS, &opt, sizeof(opt))) {
perror("setting SO_TIMESTAMP option (IPv6)"); perror("setting SO_TIMESTAMPNS option (IPv6)");
} }
} }
#endif #endif
@ -1033,19 +1069,19 @@ int main(int argc, char** argv)
signal(SIGQUIT, sigstatus); signal(SIGQUIT, sigstatus);
setlinebuf(stdout); setlinebuf(stdout);
gettimeofday(&start_time, NULL); clock_gettime(CLOCKID, &start_time);
current_time = start_time; current_time = start_time;
if (report_interval) { if (report_interval) {
next_report_time = start_time; next_report_time = start_time;
timeval_add(&next_report_time, report_interval); timespec_add_10us(&next_report_time, report_interval);
} }
last_send_time.tv_sec = current_time.tv_sec - 10000; last_send_time.tv_sec = current_time.tv_sec - 10000;
#if defined(DEBUG) || defined(_DEBUG) #if defined(DEBUG) || defined(_DEBUG)
if (randomly_lose_flag) if (randomly_lose_flag)
srandom(start_time.tv_usec); srandom(start_time.tv_nsec);
#endif /* DEBUG || _DEBUG */ #endif /* DEBUG || _DEBUG */
seqmap_init(); seqmap_init();
@ -1190,11 +1226,11 @@ void main_loop()
while (ev_first) { while (ev_first) {
/* Any event that can be processed now ? */ /* Any event that can be processed now ? */
if (ev_first->ev_time.tv_sec < current_time.tv_sec || (ev_first->ev_time.tv_sec == current_time.tv_sec && ev_first->ev_time.tv_usec < current_time.tv_usec)) { if (timespec_diff_10us(&ev_first->ev_time, &current_time) < 0) {
/* Event type: ping */ /* Event type: ping */
if (ev_first->ev_type == EV_TYPE_PING) { if (ev_first->ev_type == EV_TYPE_PING) {
/* Make sure that we don't ping more than once every "interval" */ /* Make sure that we don't ping more than once every "interval" */
lt = timeval_diff(&current_time, &last_send_time); lt = timespec_diff_10us(&current_time, &last_send_time);
if (lt < interval) if (lt < interval)
goto wait_for_reply; goto wait_for_reply;
@ -1209,9 +1245,8 @@ void main_loop()
/* Normal mode: schedule retry */ /* Normal mode: schedule retry */
if (h->waiting < retry + 1) { if (h->waiting < retry + 1) {
h->ev_type = EV_TYPE_PING; h->ev_type = EV_TYPE_PING;
h->ev_time.tv_sec = last_send_time.tv_sec; copy_timespec(&h->ev_time, &last_send_time);
h->ev_time.tv_usec = last_send_time.tv_usec; timespec_add_10us(&h->ev_time, h->timeout);
timeval_add(&h->ev_time, h->timeout);
ev_enqueue(h); ev_enqueue(h);
if (backoff_flag) { if (backoff_flag) {
@ -1221,26 +1256,23 @@ void main_loop()
/* Normal mode: schedule timeout for last retry */ /* Normal mode: schedule timeout for last retry */
else { else {
h->ev_type = EV_TYPE_TIMEOUT; h->ev_type = EV_TYPE_TIMEOUT;
h->ev_time.tv_sec = last_send_time.tv_sec; copy_timespec(&h->ev_time, &last_send_time);
h->ev_time.tv_usec = last_send_time.tv_usec; timespec_add_10us(&h->ev_time, h->timeout);
timeval_add(&h->ev_time, h->timeout);
ev_enqueue(h); ev_enqueue(h);
} }
} }
/* Loop and count mode: schedule next ping */ /* Loop and count mode: schedule next ping */
else if (loop_flag || (count_flag && h->num_sent < count)) { else if (loop_flag || (count_flag && h->num_sent < count)) {
h->ev_type = EV_TYPE_PING; h->ev_type = EV_TYPE_PING;
h->ev_time.tv_sec = last_send_time.tv_sec; copy_timespec(&h->ev_time, &last_send_time);
h->ev_time.tv_usec = last_send_time.tv_usec; timespec_add_10us(&h->ev_time, perhost_interval);
timeval_add(&h->ev_time, perhost_interval);
ev_enqueue(h); ev_enqueue(h);
} }
/* Count mode: schedule timeout after last ping */ /* Count mode: schedule timeout after last ping */
else if (count_flag && h->num_sent >= count) { else if (count_flag && h->num_sent >= count) {
h->ev_type = EV_TYPE_TIMEOUT; h->ev_type = EV_TYPE_TIMEOUT;
h->ev_time.tv_sec = last_send_time.tv_sec; copy_timespec(&h->ev_time, &last_send_time);
h->ev_time.tv_usec = last_send_time.tv_usec; timespec_add_10us(&h->ev_time, h->timeout);
timeval_add(&h->ev_time, h->timeout);
ev_enqueue(h); ev_enqueue(h);
} }
} }
@ -1259,7 +1291,7 @@ void main_loop()
wait_time = 0; wait_time = 0;
} }
else { else {
wait_time = timeval_diff(&ev_first->ev_time, &current_time); wait_time = timespec_diff_10us(&ev_first->ev_time, &current_time);
if (wait_time < 0) if (wait_time < 0)
wait_time = 0; wait_time = 0;
} }
@ -1267,7 +1299,7 @@ void main_loop()
/* make sure that we wait enough, so that the inter-ping delay is /* make sure that we wait enough, so that the inter-ping delay is
* bigger than 'interval' */ * bigger than 'interval' */
if (wait_time < interval) { if (wait_time < interval) {
lt = timeval_diff(&current_time, &last_send_time); lt = timespec_diff_10us(&current_time, &last_send_time);
if (lt < interval) { if (lt < interval) {
wait_time = interval - lt; wait_time = interval - lt;
} }
@ -1279,7 +1311,7 @@ void main_loop()
#if defined(DEBUG) || defined(_DEBUG) #if defined(DEBUG) || defined(_DEBUG)
if (trace_flag) { if (trace_flag) {
fprintf(stderr, "next event in %d ms (%s)\n", wait_time / 100, ev_first->host); fprintf(stderr, "next event in %ld ms (%s)\n", wait_time / 100, ev_first->host);
} }
#endif #endif
} }
@ -1289,7 +1321,7 @@ void main_loop()
/* Make sure we don't wait too long, in case a report is expected */ /* Make sure we don't wait too long, in case a report is expected */
if (report_interval && (loop_flag || count_flag)) { if (report_interval && (loop_flag || count_flag)) {
wait_time_next_report = timeval_diff(&next_report_time, &current_time); wait_time_next_report = timespec_diff_10us(&next_report_time, &current_time);
if (wait_time_next_report < wait_time) { if (wait_time_next_report < wait_time) {
wait_time = wait_time_next_report; wait_time = wait_time_next_report;
if (wait_time < 0) { if (wait_time < 0) {
@ -1305,7 +1337,7 @@ void main_loop()
; /* process other replies in the queue */ ; /* process other replies in the queue */
} }
gettimeofday(&current_time, NULL); clock_gettime(CLOCKID, &current_time);
if (status_snapshot) { if (status_snapshot) {
status_snapshot = 0; status_snapshot = 0;
@ -1313,14 +1345,14 @@ void main_loop()
} }
/* Print report */ /* Print report */
if (report_interval && (loop_flag || count_flag) && (timeval_diff(&current_time, &next_report_time) >= 0)) { if (report_interval && (loop_flag || count_flag) && (timespec_diff_10us(&current_time, &next_report_time) >= 0)) {
if (netdata_flag) if (netdata_flag)
print_netdata(); print_netdata();
else else
print_per_system_splits(); print_per_system_splits();
while (timeval_diff(&current_time, &next_report_time) >= 0) while (timespec_diff_10us(&current_time, &next_report_time) >= 0)
timeval_add(&next_report_time, report_interval); timespec_add_10us(&next_report_time, report_interval);
} }
} }
} }
@ -1364,7 +1396,7 @@ void finish()
int i; int i;
HOST_ENTRY* h; HOST_ENTRY* h;
gettimeofday(&end_time, NULL); clock_gettime(CLOCKID, &end_time);
/* tot up unreachables */ /* tot up unreachables */
for (i = 0; i < num_hosts; i++) { for (i = 0; i < num_hosts; i++) {
@ -1429,7 +1461,7 @@ void print_per_system_stats(void)
{ {
int i, j, avg, outage_ms; int i, j, avg, outage_ms;
HOST_ENTRY* h; HOST_ENTRY* h;
int resp; int64_t resp;
if (verbose_flag || per_recv_flag) if (verbose_flag || per_recv_flag)
fprintf(stderr, "\n"); fprintf(stderr, "\n");
@ -1441,7 +1473,7 @@ void print_per_system_stats(void)
if (report_all_rtts_flag) { if (report_all_rtts_flag) {
for (j = 0; j < h->num_sent; j++) { for (j = 0; j < h->num_sent; j++) {
if ((resp = h->resp_times[j]) >= 0) if ((resp = h->resp_times[j]) >= 0)
fprintf(stderr, " %d.%02d", resp / 100, resp % 100); fprintf(stderr, " %s", sprint_tm(resp));
else else
fprintf(stderr, " -"); fprintf(stderr, " -");
} }
@ -1515,7 +1547,7 @@ void print_netdata(void)
/* if we just sent the probe and didn't receive a reply, we shouldn't count it */ /* if we just sent the probe and didn't receive a reply, we shouldn't count it */
h->discard_next_recv_i = 0; h->discard_next_recv_i = 0;
if (h->waiting && timeval_diff(&current_time, &h->last_send_time) < h->timeout) { if (h->waiting && timespec_diff_10us(&current_time, &h->last_send_time) < h->timeout) {
if (h->num_sent_i) { if (h->num_sent_i) {
h->num_sent_i--; h->num_sent_i--;
h->discard_next_recv_i = 1; h->discard_next_recv_i = 1;
@ -1552,9 +1584,9 @@ void print_netdata(void)
if (!sent_charts) { if (!sent_charts) {
printf("CHART fping.%s_latency '' 'FPing Latency for host %s' ms '%s' fping.latency area 110000 %d\n", h->name, h->host, h->name, report_interval / 100000); printf("CHART fping.%s_latency '' 'FPing Latency for host %s' ms '%s' fping.latency area 110000 %d\n", h->name, h->host, h->name, report_interval / 100000);
printf("DIMENSION min minimum absolute 10 1000\n"); printf("DIMENSION min minimum absolute 1 1000000\n");
printf("DIMENSION max maximum absolute 10 1000\n"); printf("DIMENSION max maximum absolute 1 1000000\n");
printf("DIMENSION avg average absolute 10 1000\n"); printf("DIMENSION avg average absolute 1 1000000\n");
} }
printf("BEGIN fping.%s_latency\n", h->name); printf("BEGIN fping.%s_latency\n", h->name);
@ -1594,7 +1626,7 @@ void print_per_system_splits(void)
if (verbose_flag || per_recv_flag) if (verbose_flag || per_recv_flag)
fprintf(stderr, "\n"); fprintf(stderr, "\n");
gettimeofday(&current_time, NULL); clock_gettime(CLOCKID, &current_time);
curr_tm = localtime((time_t*)&current_time.tv_sec); curr_tm = localtime((time_t*)&current_time.tv_sec);
fprintf(stderr, "[%2.2d:%2.2d:%2.2d]\n", curr_tm->tm_hour, fprintf(stderr, "[%2.2d:%2.2d:%2.2d]\n", curr_tm->tm_hour,
curr_tm->tm_min, curr_tm->tm_sec); curr_tm->tm_min, curr_tm->tm_sec);
@ -1605,7 +1637,7 @@ void print_per_system_splits(void)
/* if we just sent the probe and didn't receive a reply, we shouldn't count it */ /* if we just sent the probe and didn't receive a reply, we shouldn't count it */
h->discard_next_recv_i = 0; h->discard_next_recv_i = 0;
if (h->waiting && timeval_diff(&current_time, &h->last_send_time) < h->timeout) { if (h->waiting && timespec_diff_10us(&current_time, &h->last_send_time) < h->timeout) {
if (h->num_sent_i) { if (h->num_sent_i) {
h->num_sent_i--; h->num_sent_i--;
h->discard_next_recv_i = 1; h->discard_next_recv_i = 1;
@ -1678,7 +1710,7 @@ void print_global_stats(void)
sprint_tm((int)(sum_replies / total_replies))); sprint_tm((int)(sum_replies / total_replies)));
fprintf(stderr, " %s ms (max round trip time)\n", sprint_tm(max_reply)); fprintf(stderr, " %s ms (max round trip time)\n", sprint_tm(max_reply));
fprintf(stderr, " %12.3f sec (elapsed real time)\n", fprintf(stderr, " %12.3f sec (elapsed real time)\n",
timeval_diff(&end_time, &start_time) / 100000.0); timespec_diff(&end_time, &start_time) / 1e9);
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }
@ -1706,7 +1738,7 @@ int send_ping(HOST_ENTRY* h)
int myseq; int myseq;
int ret = 1; int ret = 1;
gettimeofday(&h->last_send_time, NULL); clock_gettime(CLOCKID, &h->last_send_time);
myseq = seqmap_add(h->i, h->num_sent, &h->last_send_time); myseq = seqmap_add(h->i, h->num_sent, &h->last_send_time);
#if defined(DEBUG) || defined(_DEBUG) #if defined(DEBUG) || defined(_DEBUG)
@ -1748,7 +1780,7 @@ int send_ping(HOST_ENTRY* h)
#if defined(DEBUG) || defined(_DEBUG) #if defined(DEBUG) || defined(_DEBUG)
if (sent_times_flag) if (sent_times_flag)
h->sent_times[h->num_sent] = timeval_diff(&h->last_send_time, &start_time); h->sent_times[h->num_sent] = timespec_diff(&h->last_send_time, &start_time);
#endif #endif
} }
@ -1765,7 +1797,7 @@ int send_ping(HOST_ENTRY* h)
int socket_can_read(struct timeval* timeout) int socket_can_read(struct timeval* timeout)
{ {
int nfound; int nfound;
fd_set readset, writeset; fd_set readset;
int socketmax; int socketmax;
#ifndef IPV6 #ifndef IPV6
@ -1776,13 +1808,12 @@ int socket_can_read(struct timeval* timeout)
select_again: select_again:
FD_ZERO(&readset); FD_ZERO(&readset);
FD_ZERO(&writeset);
if(socket4 >= 0) FD_SET(socket4, &readset); if(socket4 >= 0) FD_SET(socket4, &readset);
#ifdef IPV6 #ifdef IPV6
if(socket6 >= 0) FD_SET(socket6, &readset); if(socket6 >= 0) FD_SET(socket6, &readset);
#endif #endif
nfound = select(socketmax + 1, &readset, &writeset, NULL, timeout); nfound = select(socketmax + 1, &readset, NULL, NULL, timeout);
if (nfound < 0) { if (nfound < 0) {
if (errno == EINTR) { if (errno == EINTR) {
/* interrupted system call: redo the select */ /* interrupted system call: redo the select */
@ -1808,7 +1839,7 @@ select_again:
} }
int receive_packet(int socket, int receive_packet(int socket,
struct timeval* reply_timestamp, struct timespec* reply_timestamp,
struct sockaddr* reply_src_addr, struct sockaddr* reply_src_addr,
size_t reply_src_addr_len, size_t reply_src_addr_len,
char* reply_buf, char* reply_buf,
@ -1830,19 +1861,21 @@ int receive_packet(int socket,
0 0
}; };
int timestamp_set = 0; int timestamp_set = 0;
#if HAVE_SO_TIMESTAMPNS
struct cmsghdr* cmsg; struct cmsghdr* cmsg;
#endif
recv_len = recvmsg(socket, &recv_msghdr, 0); recv_len = recvmsg(socket, &recv_msghdr, 0);
if (recv_len <= 0) { if (recv_len <= 0) {
return 0; return 0;
} }
#if HAVE_SO_TIMESTAMP #if HAVE_SO_TIMESTAMPNS
/* ancilliary data */ /* ancilliary data */
for (cmsg = CMSG_FIRSTHDR(&recv_msghdr); for (cmsg = CMSG_FIRSTHDR(&recv_msghdr);
cmsg != NULL; cmsg != NULL;
cmsg = CMSG_NXTHDR(&recv_msghdr, cmsg)) { cmsg = CMSG_NXTHDR(&recv_msghdr, cmsg)) {
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMP) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMPNS) {
memcpy(reply_timestamp, CMSG_DATA(cmsg), sizeof(*reply_timestamp)); memcpy(reply_timestamp, CMSG_DATA(cmsg), sizeof(*reply_timestamp));
timestamp_set = 1; timestamp_set = 1;
} }
@ -1850,7 +1883,7 @@ int receive_packet(int socket,
#endif #endif
if (!timestamp_set) { if (!timestamp_set) {
gettimeofday(reply_timestamp, NULL); clock_gettime(CLOCKID, reply_timestamp);
} }
#if defined(DEBUG) || defined(_DEBUG) #if defined(DEBUG) || defined(_DEBUG)
@ -2072,8 +2105,8 @@ int wait_for_reply(long wait_time)
HOST_ENTRY* h; HOST_ENTRY* h;
long this_reply; long this_reply;
int this_count; int this_count;
struct timeval* sent_time; struct timespec* sent_time;
struct timeval recv_time; struct timespec recv_time = {0};
SEQMAP_VALUE* seqmap_value; SEQMAP_VALUE* seqmap_value;
unsigned short id; unsigned short id;
unsigned short seq; unsigned short seq;
@ -2113,7 +2146,7 @@ int wait_for_reply(long wait_time)
return 1; return 1;
} }
gettimeofday(&current_time, NULL); clock_gettime(CLOCKID, &current_time);
/* Process ICMP packet and retrieve id/seq */ /* Process ICMP packet and retrieve id/seq */
if (response_addr.ss_family == AF_INET) { if (response_addr.ss_family == AF_INET) {
@ -2165,11 +2198,11 @@ int wait_for_reply(long wait_time)
h = table[n]; h = table[n];
sent_time = &seqmap_value->ping_ts; sent_time = &seqmap_value->ping_ts;
this_count = seqmap_value->ping_count; this_count = seqmap_value->ping_count;
this_reply = timeval_diff(&recv_time, sent_time); this_reply = timespec_diff(&recv_time, sent_time);
/* discard reply if delay is larger than timeout /* discard reply if delay is larger than timeout
* (see also: github #32) */ * (see also: github #32) */
if (this_reply > h->timeout) { if (ns_to_tick(this_reply) > h->timeout) {
return 1; return 1;
} }
@ -2261,9 +2294,9 @@ int wait_for_reply(long wait_time)
if (per_recv_flag) { if (per_recv_flag) {
if (timestamp_flag) { if (timestamp_flag) {
printf("[%lu.%06lu] ", printf("[%lu.%09lu] ",
(unsigned long)recv_time.tv_sec, (unsigned long)recv_time.tv_sec,
(unsigned long)recv_time.tv_usec); (unsigned long)recv_time.tv_nsec);
} }
avg = h->total_time / h->num_recv; avg = h->total_time / h->num_recv;
printf("%s%s : [%d], %d bytes, %s ms", printf("%s%s : [%d], %d bytes, %s ms",
@ -2424,7 +2457,8 @@ void add_name(char* name)
void add_addr(char* name, char* host, struct sockaddr* ipaddr, socklen_t ipaddr_len) void add_addr(char* name, char* host, struct sockaddr* ipaddr, socklen_t ipaddr_len)
{ {
HOST_ENTRY* p; HOST_ENTRY* p;
int n, *i; int n;
int64_t *i;
p = (HOST_ENTRY*)malloc(sizeof(HOST_ENTRY)); p = (HOST_ENTRY*)malloc(sizeof(HOST_ENTRY));
if (!p) if (!p)
@ -2454,7 +2488,7 @@ void add_addr(char* name, char* host, struct sockaddr* ipaddr, socklen_t ipaddr_
/* array for response time results */ /* array for response time results */
if (!loop_flag) { if (!loop_flag) {
i = (int*)malloc(trials * sizeof(int)); i = (int64_t*)malloc(trials * sizeof(int64_t));
if (!i) if (!i)
crash_and_burn("can't allocate resp_times array"); crash_and_burn("can't allocate resp_times array");
@ -2467,7 +2501,7 @@ void add_addr(char* name, char* host, struct sockaddr* ipaddr, socklen_t ipaddr_
#if defined(DEBUG) || defined(_DEBUG) #if defined(DEBUG) || defined(_DEBUG)
/* likewise for sent times */ /* likewise for sent times */
if (sent_times_flag) { if (sent_times_flag) {
i = (int*)malloc(trials * sizeof(int)); i = (int64_t*)malloc(trials * sizeof(int64_t));
if (!i) if (!i)
crash_and_burn("can't allocate sent_times array"); crash_and_burn("can't allocate sent_times array");
@ -2481,7 +2515,7 @@ void add_addr(char* name, char* host, struct sockaddr* ipaddr, socklen_t ipaddr_
/* schedule first ping */ /* schedule first ping */
p->ev_type = EV_TYPE_PING; p->ev_type = EV_TYPE_PING;
p->ev_time.tv_sec = 0; p->ev_time.tv_sec = 0;
p->ev_time.tv_usec = 0; p->ev_time.tv_nsec = 0;
ev_enqueue(p); ev_enqueue(p);
num_hosts++; num_hosts++;
@ -2571,46 +2605,55 @@ void print_warning(char* format, ...)
/************************************************************ /************************************************************
Function: timeval_diff Function: timespec_diff
************************************************************* *************************************************************
Inputs: struct timeval *a, struct timeval *b Inputs: struct timespec *a, struct timespec *b
Returns: long Returns: int64_t
Description: Description:
timeval_diff now returns result in hundredths of milliseconds timespec_diff now returns result in nanoseconds
ie, tens of microseconds
************************************************************/ ************************************************************/
long timeval_diff(struct timeval* a, struct timeval* b) int64_t timespec_ns(struct timespec* a)
{ {
long sec_diff = a->tv_sec - b->tv_sec; return (a->tv_sec * 1000000000LL) + a->tv_nsec;
if (sec_diff == 0) { }
return (a->tv_usec - b->tv_usec) / 10; int64_t timespec_10us(struct timespec* a)
} {
else if (sec_diff < 100) { return (a->tv_sec * 100000) + a->tv_nsec / 10000;
return (sec_diff * 1000000 + a->tv_usec - b->tv_usec) / 10; }
} void timespec_from_ns(struct timespec* a, uint64_t ns)
else { {
/* For such large differences, we don't really care about the microseconds... */ a->tv_sec = ns / 1000000000ULL;
return sec_diff * 100000; a->tv_nsec = ns % 1000000000ULL;
} }
int64_t timespec_diff(struct timespec* a, struct timespec* b)
{
return timespec_ns(a) - timespec_ns(b);
}
long timespec_diff_10us(struct timespec* a, struct timespec* b)
{
return (long)(timespec_10us(a) - timespec_10us(b));
} }
/************************************************************ /************************************************************
Function: timeval_add Function: timespec_add
*************************************************************/ *************************************************************/
void timeval_add(struct timeval* a, long t_10u) void timespec_add_10us(struct timespec* a, long t_10u)
{ {
t_10u *= 10; uint64_t ns = t_10u;
a->tv_sec += (t_10u + a->tv_usec) / 1000000; ns *= 10; // tick -> us
a->tv_usec = (t_10u + a->tv_usec) % 1000000; ns *= 1000; // us -> ns
a->tv_sec += (ns + a->tv_nsec) / 1000000000ULL;
a->tv_nsec = (ns + a->tv_nsec) % 1000000000ULL;
} }
/************************************************************ /************************************************************
@ -2630,32 +2673,33 @@ void timeval_add(struct timeval* a, long t_10u)
************************************************************/ ************************************************************/
char* sprint_tm(int t) const char* sprint_tm(int64_t ns)
{ {
static char buf[12]; static char buf[10];
double t = (double)ns / 1e6;
if (t < 0) { if (t < 0.0) {
/* negative (unexpected) */ /* negative (unexpected) */
sprintf(buf, "%.2g", (double)t / 100); sprintf(buf, "%.2g", (double)t / 1e9);
} }
else if (t < 100) { else if (t < 1.0) {
/* <= 0.99 ms */ /* <= 0.99 ms */
sprintf(buf, "0.%02d", t); sprintf(buf, "%.6f", t);
} }
else if (t < 1000) { else if (t < 10.0) {
/* 1.00 - 9.99 ms */ /* 1.00 - 9.99 ms */
sprintf(buf, "%d.%02d", t / 100, t % 100); sprintf(buf, "%.2f", t);
} }
else if (t < 10000) { else if (t < 100.0) {
/* 10.0 - 99.9 ms */ /* 10.0 - 99.9 ms */
sprintf(buf, "%d.%d", t / 100, (t % 100) / 10); sprintf(buf, "%.1f", t);
} }
else if (t < 100000000) { else if (t < 1000000.0) {
/* 100 - 1'000'000 ms */ /* 100 - 1'000'000 ms */
sprintf(buf, "%d", t / 100); sprintf(buf, "%d", (int)t);
} }
else { else {
sprintf(buf, "%.2e", (double)(t / 100)); sprintf(buf, "%.2e", t);
} }
return (buf); return (buf);
@ -2707,8 +2751,8 @@ void ev_enqueue(HOST_ENTRY* h)
#if defined(DEBUG) || defined(_DEBUG) #if defined(DEBUG) || defined(_DEBUG)
if (trace_flag) { if (trace_flag) {
long st = timeval_diff(&h->ev_time, &current_time); long st = timespec_diff_10us(&h->ev_time, &current_time);
fprintf(stderr, "Enqueue: host=%s, when=%d ms (%d, %d)\n", h->host, st / 100, h->ev_time.tv_sec, h->ev_time.tv_usec); fprintf(stderr, "Enqueue: host=%s, when=%ld ms (%ld, %ld)\n", h->host, st / 100, h->ev_time.tv_sec, h->ev_time.tv_nsec);
} }
#endif #endif
@ -2722,7 +2766,7 @@ void ev_enqueue(HOST_ENTRY* h)
} }
/* Insert on tail? */ /* Insert on tail? */
if (h->ev_time.tv_sec > ev_last->ev_time.tv_sec || (h->ev_time.tv_sec == ev_last->ev_time.tv_sec && h->ev_time.tv_usec >= ev_last->ev_time.tv_usec)) { if (timespec_diff(&h->ev_time, &ev_last->ev_time) >= 0) {
h->ev_next = NULL; h->ev_next = NULL;
h->ev_prev = ev_last; h->ev_prev = ev_last;
ev_last->ev_next = h; ev_last->ev_next = h;
@ -2734,7 +2778,7 @@ void ev_enqueue(HOST_ENTRY* h)
i = ev_last; i = ev_last;
while (1) { while (1) {
i_prev = i->ev_prev; i_prev = i->ev_prev;
if (i_prev == NULL || h->ev_time.tv_sec > i_prev->ev_time.tv_sec || (h->ev_time.tv_sec == i_prev->ev_time.tv_sec && h->ev_time.tv_usec >= i_prev->ev_time.tv_usec)) { if (i_prev == NULL || timespec_diff(&h->ev_time, &i_prev->ev_time) >= 0) {
h->ev_prev = i_prev; h->ev_prev = i_prev;
h->ev_next = i; h->ev_next = i;
i->ev_prev = h; i->ev_prev = h;

@ -66,7 +66,7 @@ void seqmap_init()
} }
} }
unsigned int seqmap_add(unsigned int host_nr, unsigned int ping_count, struct timeval* now) unsigned int seqmap_add(unsigned int host_nr, unsigned int ping_count, struct timespec* now)
{ {
unsigned int current_id; unsigned int current_id;
SEQMAP_VALUE* next_value; SEQMAP_VALUE* next_value;
@ -89,7 +89,7 @@ unsigned int seqmap_add(unsigned int host_nr, unsigned int ping_count, struct ti
next_value->host_nr = host_nr; next_value->host_nr = host_nr;
next_value->ping_count = ping_count; next_value->ping_count = ping_count;
next_value->ping_ts.tv_sec = now->tv_sec; next_value->ping_ts.tv_sec = now->tv_sec;
next_value->ping_ts.tv_usec = now->tv_usec; next_value->ping_ts.tv_nsec = now->tv_nsec;
/* increase next id */ /* increase next id */
current_id = seqmap_next_id; current_id = seqmap_next_id;
@ -98,7 +98,7 @@ unsigned int seqmap_add(unsigned int host_nr, unsigned int ping_count, struct ti
return current_id; return current_id;
} }
SEQMAP_VALUE* seqmap_fetch(unsigned int id, struct timeval* now) SEQMAP_VALUE* seqmap_fetch(unsigned int id, struct timespec* now)
{ {
SEQMAP_VALUE* value; SEQMAP_VALUE* value;

@ -7,14 +7,14 @@ typedef struct seqmap_value
{ {
unsigned int host_nr; unsigned int host_nr;
unsigned int ping_count; unsigned int ping_count;
struct timeval ping_ts; struct timespec ping_ts;
} SEQMAP_VALUE; } SEQMAP_VALUE;
#define SEQMAP_MAXSEQ 65535 #define SEQMAP_MAXSEQ 65535
void seqmap_init(); void seqmap_init();
unsigned int seqmap_add(unsigned int host_nr, unsigned int ping_count, struct timeval *now); unsigned int seqmap_add(unsigned int host_nr, unsigned int ping_count, struct timespec *now);
SEQMAP_VALUE *seqmap_fetch(unsigned int id, struct timeval *now); SEQMAP_VALUE *seqmap_fetch(unsigned int id, struct timespec *now);
#endif #endif

Loading…
Cancel
Save