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.
This commit is contained in:
Robert Watson 2004-09-21 20:21:40 +00:00
parent cd3ee173f9
commit aa1cb3e183

View File

@ -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_gettime(CLOCK_REALTIME, &starttime) < -1) {
if (clock_getres(CLOCK_REALTIME, &tmptime) == -1) {
perror("clock_getres");
return (-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 {