0

i am attempting to use rdtsc for a timer, but both the eax and edx registers either remain empty or they form a number very different from the one given by the __rdtsc function from MS's instrin.h library.

here's the assembly code:

.model flat, c

.code

get_curr_cycle proc
cpuid
cpuid
cpuid
xor eax, eax ; empty eax register
xor edx, edx ; empty edx register
rdtsc
shl edx, 32 ; shift high bits to the left
or edx, eax ; or the high bits to the low bits
mov eax, edx ; move the final result into eax
retn
get_curr_cycle endp

end

and here is the c++ code:

#include <iostream>
#include <intrin.h>

extern "C" long long get_curr_cycle();

int main()
{
    long long t1 = __rdtsc();
    long long t2 = get_curr_cycle();

    for(unsigned int i = 0; i <= 10; ++i)
    {
        printf("%d - %d\n", t1, t2);
    }

    getchar();

    return 0;
}

here's my last output:

87592744 - 31162
87592744 - 31162
87592744 - 31162
87592744 - 31162
87592744 - 31162
87592744 - 31162
87592744 - 31162
87592744 - 31162
87592744 - 31162
87592744 - 31162
87592744 - 31162
Michael Petch
  • 46,082
  • 8
  • 107
  • 198
tb044491
  • 144
  • 7
  • 1
    Two things that stand out: First, why do you clear the result registers `eax` and `edx` *after* the `rdtsc` instruction? Secondly, what happens when you shift all 32 bits of a 32-bit register of the left end? – Some programmer dude May 17 '20 at 23:35
  • first thing is a copying error. my original code has those before the rdtsc. second one is retardation, you're right. – tb044491 May 17 '20 at 23:52

1 Answers1

2

According to Wikipedia:

The instruction RDTSC returns the TSC in EDX:EAX. In x86-64 mode, RDTSC also clears the higher 32 bits of RAX and RDX.

So, on x86, your code can simply be:

get_curr_cycle proc
rdtsc
retn
get_curr_cycle endp

Which will return the current timer value in edx:eax.

On x64, you can do:

get_curr_cycle proc
rdtsc
shl rdx, 32
or rax, rdx
retn
get_curr_cycle endp

This will return the timer value in rax.

Also, your format specifiers for printf are wrong. They should be %lld.

Paul Sanders
  • 24,133
  • 4
  • 26
  • 48
  • 2
    You do still want `lfence` before `rdtsc` to wait for earlier instructions to retire before allowing `rdtsc` to run. That's presumably why the OP was using `cpuid`. See [How to get the CPU cycle count in x86\_64 from C++?](https://stackoverflow.com/a/51907627) for more about RDTSC. – Peter Cordes May 18 '20 at 22:41