delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2007/01/05/17:36:42

X-Authentication-Warning: delorie.com: mail set sender to djgpp-workers-bounces using -f
In-Reply-To: <OFACB4C4B1.4472CEFA-ON8725725A.00631AB0-8725725A.00639428@LocalDomain>
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: <OFB2FA9B9C.E9085AD3-ON8725725A.007A5416-8725725A.007C1E9E@seagate.com>
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
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

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 <libc/stubs.h>
#include <time.h>
#include <dpmi.h>
#include <limits.h>

#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

- Raw text -


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