решение rdtsc из исполнения заказа? - PullRequest
0 голосов
/ 14 февраля 2019

Я пытаюсь заменить clock_gettime (CLOCK_REALTIME, & ts) на rdtsc для сравнения времени выполнения кода с точки зрения циклов процессора, а не времени сервера.Время выполнения кода тестирования критически важно для программного обеспечения.Я пытался запустить код на x86_64 3,20 ГГц Ubuntu на изолированном ядре и получил следующие цифры:

case 1: время получения часов: 24 нано секунд

void gettime(Timespec &ts) {
        clock_gettime(CLOCK_REALTIME, &ts);
}

случай 2: rdtsc (без защиты и защиты компилятора): 10 нс

void rdtsc(uint64_t& tsc) {
        unsigned int lo,hi;
        __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
        tsc = ((uint64_t)hi << 32) | lo;
}

случай 3: rdtsc (с mfence и барьером компилятора): 30 нс

void rdtsc(uint64_t& tsc) {
        unsigned int lo,hi;
        __asm__ __volatile__ ("mfence;rdtsc" : "=a" (lo), "=d" (hi) :: "memory");
        tsc = ((uint64_t)hi << 32) | lo;
}

Проблема здесь в том, что мне известно о том, что rdtsc является несериализационным вызовом и может быть переупорядочен ЦП,альтернативой является rdtscp, который является сериализованным вызовом, но инструкции после вызова rdtscp могут быть переупорядочены перед вызовом rdtscp.Использование барьера памяти увеличивает время выполнения.

  • Какой самый оптимальный и лучший способ для сравнения кода, чувствительного к задержке?
  • Есть ли способ оптимизировать случаи, о которых я упоминал?

1 Ответ

0 голосов
/ 14 февраля 2019

Вы хотите, чтобы lfence;rdtsc - запустили часы, и rdtscp;lfence остановили часы, поэтому барьеры находятся за пределами временного интервала.

(Или иногда вы хотите lfence;rdtsc;lfence для запуска часов, для дополнительной повторяемости за счет дополнительных накладных расходов.)

MFENCE - неправильная инструкция для этого;не гарантируется сериализация потока команд (но на практике это происходит в Skylake с современным микрокодом, чтобы исправить ошибку).LFENCE сериализует поток команд, не дожидаясь, пока буфер хранилища опустеет, только для ROB.Это всегда верно для Intel, но на AMD только с включенным смягчением Spectre, что делает lfence не просто NOP.(Полагаю, AMD не переупорядочивает movntdqa загрузки из памяти WC, поэтому lfence не имеет смысла в качестве барьера памяти, а только полезен в качестве барьера выполнения против спекулятивного выполнения или для RDTSC.)

См. Также Получить счетчик циклов ЦП? , в котором есть раздел о сериализации rdtsc.Но вам также не нужен встроенный ассемблер для этого;используйте __rdtsc() и _mm_lfence().(Но, как обычно, с микробенчмарками, неплохая идея проверить вывод asm компилятора, чтобы убедиться, что он сделал то, что вы хотите.)


Вы не можете избежать накладных расходов, это всегда будетбыть значительным по сравнению со стоимостью пары инструкций.

Также clflush для аннулирования строки кэша с помощью функции C для примера вычитания накладных расходов на измерения.

Но также обратите внимание, что обычно более полезно помещать тестируемый код в цикл, потому что задержка выполнения до того, как результат будет готов, является более значимой, чем ожидание, пока инструкция (ы) фактически не удалится из ROB.См. RDTSCP в NASM всегда возвращает одно и то же значение для примера (в asm) измерения одного insn для пропускной способности / задержки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...