Дисперсия в накладных расходах RDTSC

Я создаю микротест для измерения изменений производительности, экспериментируя с использованием встроенных функций инструкций SIMD в некоторых примитивных операциях обработки изображений. Однако писать полезные микротесты сложно, поэтому я хотел бы сначала понять (и, если возможно, устранить) как можно больше источников вариаций и ошибок.

Один из факторов, который я должен учитывать, - это накладные расходы на сам код измерения. Я измеряю с помощью RDTSC, и я использую следующий код, чтобы найти накладные расходы на измерения:

extern inline unsigned long long __attribute__((always_inline)) rdtsc64() {
    unsigned int hi, lo;
        __asm__ __volatile__(
            "xorl %%eax, %%eax\n\t"
            "cpuid\n\t"
            "rdtsc"
        : "=a"(lo), "=d"(hi)
        : /* no inputs */
        : "rbx", "rcx");
    return ((unsigned long long)hi << 32ull) | (unsigned long long)lo;
}

unsigned int find_rdtsc_overhead() {
    const int trials = 1000000;

    std::vector<unsigned long long> times;
    times.resize(trials, 0.0);

    for (int i = 0; i < trials; ++i) {
        unsigned long long t_begin = rdtsc64();
        unsigned long long t_end = rdtsc64();
        times[i] = (t_end - t_begin);
    }

    // print frequencies of cycle counts
}

При запуске этого кода я получаю следующий результат:

Frequency of occurrence (for 1000000 trials):
234 cycles (counted 28 times)
243 cycles (counted 875703 times)
252 cycles (counted 124194 times)
261 cycles (counted 37 times)
270 cycles (counted 2 times)
693 cycles (counted 1 times)
1611 cycles (counted 1 times)
1665 cycles (counted 1 times)
... (a bunch of larger times each only seen once)

У меня следующие вопросы:

  1. Каковы возможные причины бимодального распределения количества циклов, генерируемого приведенным выше кодом?
  2. Почему самое быстрое время (234 цикла) происходит всего несколько раз - какое весьма необычное обстоятельство могло уменьшить счетчик?

Дополнительная информация

Платформа:

  • Linux 2.6.32 (Ubuntu 10.04)
  • g ++ 4.4.3
  • Core 2 Duo (E6600); это имеет постоянную скорость TSC.

SpeedStep отключен (процессор установлен в режим производительности и работает на частоте 2,4 ГГц); при работе в режиме «ondemand» я получаю два пика на 243 и 252 циклах и два (предположительно соответствующих) пика на 360 и 369 циклах.

Я использую sched_setaffinity , чтобы заблокировать процесс. одно ядро. Если я запускаю тест на каждом ядре по очереди (т. Е. Блокирую ядро ​​0 и запускаю, затем блокирую ядро ​​1 и запускаю), я получаю аналогичные результаты для двух ядер, за исключением того, что самое быстрое время в 234 цикла, как правило, немного в ядре 1 меньше раз, чем в ядре 0.

Команда компиляции:

g++ -Wall -mssse3 -mtune=core2 -O3 -o test.bin test.cpp

Код, который GCC генерирует для цикла ядра:

.L105:
#APP
# 27 "test.cpp" 1
    xorl %eax, %eax
    cpuid
    rdtsc
# 0 "" 2
#NO_APP
    movl    %edx, %ebp
    movl    %eax, %edi
#APP
# 27 "test.cpp" 1
    xorl %eax, %eax
    cpuid
    rdtsc
# 0 "" 2
#NO_APP
    salq    $32, %rdx
    salq    $32, %rbp
    mov %eax, %eax
    mov %edi, %edi
    orq %rax, %rdx
    orq %rdi, %rbp
    subq    %rbp, %rdx
    movq    %rdx, (%r8,%rsi)
    addq    $8, %rsi
    cmpq    $8000000, %rsi
    jne .L105
13
задан Mysticial 17 February 2013 в 18:34
поделиться