X-Authentication-Warning: delorie.com: mail set sender to djgpp-workers-bounces using -f Subject: Update to gettimeofday() code To: djgpp-workers AT delorie DOT com X-Mailer: Lotus Notes Release 7.0.2 September 26, 2006 Message-ID: From: Gordon DOT Schumacher AT seagate DOT com Date: Tue, 13 Mar 2007 07:26:33 -0600 X-MIMETrack: Serialize by Router on SV-GW1/Seagate Internet(Release 7.0.1 HF29|March 07, 2006) at 03/13/2007 06:26:37 AM MIME-Version: 1.0 Content-type: text/plain; charset=US-ASCII X-Proofpoint-FWRule: outbound2 X-Proofpoint-Virus-Version: vendor=fsecure engine=4.65.5502:2.3.11,1.2.37,4.0.164 definitions=2007-03-13_04:2007-03-13,2007-03-13,2007-03-13 signatures=0 Reply-To: djgpp-workers AT delorie DOT com Here's my latest - I simply convert to microseconds first and work in a 64-bit int. That gives us more room than a clock_t holds ticks, so we have no worries there. The test run, after running for half an hour, looked like this: The time now is 03/13/07 07:21:00.501125 Maximum value of usec is 999999 Maximum errors are 0.019900 and -0.061150 /* Copyright (C) 2007 Gordon Schumacher, see COPYING.DJ for details */ /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ #include #include #include #include #include /* Thanks to Rod Pemberton for the math for the clock frequency. The exact calculation is as follows: 4 * ((4.5Mhz * 455) / 572) = 14.31818... MHz (4.5Mhz US TV bandwith/channel, 455 colorburst phase changes/line, 572 total lines/frame including sync) 14.318Mhz / 12 = 1.1931818... Mhz (The clock has a divisor of 12) 1.1931818... Mhz / 65536 ~= 18.2065Hz (65536 cycles per tick) Remember that clock() multiplies by 5! */ //#define CLOCKS_PER_SEC ((4 * ((4.5 * 455) / 572)) / (12 * 65536)) * 5 //#define CLOCKS_PER_SEC_EXACT 91.032548384232954545454545454545F #define CLOCK_T_MAX INT_MAX #define USEC_PER_CLOCK 10985U #define USEC_PER_SEC 1000000U #define RECAL_TIME 3600000000U int gettimeofday(struct timeval *tv, struct timezone *tz) { static clock_t startclock = 0; static struct timeval starttime; static unsigned long fudge = 0; struct timeval tv_tmp; if (!tv) tv = &tv_tmp; if (unlikely(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 long usecs; if (likely(curclock >= startclock)) usecs = (unsigned long long) (curclock - startclock); else { usecs = ((unsigned long long) CLOCK_T_MAX + curclock) - startclock; startclock = 0; // Recalibrate now... } usecs *= USEC_PER_CLOCK; // Apply the elapsed time, with the fudge factor... *tv = starttime; tv->tv_sec += (time_t) (usecs / USEC_PER_SEC); tv->tv_usec += usecs % USEC_PER_SEC; if (unlikely(tv->tv_usec >= 1000000)) { tv->tv_usec -= 1000000; tv->tv_sec++; } // Recalibrate against the RTC about once an hour // This should keep any error within one tick if (unlikely(usecs > RECAL_TIME)) 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) #include 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