7

Does anybody know x86 instructions that can be used to measure time? Is the timer that leads to task switches accessible by software?

2

3 Answers 3

14

Ways to measure time on an x86 platform:

  • Real Time Clock - The source of time and date for your OS. 1 second precision. The only time source in a standard PC that can be used to measure absolute time.

  • 8254 Counter/Timers - A standard counter/timer chip that has been present on motherboards since the dawn of PC (now a functional block inside the chipset). This is the traditional source of IRQ0, the timer interrupt that does task switching in most older OSes.

  • RDTSC assembly instruction - Counts CPU clock cycles. See the answer Anon ymous posted for some usage details. Pretty much the highest level of precision you can find for a time source on x86. However, it has some gotchas with accuracy. Also the most convenient option if you are writing in assembly.

  • RDTSCP assembly instruction - Similar to RDTSC, but is serialized, which resolves some of the accuracy issues with RDTSC. Only found on the newest processors.

  • HPET - Introduced around the Core Duo era of PCs. Intended to be a replacement for the venerable 8254. Modern OSes will use this as their task scheduling interrupt (Vista and later)

  • Proprietary Timers in the Chipset - Some chipsets have special timers built into them for Power Management and Multimedia functions. You can sometimes commandeer these for your own application, assuming you are dealing with a fixed-function embedded system and not a general purpose PC.

Note that not all of these options will be available to you depending on your OS and Hardware. If you are running under a modern OS (Windows, Linux), it will take control of the 8254/HPET for its own timing needs, and thus they will be unavailable for you.

Under a modern Operating System, it is usually best to use the OS-provided timing functions. The OS developers have probably worked out a lot of the issues that you will run into on your own if you try to use it. (Note that the OS may provide multiple timing functions. Pick the one that is suitable for your application.)

2

You can use rdtsc.Just deducts previous value from present value to calculate between time difference.

Loads the current value of the processor’s time-stamp counter (a 64-bit MSR) into the EDX:EAX registers. The EDX register is loaded with the high-order 32 bits of the MSR and the EAX register is loaded with the low-order 32 bits. (On processors that support the Intel 64 architecture, the high-order 32 bits of each of RAX and RDX are cleared.)

This is a C code which implements this instruction :-

unsigned long long int rdtsc(void)
{
   unsigned long long int x;
   unsigned a, d;

   __asm__ volatile("rdtsc" : "=a" (a), "=d" (d));

   return ((unsigned long long)a) | (((unsigned long long)d) << 32);;
}
2
  • 1
    Note that RDTSC has a few limitations that can affect accuracy: (1) It is not serializing, and may get affected by the contents of the CPU pipeline. (2) CPU frequency can fluctuate due to Power Management, Intel Turbo Boost, or Thermal Throttling. (3) In a multi-CPU/multicore system, which core did that instruction execute on? Commented Sep 4, 2012 at 13:03
  • @msemack Current (2016) processors with rdtscp handle case (1), apparently.
    – JAB
    Commented Oct 27, 2016 at 21:58
0

Here is a FORTRAN callable routine that does it:

The assembler instruction RDTSC returns a 64-bit integer which is the number of CPU clock counts since the year dot. If your FORTRAN has 64-bit integers, the argument KOUNT is just declared to be INTEGER*8. Else declare it to be an array of two 32-bit INTEGER*4's

So in your FORTRAN program you write

CALL TIMERR(KOUNT)

at the start, save the value of KOUNT, then repeat at the end. Then subtract the two 64-bit values to determine the elapsed time. I generally only bother to subtract the two lower words, as what I time is usually less than 2^32 system clocks

It's also callable from C, but I don't speak C.

; C This assembler routine looks to FORTRAN like this:
;       SUBROUTINE TIMERR(KOUNT)
;       INTEGER*4 KOUNT(2);  or INTEGER*8 KOUNT
;       ...get a 64-but system time value into KOUNT......
;       RETURN
;       END
;
.Code
_TIMERR@4: RDTSC
         Push Eax
    Push Ecx
    Push Edx
    Mov Ecx, [Esp + 16]
    Mov [Ecx], Eax
    Mov [Ecx + 4], Edx
    Pop Edx
    Pop Ecx
    Pop Eax
    Ret 4

Not the answer you're looking for? Browse other questions tagged or ask your own question.