Измерение разницы во времени с использованием RDTSC - слишком большие результаты - PullRequest
1 голос
/ 18 мая 2019

Я пытаюсь вычислить количество циклов ЦП, необходимых для запуска одной инструкции ASM.Для этого я создал эту функцию:

measure_register_op:
    # Calculate time of required for movl operation

    # function setup
    pushl %ebp
    movl %esp, %ebp
    pushl %ebx
    pushl %edi

    xor %edi, %edi

    # first time measurement
    xorl %eax, %eax
    cpuid               # sync of threads
    rdtsc               # result in edx:eax

    # we are measuring instuction below
    movl %eax, %edi     

    # second time measurement
    cpuid               # sync of threads
    rdtsc               # result in edx:eax

    # time difference
    sub %eax, %edi

    # move to EAX. Value of EAX is what function returns
    movl %edi, %eax

    # End of function
    popl %edi
    popl %ebx
    mov %ebp, %esp
    popl %ebp

    ret

Я использую ее в файле * .c:

extern unsigned int measure_register_op();

int main(void)
{

    for (int a = 0; a < 10; a++)
    {
        printf("Instruction took %u cycles \n", measure_register_op());
    }

    return 0;
}

Проблема в том, что значения, которые я вижуслишком велики.Я получаю 3684414156 сейчас.Что может пойти не так?

РЕДАКТИРОВАТЬ: Изменен с EBX на EDI, но результат все еще похож.Это должно быть что-то с самим rdtsc.В отладчике я вижу, что результаты второго измерения с 0x7f61e078 и первым 0x42999940, который после вычитания все еще дает около 1019758392

РЕДАКТИРОВАТЬ: Вот мой make-файл.Возможно, я неправильно его компилирую:

compile: measurement.s measurement.c
    gcc -g measurement.s measurement.c -o ./build/measurement -m32

РЕДАКТИРОВАТЬ: Вот точный результат, который я вижу:

Instruction took 4294966680 cycles 
Instruction took 4294966696 cycles 
Instruction took 4294966688 cycles 
Instruction took 4294966672 cycles 
Instruction took 4294966680 cycles 
Instruction took 4294966688 cycles 
Instruction took 4294966688 cycles 
Instruction took 4294966696 cycles 
Instruction took 4294966688 cycles 
Instruction took 4294966680 cycles 

Ответы [ 2 ]

5 голосов
/ 18 мая 2019

cpuid clobbers ebx и много других регистров. Вам следует воздержаться от использования cpuid здесь или сохранить значение там, где оно не будет засорено.

4 голосов
/ 18 мая 2019

В вашей версии обновления, которая не сокращает время запуска (ошибка @R. Указала):

sub %eax, %edi вычисляет start - end.Это отрицательное число , то есть огромное число без знака чуть ниже 2 ^ 32.Если вы собираетесь использовать %u, то при отладке привыкните к интерпретации его вывода обратно в битовый шаблон.

Вы хотите end - start.

И, кстати, используйте lfence;это значительно эффективнее, чем cpuid.Гарантируется сериализация инструкции выполнение на Intel (без очистки буфера хранилища, как полная инструкция сериализации).Это также безопасно на ЦП AMD с включенным смягчением спектра .

См. Также http://akaros.cs.berkeley.edu/lxr/akaros/kern/arch/x86/rdtsc_test.c о некоторых различных способах сериализации RDTSC и / или RDTSCP.


См. Также Получить счетчик циклов ЦП? , чтобы узнать больше о RDTSC, особенно о том, что он не учитывает такты ядра, а только эталонные циклы.Так что холостой ход / турбо повлияет на ваши результаты.

Кроме того, стоимость одной инструкции не является одномерной. Не очень полезно синхронизировать одну инструкцию с RDTSC, как это .См. RDTSCP в NASM всегда возвращает одно и то же значение для получения дополнительной информации о том, как измерить пропускную способность / задержку / мопов для одной инструкции.

RDTSC может быть полезен для синхронизации всего цикла или более длинной последовательностиинструкции, больше, чем окно выполнения OoO вашего CPU.

...