Полностью перевернутый результат бенчмарка по лямбде против функции между GCC и Clang

#c #gcc #optimization #lambda #clang

#c #ссагпз #оптимизация #лямбда #clang

Вопрос:

Рассмотрим слегка измененную версию Фибоначчи, чтобы проверить производительность между (лямбда-функцией и функцией) (с и без) захватами:

 size_t fibFn(size_t n) {
  if (n <= 1) { return n; }
  return fibFn(n - 1)   fibFn(n - 2) 1 2;
//                                  ^~~~
//   This is modified so that I can | 
//        capture something outside |
//                    this function |
}
 

Когда я запустил это в Quickbench с Clang 10.0, я получил разумный результат:

fnNoCapture < лямбдаНоКаптура < fn << лямбда

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

lambdaNoCapture > fnNoCapture >> fn > лямбда

Как это возможно? Это потому, что два компилятора реализовали lambda по-разному?

РЕДАКТИРОВАТЬ: Тем не менее, для меня не имеет смысла, что лямбда-выражение (с захватом) может быть намного быстрее, чем без захвата. Лучший случай, который компилятор может оптимизировать, на мой взгляд, — это преобразовать лямбда-выражение с захватом в без захвата (например, путем встраивания переменных), если это возможно.

Комментарии:

1. С самого начала переключение оптимизации на O2 говорит о другом.

2. @sweenish Sry Я не уверен, что вы имели в виду, говоря «рассказывает другую историю», не могли бы вы уточнить?

3. Вы уверены, что компилятор не может заметить, что вы выполняете несколько раз одно и то же вычисление в цикле и сохраняете только одну итерацию?

4. @MarcGlisse Компилятор не должен это оптимизировать. Именно так должна работать библиотека Google Bench library.

5. Библиотека не может изменить то, что говорит язык. Возможно, если бы вы сделали N volatile или вызвали DoNotOptimize(N) в цикле перед вызовом функции… Результат остается удивительным, но соотношение уменьшается.