delorie.com/archives/browse.cgi   search  
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 -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019