OS/2, eCS & ArcaOS - Technical > Programming

DISKIO - preferred TIMER to use

(1/1)

Dariusz Piatkowski:
DISKIO uses a TIMER in order to track the duration of various data xfer events.

More specifically, provisions were made in the old code to account for an incorrectly working high-resolution timer on SMP machines.

Subsequently right at the start of DISKIO a call is made to determine which TIMER should be used by examining the CPU core count, and if >1 than we force the use of "standard MS counter":

Original Code

--- Code: ---// init flHiresTmr flag
// note: DosTmrQueryTime() API not works on OS/2 SMP as designed (thanks scott),
// so on SMP systems we must use other timer - standart MS counter.
void init_timer (void)
{
    int nCPUs = 0;

    if (DosQuerySysInfo (QSV_NUMPROCESSORS,
                         QSV_NUMPROCESSORS,
                         &nCPUs,
                         sizeof(nCPUs)) == NO_ERROR)
    {
        if (nCPUs > 1) flHiresTmr = 0;
    }
}

--- End code ---

My udpated code

--- Code: ---// init flHiresTmr flag
// note: DosTmrQueryTime() API does not work on OS/2 SMP as designed (thanks scott),
// so on SMP systems we must use other timer - standart MS counter.
void init_timer (void)
{
   //int iCPUs = 0; //moved this to a GLOBAL variable in diskio.h, v1.26

   if (DosQuerySysInfo (QSV_NUMPROCESSORS,    /* ordinal of first system variable */
                        QSV_NUMPROCESSORS, /* ordinal of the last system variable */
                        &iCPUs,              /* address of output data buffer */ 
                        sizeof(iCPUs))          /* size of output data buffer */
       == NO_ERROR)
   {
      if (iCPUs > 1)
         flHiresTmr = 1;
   }
         
   #ifdef DEBUG
      printf("\n DEBUG => CPU cores detected is: %d\n", iCPUs);
      printf(" DEBUG => flHiresTmr is: %d\n", flHiresTmr);
   #endif /* DEBUG */

} // end of init_timer

--- End code ---

...where I basically ignore that original comment and force flHiresTmr = 1, which also means that throughout DISKIO's execution I will always use the hi-res TIMER, that being through DosTmrQueryTime API.

OK, so when I had initially encountered this I thought to myself: umm, I recall we had some troubles in the past with the hi-res stuff being spotty. Firefox had encountered some of this, heck we even made use of the 'SET NSPR_OS2_NO_HIRES_TIMER=1' flag. But digging into this further, by all accounts today that no longer appears to be the case. My FF install no longer uses this, I have several other apps that use the hi-res TIMER, and I believe some work was done in the ACPI codebase to manage this better, although some opinions remainder for a while as to whether these changes were working or not.

Needless to say, my testing here appears to be showing correct results as the results match what the original DISKO logic was showing.

Here is a more specific example of code (API comments have been added by me, as well as some variable name changes) that relies on previous determination of what TIMER should be used:


--- Code: ---// use MS counter timer for SMP systems and HiRes Timer for any other
int start_timer (TIMER *tStart)
{
   if (flHiresTmr)
   {
      if (DosTmrQueryTime (tStart) != NO_ERROR)
      {
         printf("Timer error.\n");
         return (-1);
      }
   }
   else
   {
      tStart->ulHi = 0;
      if (DosQuerySysInfo (QSV_MS_COUNT,   /* ordinal of first system variable */
                           QSV_MS_COUNT,/* ordinal of the last system variable */
                           tStart,           /* address of output data buffer */
                           sizeof(tStart))      /* size of output data buffer */
          != NO_ERROR)
      {
         printf("Timer error.\n");
         return (-1);
      }
   }

   return (0);

} // end of start_timer

--- End code ---

My question to you all is: should we be still concerned about this?

I feel like simplifying the codebase is a good pursuit and if the hi-res TIMER works (which I understand to be the more precise one given that at the standard frequency the PIT chip runs at (roughly) 1.193182 MHz, so that gives us a microsecond precision as opposed to the ms stuff that DosQuerySysInfo is capable of), we should use it.

Dave Yeo:
While the Hi-Res timer is supposed to be fixed, as you noted, the fix is in ACPI, so depending on it would remove support for older versions of OS/2 including, IIRC, even early versions of ArcaOS that didn't have the fix.
Another thing is that once you fix diskio, it should be used to update sysbench, which uses diskio for the disk tests, and once again, nice if it works on older versions of OS/2

Lars:
You can also use the TIMER$ driver with all its known ill effects (high IRQ load, for example). Question is if that timer will too much interfere with the measurement itself ( decrease I/O performance due to the high IRQ rate of the timer).

Dariusz Piatkowski:
Hi Dave!


--- Quote from: Dave Yeo on December 27, 2024, 01:28:19 am ---While the Hi-Res timer is supposed to be fixed, as you noted, the fix is in ACPI, so depending on it would remove support for older versions of OS/2 including, IIRC, even early versions of ArcaOS that didn't have the fix.

--- End quote ---

Hmm, good point, I tend to be a little myopic in my vision of what works, that being the latest set of configurations as far as the main components are concerned.

So a quick look at the ACPI dev toolkit shows me at least two APIs I might be able to use:

1) AcpiTkGetVersion - "Returns the version numbers of various ACPI components including the toolkit API version", so this might be a viable way to look for that 'cut-off' where the hi-res TIMER go fixed?

2) AcpiTkValidateVersion - "This function is an easy and reliable way for all applications to determine if they are compatible with the installed ACPI", so in a sense knowing what that 'cut-off' ACPI level is (point #1 above) I might be able to use this API to make a quick check whether the target system is at sufficient ACPI level to use the hi-res TIMER


--- Quote from: Dave Yeo on December 27, 2024, 01:28:19 am ---...Another thing is that once you fix diskio, it should be used to update sysbench, which uses diskio for the disk tests, and once again, nice if it works on older versions of OS/2

--- End quote ---

Absolutely, my goal is to overcome some of the current DISKIO hurdles, get it stable enough (i.e. working for a sufficient large pool of testers & configurations), and then pick this up to retrofit into SysBench.

Dariusz Piatkowski:
Hello Lars,


--- Quote from: Lars on December 27, 2024, 12:21:32 pm ---You can also use the TIMER$ driver with all its known ill effects (high IRQ load, for example). Question is if that timer will too much interfere with the measurement itself ( decrease I/O performance due to the high IRQ rate of the timer).

--- End quote ---

Most of this stuff is brand spankin' new to me (as far as actual hands-on code work), however I've done enough reading and doing a few pieces here and there to at least (I hope lol) understand the bigger playing field, point being: my conclusions below may not be spot-on, but I hope at least I'm moving in the right direction.

I looked at the TIMER$ option but concluded, for all the reasons you pointed out above, that this would not be a good option to pursue further given the timing precision needed.

There is an interesting approach highlighted in an EDM/2 article from a few years back: "http://www.edm2.com/index.php?title=High_Resolution_Timing_under_OS/2&oldid=78884" by Timur Tabi that covers this pretty well.

In fact, for me at least it answered (well, almost) the question of "could I pull in the timer information that modern day CPUs already contain, specifically the RDTSC stuff?".

Where I'm a little fuzzy on is whether this API - DevHelp_GetDOSVar, subfunction DHGETDOSV_SYSINFOSEG - can be used in non device driver code???

The example shown in that article is:

--- Code: ---...
USHORT usrc;                    /* Return Code. */
USHORT TickCount;               /* Number of ticks per call */
void NEAR TimerHandler(void);   /* Callback function */
PGINFOSEG pGlobalInfoSeg;       /* Pointer to Global Info Seg */

usrc = DevHelp_GetDOSVar(DHGETDOSV_SYSINFOSEG, 0, &pGlobalInfoSeg);
...

--- End code ---

...but the whole timer topic is waaaaayyyy above my head already!  ???

Navigation

[0] Message Index

Go to full version