Как точно измерить тактовые циклы, используемые функцией c ++? - PullRequest
3 голосов
/ 03 февраля 2009

Я знаю, что должен использовать: rdtsc. Измеренная функция является детерминированной, но результат далеко не повторяется (я получаю 5% колебаний от запуска к запуску) Возможные причины:

  • переключение контекста
  • кеш пропускает

Знаете ли вы какие-либо другие причины? Как их устранить?

Ответы [ 6 ]

5 голосов
/ 03 февраля 2009

TSC (что использует rdtsc ) часто не синхронизируются в многопроцессорных системах. Это может помочь установить привязку к процессору, чтобы привязать процесс к одному процессору.

Вы также можете получить временные метки от таймеров HPET , если они доступны, которые не подвержены той же проблеме.

Что касается повторяемости, эти отклонения верны. Вы можете отключить кеширование, отдать приоритет процессу в реальном времени и / или (если в Linux или чем-то подобном) перекомпилировать ваше ядро ​​с более низкой фиксированной частотой прерывания по таймеру (той, которая выполняет квантование по времени). Вы не можете полностью устранить дисперсию, по крайней мере, не легко и не в обычных комбинациях CPU + OS.

В общем, для удобства кодирования, надежности и переносимости я предлагаю вам использовать то, что может предложить ОС. Если он предлагает высокоточные таймеры, используйте соответствующий помощник ОС.

(На всякий случай, если вы пытаетесь провести временную атаку на криптосистему, вам придется смириться с 1. этой случайностью и 2. общей защитой, которая делает систему непредсказуемой по уважительным причинам, поэтому функция может быть не детерминированной по времени.)

РЕДАКТИРОВАТЬ: добавлен параграф о таймеры, которые может предложить ОС.

РЕДАКТИРОВАТЬ: Это относится к Linux. Для привязки процесса к одному ЦП (для точного чтения из RDTSC) вы можете использовать sched_setaffinity (2) . И здесь - это некоторый код из одного из моих проектов, использующий его для каких-то других целей (отображение потоков на процессоры). Это должно быть вашей первой попыткой. Что касается HPET, вы можете использовать обычные вызовы POSIX, такие как , эти , при условии, что ядро ​​и компьютер поддерживают эти таймеры.

2 голосов
/ 02 апреля 2011

На самом деле в новых ядрах Linux появилась новая подсистема perf. Пример:

$ ./perf stat du -s /tmp
94796   /tmp

 Performance counter stats for 'du -s /tmp':

          2.546403 task-clock-msecs         #      0.060 CPUs 
                 3 context-switches         #      0.001 M/sec
                 0 CPU-migrations           #      0.000 M/sec
               166 page-faults              #      0.065 M/sec
           2434963 cycles                   #    956.236 M/sec
           1798092 instructions             #      0.738 IPC  
            302969 branches                 #    118.979 M/sec
             26197 branch-misses            #      8.647 %    
             23217 cache-references         #      9.118 M/sec
              4621 cache-misses             #      1.815 M/sec

        0.042406580  seconds time elapsed
2 голосов
/ 03 февраля 2009

Зачем их устранять? Похоже, вы создали реалистичный тест. Этот код будет иметь такую ​​же изменчивость при использовании в дикой природе. Вероятно, хуже, так как вы, вероятно, устранили задержки в кеше диска и процессора. Использование подхода Джона Скита, создание условий, дающих вам наилучший результат, оставит вас только с результатом, который заставляет вас чувствовать себя хорошо, но никогда не достижим.

Если важно абсолютное число, рассчитайте медиану, а не среднее.

2 голосов
/ 03 февраля 2009

См. Вопрос Допустим ли сравнительный анализ секундомера? для дискурса о дисперсии микропроцессорных тестов на современном многоядерном многопоточном многопроцессорном станке.

Хотя вопрос касается Java, соображения применимы к тестированию на любом языке.

См. Также: Как написать правильный микро-бенчмарк на Java?

Alse see: Какой совет вы можете дать мне для написания значимого теста?

1 голос
/ 03 февраля 2009

Добавление к списку причин: предсказание / неправильное предсказание ветвлений (это может быть вызвано переключением контекста со сложными кэшами предсказания на некоторых чипах. Также на предсказание могут влиять различные входные данные вашей программы и прямое сравнение два разных набора данных могут быть слегка искажены.

В общем, все это почти невозможно смягчить, но есть некоторые вещи, которые вы можете сделать, чтобы помочь каждому:

  • Отсутствие кэша: «Заполните» кэш перед началом синхронизации. Не забывайте, что есть кэш инструкций, который также необходимо заполнить. Для небольших наборов данных просто запустите весь тест один раз без синхронизации, а затем повторите его с синхронизацией. Для больших наборов данных сделайте это, но затем используйте команду предварительного кэширования процессора, чтобы загрузить первый блок данных обратно в кэш.
  • Переключение контекста: используйте многопроцессорную / базовую микросхему в слегка загруженной системе и установите привязку процесса к конкретному ЦП (предпочтительно не ЦП 0). Это также поможет с ошибками в кеше (поскольку перемещение ЦП означает, что кеш полностью утерян) и предсказанием переходов (поскольку на самом деле это форма кеша).

Но, конечно же, безусловно, лучший способ выполнения таких таймингов - это делать их очень много раз на очень больших фрагментах данных, так что изменчивость, вносимая вещами, которые вы не можете контролировать, сводится к минимуму. (Это никогда не удастся стереть.)

0 голосов
/ 03 февраля 2009

Большинство современных процессоров поддерживают замечательный набор низкоуровневых аппаратных счетчиков производительности. Если вы действительно хотите знать ответы, в том числе реальные измерения ошибок кэша и издержек переключения контекста, возьмите инструментарий PAPI (Performance API), затем на некоторых (хотя и не на всех) ОС установите одно исправление ядра и, приложив дополнительные усилия, вы уже в работе.

...