From: Gerrit Renker Date: Tue, 24 Feb 2009 19:30:50 +0000 (+0100) Subject: Timer Utilities X-Git-Url: http://sjero.net/git/?p=iperf;a=commitdiff_plain;h=fad82d47d76abc8f4ac6767e58b89859ad35a2ca Timer Utilities Apart from extending the Timestamp class (support for measuring elapsed time and an `after' test), the main point of this patch is to update the delay_loop() function. The present implementation used a tight loop of continually calling gettimeofday(2) until the specified amount of time has passed. This is resource-intensive. In addition, while the loop worked reasonably in many cases, it sometimes caused unwanted delays of 50 milliseconds or more (process preempted?). This has been replaced with nanosleep(2) as default now. The advantage of nanosleep over the old solution is that signals are blocked and it seems a much more robust solution. Also, nanosleep uses the hrtimers interface internally (/usr/src/davem-2.6/Documentation/hrtimers/hrtimers.txt). For people who would like to keep the old behaviour, #ifdefs with alternatives have been added. --- diff --git a/compat/delay.cpp b/compat/delay.cpp index 9fc69c6..5d42469 100644 --- a/compat/delay.cpp +++ b/compat/delay.cpp @@ -51,19 +51,31 @@ * ------------------------------------------------------------------- */ #include "Timestamp.hpp" - +#include "util.h" #include "delay.hpp" /* ------------------------------------------------------------------- - * A micro-second delay function. This uses gettimeofday (underneith - * the Timestamp) which has a resolution of upto microseconds. I've - * found it's good to within about 10 usecs. - * I used to do calibration, but iperf automatically adjusts itself - * so that isn't necesary, and it causes some problems if the - * calibration adjustment is larger than your sleep time. + * A micro-second delay function. * ------------------------------------------------------------------- */ +void delay_loop(unsigned long usec) +{ +#ifdef SLEEP_VIA_SELECT + // This is a hack but works apparently quite well + // I found that it sometimes under-estimates the timeout + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = usec; -void delay_loop( unsigned long usec ) { + select(1, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &tv); +#elif defined(SLEEP_OLD_METHOD) + /* Tis uses gettimeofday (underneath the Timestamp), which has a + * resolution of upto microseconds. I've found it's good to within + * about 10 usecs. I used to do calibration, but iperf automatically + * adjusts itself so that isn't necesary, and it causes some problems + * if the calibration adjustment is larger than your sleep time. + * Note: I found this has problems - if the loop gets interrupted, + * long sleeps can result. I found up to 50..60msec. -- Gerrit */ Timestamp end; end.add( usec * 1e-6 ); @@ -71,4 +83,14 @@ void delay_loop( unsigned long usec ) { while ( now.before( end ) ) { now.setnow(); } +#else + // This is preferred; it is even better than usleep (see manpage). + struct timespec ts; + + ts.tv_sec = 0; + ts.tv_nsec = usec * 1000L; + + if (nanosleep(&ts, NULL) < 0) + WARN_errno(1, "nanosleep"); +#endif } diff --git a/include/Timestamp.hpp b/include/Timestamp.hpp index ae05f85..d98bcfc 100644 --- a/include/Timestamp.hpp +++ b/include/Timestamp.hpp @@ -151,6 +151,16 @@ public: (mTime.tv_usec - right.tv_usec); } + /* ------------------------------------------------------------------- + * Return the number of microseconds from now to last time of setting. + * ------------------------------------------------------------------- */ + long delta_usec(void) { + struct timeval previous = mTime; + + setnow(); + return subUsec(previous); + } + /* ------------------------------------------------------------------- * subtract the right timestamp from my timestamp. * return the difference in seconds as a floating point. @@ -199,15 +209,6 @@ public: mTime.tv_usec < kMillion ); } - /* ------------------------------------------------------------------- - * return true if my timestamp is before the right timestamp. - * ------------------------------------------------------------------- */ - bool before( Timestamp right ) { - return mTime.tv_sec < right.mTime.tv_sec || - (mTime.tv_sec == right.mTime.tv_sec && - mTime.tv_usec < right.mTime.tv_usec); - } - /* ------------------------------------------------------------------- * return true if my timestamp is before the right timestamp. * ------------------------------------------------------------------- */ @@ -216,15 +217,17 @@ public: (mTime.tv_sec == right.tv_sec && mTime.tv_usec < right.tv_usec); } + bool before( Timestamp right ) { return before(right.mTime); } /* ------------------------------------------------------------------- * return true if my timestamp is after the right timestamp. * ------------------------------------------------------------------- */ - bool after( Timestamp right ) { - return mTime.tv_sec > right.mTime.tv_sec || - (mTime.tv_sec == right.mTime.tv_sec && - mTime.tv_usec > right.mTime.tv_usec); + bool after( timeval right ) { + return mTime.tv_sec > right.tv_sec || + (mTime.tv_sec == right.tv_sec && + mTime.tv_usec > right.tv_usec); } + bool after( Timestamp right ) { return after(right.mTime); } /** * This function returns the fraction of time elapsed after the beginning