Я изучаю результаты измерения производительности, используя регистр временных меток (TSR), найденный в процессорах x86. Это полезный регистр, поскольку он измеряет в монотонной единице времени, которая невосприимчива к часам изменение скорости. Очень круто.
Вот документ Intel, показывающий фрагменты ASM для надежного бенчмаркинга с использованием TSR, включая использование cpuid для синхронизации конвейера. См. Стр. 16:
Чтобы прочитать время начала, в нем говорится (я немного добавил комментарий):
__asm volatile (
"cpuid\n\t" // writes e[abcd]x
"rdtsc\n\t" // writes edx, eax
"mov %%edx, %0\n\t"
"mov %%eax, %1\n\t"
//
:"=r" (cycles_high), "=r" (cycles_low) // outputs
: // inputs
:"%rax", "%rbx", "%rcx", "%rdx"); // clobber
Мне интересно, почему регистры нуля используются для принятия значений edx
и eax
. Почему бы не удалить movs и прочитать значение TSR прямо из edx
и eax
? Вот так:
__asm volatile(
"cpuid\n\t"
"rdtsc\n\t"
//
: "=d" (cycles_high), "=a" (cycles_low) // outputs
: // inputs
: "%rbx", "%rcx"); // clobber
Таким образом, вы сохраняете два регистра, уменьшая вероятность того, что C компилятор, нуждающийся в разливе.
Я прав? Или эти MOV как-то стратегические?
(Я согласен, что вам нужны регистры царапин, чтобы прочитать время остановки, так как в этом случае порядок инструкций отменяется: у вас есть rdtscp,..., cpuid. Инструкция cpuid разрушает результат rdtscp).
Спасибо