X-Authentication-Warning: delorie.com: mail set sender to djgpp-workers-bounces using -f In-Reply-To: Subject: Re: Performance enhancement for gettimeofday()? To: djgpp-workers AT delorie DOT com X-Mailer: Lotus Notes Release 6.5.4 CCH5 September 12, 2005 Message-ID: From: Gordon DOT Schumacher AT seagate DOT com Date: Fri, 5 Jan 2007 15:35:42 -0700 X-MIMETrack: Serialize by Router on SV-GW1/Seagate Internet(Release 7.0.1 HF29|March 07, 2006) at 01/05/2007 02:35:48 PM MIME-Version: 1.0 Content-type: text/plain; charset=US-ASCII X-Proofpoint-FWRule: outbound2 X-Proofpoint-Virus-Version: vendor=fsecure engine=4.65.5446:2.3.11,1.2.37,4.0.164 definitions=2007-01-05_03:2007-01-03,2006-12-29,2007-01-05 signatures=0 Reply-To: djgpp-workers AT delorie DOT com Errors-To: nobody AT delorie DOT com X-Mailing-List: djgpp-workers AT delorie DOT com X-Unsubscribes-To: listserv AT delorie DOT com Precedence: bulk Gordon Schumacher/Seagate wrote on 01/05/2007 11:07:39 AM: # Accuracy/safety could perhaps be improved by putting in an extra check to # get the date and time from DOS when the elapsed tick count is greater than # a certain amount. A few improvements in this version, and the addition of a test program. This one checks for wrap on the clock tick counter (which should be pretty rare, but better safe than sorry), and also goes back to the RTC after either a clock wrap or once an hour. There's also a bug fix to computing the microseconds. I've run the test program briefly, and am currently running it for an extended test. The maximum reported error appears to range from on order 5mS behind, to about 70mS ahead of the RTC (note that this does not take computation time into account). (To build the test program by itself - without rebuilding libc - you can stick an underscore or two in front of the function name...) #include #include #include #include #define US_PER_CLOCK (1000000 / CLOCKS_PER_SEC) #define CLOCK_T_MAX INT_MAX int gettimeofday(struct timeval *tv, struct timezone *tz) { static clock_t startclock = 0; static struct timeval starttime; struct timeval tv_tmp; if (!tv) tv = &tv_tmp; if (startclock == 0) { __dpmi_regs r; struct tm tmblk; startclock = clock(); r.h.ah = 0x2c; __dpmi_int(0x21, &r); starttime.tv_usec = r.h.dl * 10000; tmblk.tm_sec = r.h.dh; tmblk.tm_min = r.h.cl; tmblk.tm_hour = r.h.ch; r.h.ah = 0x2a; __dpmi_int(0x21, &r); tmblk.tm_mday = r.h.dl; tmblk.tm_mon = r.h.dh - 1; tmblk.tm_year = (r.x.cx & 0x7ff) - 1900; tmblk.tm_wday = tmblk.tm_yday = tmblk.tm_gmtoff = 0; tmblk.tm_zone = 0; tmblk.tm_isdst = -1; starttime.tv_sec = mktime(&tmblk); tv->tv_sec = starttime.tv_sec; tv->tv_usec = starttime.tv_usec; } else { clock_t curclock = clock(); unsigned long clockdiff; if (curclock >= startclock) clockdiff = (unsigned long) (curclock - startclock); else { clockdiff = ((unsigned long) CLOCK_T_MAX + curclock) - startclock; startclock = 0; // Recalibrate now... } tv->tv_sec = starttime.tv_sec + (clockdiff / CLOCKS_PER_SEC); tv->tv_usec = starttime.tv_usec + ((clockdiff % CLOCKS_PER_SEC) * US_PER_CLOCK); if (tv->tv_usec >= 1000000) { tv->tv_sec++; tv->tv_usec -= 1000000; } // Recalibrate against the RTC once an hour if (clockdiff > 65520) startclock = 0; } if(tz) { struct tm *tmloc = localtime(&(tv->tv_sec)); tz->tz_minuteswest = - tmloc->tm_gmtoff / 60; tz->tz_dsttime = tmloc->tm_isdst; } return 0; } #if defined(TEST) int main() { int start, end, i; struct tm tmblk; struct timeval rtc, tod; time_t rtc_secs, tod_secs; char timestr[25]; unsigned long maxusec = 0; __dpmi_regs r; double maxposerror = 0.0F, maxnegerror = 0.0F; while (!kbhit()) { double curerror; r.h.ah = 0x2c; __dpmi_int(0x21, &r); rtc.tv_usec = r.h.dl * 10000; tmblk.tm_sec = r.h.dh; tmblk.tm_min = r.h.cl; tmblk.tm_hour = r.h.ch; r.h.ah = 0x2a; __dpmi_int(0x21, &r); tmblk.tm_mday = r.h.dl; tmblk.tm_mon = r.h.dh - 1; tmblk.tm_year = (r.x.cx & 0x7ff) - 1900; tmblk.tm_wday = tmblk.tm_yday = tmblk.tm_gmtoff = 0; tmblk.tm_zone = 0; tmblk.tm_isdst = -1; rtc_secs = rtc.tv_sec = mktime(&tmblk); gettimeofday(&tod, NULL); tod_secs = tod.tv_sec; if (tod.tv_usec > maxusec) maxusec = tod.tv_usec; curerror = difftime(rtc_secs, tod_secs) + ((rtc.tv_usec - tod.tv_usec) / 1000000.0F); if (curerror > maxposerror) maxposerror = curerror; if (curerror < maxnegerror) maxnegerror = curerror; strftime(timestr, sizeof(timestr), "%m/%d/%y %H:%M:%S", localtime(&tod_secs)); printf("\rThe time now is %s.%ld ", timestr, tod.tv_usec); } printf("\nMaximum value of usec is %ld\n", maxusec); printf("Maximum errors are %f and %f\n", maxposerror, maxnegerror); return 0; } #endif