Тесты на quick-bench.com намного быстрее с отключенными оптимизациями - PullRequest
2 голосов
/ 30 сентября 2019

Я создал очень простой тест для иллюстрации оптимизации коротких строк и запустил его на quick-bench.com . Эталонный тест работает очень хорошо для сравнения класса строк с отключенным / включенным SSO, и результаты очень согласуются с GCC и Clang. Однако я понял, что когда я отключаю оптимизацию, сообщаемое время примерно в 4 раза быстрее, чем наблюдаемое при включенных оптимизациях (-O2 или -O3), как с GCC, так и с Clang.

Тест здесь: http://quick -bench.com / DX2G2AdxUb7sGPE-zLRa41-MCk0 .

Есть идеи, что может привести к тому, что неоптимизированный тест будет работать в 4 раза быстрее?

К сожалению,Я не вижу сгенерированную сборку;не знаю, где проблема (флажок «Запись разборки» установлен, но не влияет на мои прогоны). Кроме того, когда я запускаю бенчмарк локально с помощью Google Benchmark, результаты ожидаются, то есть оптимизированный бенчмарк работает быстрее.

Я также попытался сравнить оба варианта в Compiler Explorer, и неоптимизированный, по-видимому, выполняет гораздо большеинструкция: https://godbolt.org/z/I4a171.

1 Ответ

2 голосов
/ 30 сентября 2019

Итак, как обсуждалось в комментариях, проблема заключается в том, что quick-bench.com показывает не абсолютное время для кода, измеренного в тестах, а скорее время относительно времени, которое занял тест без опций. Контрольный тест no-op можно найти в исходных файлах quick-bench.com:

static void Noop(benchmark::State& state) {
    for (auto _ : state) benchmark::DoNotOptimize(0);
}

Все тесты прогона скомпилированы вместе. Поэтому флаги оптимизации применимы и к нему.

Воспроизведение и сравнение безоперационного бенчмарка для разных уровней оптимизации можно видеть, что с 6 до 7 раз происходит ускорение-O0 до -O1 версия. При сравнении прогонов тестов, выполненных с различными флагами оптимизации, этот фактор в базовой линии должен учитываться для сравнения результатов. Таким образом, 4-кратное ускорение, наблюдаемое в контрольном задании вопроса, более чем компенсировано, и поведение действительно такое, как можно было бы ожидать. что для -O0 в коде google-benchmark есть некоторые утверждения и другие дополнительные ветви, оптимизированные для более высоких уровней оптимизации.

Кроме того, при -O0 каждая итерация цикла загружается в регистр,изменять и сохранять в памяти части state несколько раз, например, для уменьшения счетчика цикла и условных выражений на счетчике цикла, в то время как версия -O1 будет хранить state в регистрах, что делает ненужной загрузку / сохранение памяти в цикле,Первый из них гораздо медленнее, он занимает не менее нескольких циклов на итерацию для необходимых пересылок хранилища и / или перезагрузок из памяти.

...