Mail Archives: djgpp-workers/2007/03/13/08:27:48
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: | <OFD4358C0E.C4408663-ON8725729D.004963B8-8725729D.0049D724@seagate.com>
|
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
|
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 <libc/stubs.h>
#include <time.h>
#include <dpmi.h>
#include <limits.h>
#include <sys/gcc.h>
/*
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 <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 -