summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2004-09-21 20:21:40 +0000
committerrwatson <rwatson@FreeBSD.org>2004-09-21 20:21:40 +0000
commit3165926b59afb76d1dff978887ebe7b62f58cfa3 (patch)
tree9487eb71cfc18d6fcaa09bf2fcc32b51cfcbf2eb /tools
parenta4c12f80064a9009ad12611adb31c37c72ee9eca (diff)
downloadFreeBSD-src-3165926b59afb76d1dff978887ebe7b62f58cfa3.zip
FreeBSD-src-3165926b59afb76d1dff978887ebe7b62f58cfa3.tar.gz
Improve netsend timing logic in various ways:
- Centralize time comparison. - Check clock resolution to make sure it has enough granularity to implement the desired wait interval. - Keep track of how many times the timing loop has to spin waiting for the next send time; report statistics. - Add commented out warning about deadlines being missed when spinning. - Improve statistics reporting generally to provide a more useful summary of sender condition after a run.
Diffstat (limited to 'tools')
-rw-r--r--tools/tools/netrate/netsend/netsend.c91
1 files changed, 78 insertions, 13 deletions
diff --git a/tools/tools/netrate/netsend/netsend.c b/tools/tools/netrate/netsend/netsend.c
index 91c937b..4bccfae 100644
--- a/tools/tools/netrate/netsend/netsend.c
+++ b/tools/tools/netrate/netsend/netsend.c
@@ -61,21 +61,45 @@ timespec_add(struct timespec *tsa, struct timespec *tsb)
}
}
+static __inline int
+timespec_ge(struct timespec *a, struct timespec *b)
+{
+
+ if (a->tv_sec > b->tv_sec)
+ return (1);
+ if (a->tv_sec < b->tv_sec)
+ return (0);
+ if (a->tv_nsec >= b->tv_nsec)
+ return (1);
+ return (0);
+}
+
/*
* Busy wait spinning until we reach (or slightly pass) the desired time.
* Optionally return the current time as retrieved on the last time check
- * to the caller.
+ * to the caller. Optionally also increment a counter provided by the
+ * caller each time we loop.
*/
int
-wait_time(struct timespec ts, struct timespec *wakeup_ts)
+wait_time(struct timespec ts, struct timespec *wakeup_ts, long long *waited)
{
struct timespec curtime;
curtime.tv_sec = 0;
curtime.tv_nsec = 0;
- while (curtime.tv_sec < ts.tv_sec || curtime.tv_nsec < ts.tv_nsec) {
- if (clock_gettime(CLOCK_REALTIME, &curtime) < -1) {
+ if (clock_gettime(CLOCK_REALTIME, &curtime) == -1) {
+ perror("clock_gettime");
+ return (-1);
+ }
+#if 0
+ if (timespec_ge(&curtime, &ts))
+ printf("warning: wait_time missed deadline without spinning\n");
+#endif
+ while (timespec_ge(&ts, &curtime)) {
+ if (waited != NULL)
+ (*waited)++;
+ if (clock_gettime(CLOCK_REALTIME, &curtime) == -1) {
perror("clock_gettime");
return (-1);
}
@@ -94,11 +118,23 @@ int
timing_loop(int s, struct timespec interval, long duration, u_char *packet,
u_int packet_len)
{
- struct timespec starttime, tmptime;
+ struct timespec nexttime, starttime, tmptime;
+ long long waited;
u_int32_t counter;
long finishtime;
+ int send_errors, send_calls;
+
+ if (clock_getres(CLOCK_REALTIME, &tmptime) == -1) {
+ perror("clock_getres");
+ return (-1);
+ }
- if (clock_gettime(CLOCK_REALTIME, &starttime) < -1) {
+ if (timespec_ge(&tmptime, &interval))
+ fprintf(stderr,
+ "warning: interval less than resolution (%d.%09lu)\n",
+ tmptime.tv_sec, tmptime.tv_nsec);
+
+ if (clock_gettime(CLOCK_REALTIME, &starttime) == -1) {
perror("clock_gettime");
return (-1);
}
@@ -106,14 +142,17 @@ timing_loop(int s, struct timespec interval, long duration, u_char *packet,
tmptime.tv_nsec = 0;
timespec_add(&starttime, &tmptime);
starttime.tv_nsec = 0;
- if (wait_time(starttime, NULL) == -1)
+ if (wait_time(starttime, NULL, NULL) == -1)
return (-1);
+ nexttime = starttime;
finishtime = starttime.tv_sec + duration;
+ send_errors = send_calls = 0;
counter = 0;
+ waited = 0;
while (1) {
- timespec_add(&starttime, &interval);
- if (wait_time(starttime, &tmptime) == -1)
+ timespec_add(&nexttime, &interval);
+ if (wait_time(nexttime, &tmptime, &waited) == -1)
return (-1);
/*
* We maintain and, if there's room, send a counter. Note
@@ -131,12 +170,34 @@ timing_loop(int s, struct timespec interval, long duration, u_char *packet,
*((u_int32_t *)packet) = htonl(counter);
counter++;
}
- if (send(s, packet, packet_len, 0) < 0)
+ if (send(s, packet, packet_len, 0) < 0) {
perror("send");
+ send_errors++;
+ }
+ send_calls++;
if (duration != 0 && tmptime.tv_sec >= finishtime)
- return (0);
+ goto done;
+ }
+
+done:
+ if (clock_gettime(CLOCK_REALTIME, &tmptime) == -1) {
+ perror("clock_gettime");
+ return (-1);
}
+ printf("\n");
+ printf("start: %d.%09lu\n", starttime.tv_sec,
+ starttime.tv_nsec);
+ printf("finish: %d.%09lu\n", tmptime.tv_sec,
+ tmptime.tv_nsec);
+ printf("send calls: %d\n", send_calls);
+ printf("send errors: %d\n", send_errors);
+ printf("approx send rate: %ld\n", (send_calls - send_errors) /
+ duration);
+ printf("approx error rate: %ld\n", (send_errors / send_calls));
+ printf("waited: %lld\n", waited);
+ printf("approx wait rate: %lld\n", waited / send_calls);
+
return (0);
}
@@ -175,7 +236,8 @@ main(int argc, char *argv[])
/*
* Specify an arbitrary limit. It's exactly that, not selected by
- * any particular strategy.
+ .* any particular strategy. '0' is a special value meaning "blast",
+ * and avoids the cost of a timing loop.
*/
rate = strtoul(argv[4], &dummy, 10);
if (rate < 1 || *dummy != '\0')
@@ -196,7 +258,10 @@ main(int argc, char *argv[])
}
bzero(packet, payloadsize);
- if (rate == 1) {
+ if (rate == 0) {
+ interval.tv_sec = 0;
+ interval.tv_nsec = 0;
+ } else if (rate == 1) {
interval.tv_sec = 1;
interval.tv_nsec = 0;
} else {
OpenPOWER on IntegriCloud