Mail Archives: djgpp-workers/2007/02/28/17:37:10
X-Authentication-Warning: | delorie.com: mail set sender to djgpp-workers-bounces using -f
|
Subject: | Final version of gettimeofday() patch
|
To: | djgpp-workers AT delorie DOT com
|
X-Mailer: | Lotus Notes Release 7.0.2 September 26, 2006
|
Message-ID: | <OF797A29F0.37D3281E-ON87257290.007B2DAD-87257290.007C2A0C@seagate.com>
|
From: | Gordon DOT Schumacher AT seagate DOT com
|
Date: | Wed, 28 Feb 2007 15:36:12 -0700
|
X-MIMETrack: | Serialize by Router on SV-GW1/Seagate Internet(Release 7.0.1 HF29|March 07, 2006) at
|
| 02/28/2007 02:36:15 PM
|
MIME-Version: | 1.0
|
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-02-28_06:2007-02-28,2007-02-27,2007-02-28 signatures=0
|
Reply-To: | djgpp-workers AT delorie DOT com
|
I've now got what I believe to be a finalized version of my proposed
changes to gettimeofday(). I'm running it to good effect here, and
you can feel free to try compiling it with -DTEST to build a sample
application that should check for drift against what the time that
DOS int21 reports. On my test systems the drift was negligible.
(And yes, I realize that I'm defining the clock frequency to far
more digits than necessary; better too many than too few, though.)
The include of <sys/gcc.h> is simply to pick up the macro definitions
for likely() and unlikely(); you can compile it just fine without
that header (which is new in my testing) by commenting out that
header include and adding the following instead:
#define likely(x) x
#define unlikely(x) x
I will include my proposal for <sys/gcc.h> in another message.
--- src/libc/dos/dos/gettimeo.c.orig 1995-03-11 03:42:42.000000000
-0700
+++ src/libc/dos/dos/gettimeo.c 2007-02-28 15:28:57.156250000 -0700
@@ -1,44 +1,164 @@
+/* Copyright (C) 2007 Gordon Schumacher, see COPYING.DJ for details */
/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
#include <libc/stubs.h>
#include <time.h>
#include <dpmi.h>
+#include <limits.h>
+#include <math.h>
+#include <sys/gcc.h>
+
+#undef CLOCKS_PER_SEC
+/*
+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))
+#define CLOCKS_PER_SEC 91.032548384232954545454545454545F
+#define CLOCK_T_MAX INT_MAX
int gettimeofday(struct timeval *tv, struct timezone *tz)
{
- __dpmi_regs r;
- struct tm tmblk;
- struct timeval tv_tmp;
-
-
- if (!tv)
- tv = &tv_tmp;
-
- r.h.ah = 0x2c;
- __dpmi_int(0x21, &r);
-
- tv->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;
-
- tv->tv_sec = mktime(&tmblk);
-
- if(tz)
- {
- struct tm *tmloc = localtime(&(tv->tv_sec));
- tz->tz_minuteswest = - tmloc->tm_gmtoff / 60;
- tz->tz_dsttime = tmloc->tm_isdst;
- }
- return 0;
+ static clock_t startclock = 0;
+ static struct timeval starttime;
+ 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
+ {
+ double secs;
+ clock_t curclock = clock();
+ unsigned long clockdiff;
+
+ if (likely(curclock >= startclock))
+ clockdiff = (unsigned long) (curclock - startclock);
+ else
+ {
+ clockdiff = ((unsigned long) CLOCK_T_MAX + curclock) -
startclock;
+ startclock = 0; // Recalibrate now...
+ }
+
+ secs = clockdiff / CLOCKS_PER_SEC;
+ tv->tv_sec = starttime.tv_sec + secs;
+ tv->tv_usec = starttime.tv_usec + ((secs - (long) secs) * 1000000);
+ if (unlikely(tv->tv_usec >= 1000000))
+ {
+ tv->tv_sec++;
+ tv->tv_usec -= 1000000;
+ }
+
+ // Recalibrate against the RTC about once an hour
+ // This should keep any error within one tick
+ if (unlikely(clockdiff > 65535))
+ 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 <stdio.h>
+
+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
+
+
- Raw text -