2

I'm trying to figure out how to read this assembly code in C++.

This is the code:

unsigned __int64 high_perf_time;
unsigned __int64 *dest = &high_perf_time;
__asm 
{
    _emit 0xf        // these two bytes form the 'rdtsc' asm instruction,
    _emit 0x31       //  available on Pentium I and later.
    mov esi, dest
    mov [esi  ], eax    // lower 32 bits of tsc
    mov [esi+4], edx    // upper 32 bits of tsc
}
__int64 time_s     = (__int64)(high_perf_time / frequency);  // unsigned->sign conversion should be safe here
__int64 time_fract = (__int64)(high_perf_time % frequency);  // unsigned->sign conversion should be safe here

I know 0xf 0x31 is rdtsc eax, edx, but what is mov esi,dest? How can I write that in C++?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
maor03
  • 23
  • 5
  • The `move esi, dest` instruction moves the contents of the `destination` location in the `esi` register. An equivalent is an assignment statement. – Thomas Matthews Feb 27 '23 at 16:51
  • You can't write to a register in C++. Or read from one. You need all those assembly instructions since MSVC has no syntax for specifying the output operands of an inline piece of assembly code. – Margaret Bloom Feb 27 '23 at 16:54
  • 1
    @MargaretBloom: WIth MSVC, you'd just use `QueryPerformanceCounter()` and `QueryPerformanceFrequency()` and not use inline assembly code at all. – Ben Voigt Feb 27 '23 at 17:16
  • @BenVoigt It depends on what OP wants to actually do. But they didn't say, that's why this is not a good question. I read it as asking how to store `edx:eax` in a variable without using assembly. I see your answer is what OP wanted. – Margaret Bloom Feb 27 '23 at 17:41
  • @MargaretBloomL Yes, it was necessary to abstract the task performed by those lines as not "copy edx and eax into a variable" but "store the rdtsc results into a variable". – Ben Voigt Feb 27 '23 at 18:33

2 Answers2

6

If you want to understand what these three instructions do:

The following three instructions:

    mov esi, dest
    mov [esi  ], eax    // lower 32 bits of tsc
    mov [esi+4], edx    // upper 32 bits of tsc

... are the equivalent of the following C++ code:

    uint32_t * esi = (uint32_t *)dest;
    esi[0] = eax;
    esi[1] = edx;

And because the x86 CPUs are "little-endian", this is equal to:

    *dest = (((__int64_t)edx)<<32) + (uint32_t)eax;

... however, because you cannot access the eax and edx registers directly using C++, this operation must be done in assembly code.

Martin Rosenau
  • 17,897
  • 3
  • 19
  • 38
  • "you cannot access the eax and edx registers directly using C++" -- True. "this operation must be done in assembly code" -- False. – Ben Voigt Feb 27 '23 at 17:20
  • 1
    @BenVoigt I was only referring to the last 3 lines of assembly code because the OP only asked about those lines. – Martin Rosenau Feb 27 '23 at 18:08
2

The C++ code is

#include <intrin.h>
unsigned __int64 high_perf_time = __rdtsc();

Documentation here: https://learn.microsoft.com/en-us/cpp/intrinsics/rdtsc

But you probably want QueryPerformanceCounter() and QueryPerformanceFrequency() instead, else you will have a race condition if your thread is scheduled on a different processor core between successive __rdtsc() calls.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • Thank you yes i read it in first core work great ! – maor03 Feb 27 '23 at 17:24
  • `__rdtscp` also gives you the core ID from the same instruction the TSC reading came from. If it was a different core you could just discard that measurement if it's for a short microbenchmark, since it had context-switch overhead. (Most modern CPUs in practice do have the TSC synced across cores, although it's not guaranteed, especially for multi-socket system.), @maor03 . – Peter Cordes Feb 28 '23 at 08:54
  • BTW, microbenchmarking is hard; just using `rdtscp` is not enough to reliably benchmark very short intervals; clock frequency varies, but TSC frequency doesn't, among other effects. See also [Idiomatic way of performance evaluation?](https://stackoverflow.com/q/60291987) – Peter Cordes Feb 28 '23 at 08:54