std::inner_product в 4 раза быстрее, чем ручной, но SIMD не используется?

Мне было интересно как std::inner_product() выполняет по сравнению с ручным вычислением точечного произведения, поэтому я сделал тест.

std::inner_product() был в 4 раза быстрее, чем ручная реализация. Я нахожу это странным, потому что на самом деле не так много способов рассчитать это?! Я также не вижу никаких регистров SSE/AVX, используемых в точке расчета.

Настройка: VS2013/MSVC(12?), Процессор Haswell i7 4770, 64-разрядная компиляция, режим выпуска.

Вот код теста C++:

#include <iostream>
#include <functional>
#include <numeric>
#include <cstdint>

int main() {
   const int arraySize = 1000;
   const int numTests = 500;
   unsigned int x, y = 0;
   unsigned long long* array1 = new unsigned long long[arraySize];
   unsigned long long* array2 = new unsigned long long[arraySize];

   //Initialise arrays
   for (int i = 0; i < arraySize; i++){
      unsigned long long val = __rdtsc();
      array1[i] = val;
      array2[i] = val;
   }

   //std::inner_product test
   unsigned long long timingBegin1 = __rdtscp(&s);
   for (int i = 0; i < numTests; i++){
      volatile unsigned long long result = std::inner_product(array1, array1 + arraySize, array2, static_cast<uint64_t>(0));
   }
   unsigned long long timingEnd1 = __rdtscp(&s);

   f, s = 0;

   //Manual Dot Product test
   unsigned long long timingBegin2 = __rdtscp(&f);
   for (int i = 0; i < numTests; i++){
      volatile unsigned long long result = 0;

      for (int i = 0; i < arraySize; i++){
         result += (array1[i] * array2[i]);
      }
   }
   unsigned long long timeEnd2 = __rdtscp(&f);


   std::cout << "STL:     :  " << static_cast<double>(finish1 - start1) / numTests << " CPU cycles per dot product" << std::endl;
   std::cout << "Manually :  " << static_cast<double>(finish2 - start2) / numTests << " CPU cycles per dot product" << std::endl;

1 ответ

Решение

Ваш тест плох, и это, вероятно, будет иметь большое значение.

volatile uint64_t result = 0;

for (int i = 0; i < arraySize; i++){
   result += (array1[i] * array2[i]);

Обратите внимание, как вы постоянно используете volatileпеременная здесь. Это заставляет компилятор записывать временные результаты в память.

В отличие от вашего inner_product версия:

volatile uint64_t result = std::inner_product(array1, array1 + arraySize, array2, static_cast<uint64_t>(0));

сначала вычисляет внутренний продукт, что позволяет оптимизировать, и только потом присваивает результат volatileчетвертая переменная.

Другие вопросы по тегам