Почему cublas на GTX Titan медленнее однопоточного кода процессора?

Я тестирую библиотеку Nvidia Cublas на своем GTX Titan. У меня есть следующий код:

#include "cublas.h"#include <stdlib.h>
#include <conio.h>
#include <Windows.h>
#include <iostream>
#include <iomanip>

/* Vector size */
#define N (1024 * 1024 * 32)

/* Main */
int main(int argc, char** argv)
{
LARGE_INTEGER frequency;
LARGE_INTEGER t1, t2;

float* h_A;
float* h_B;
float* d_A = 0;
float* d_B = 0;

/* Initialize CUBLAS */
cublasInit();

/* Allocate host memory for the vectors */
h_A = (float*)malloc(N * sizeof(h_A[0]));
h_B = (float*)malloc(N * sizeof(h_B[0]));

/* Fill the vectors with test data */
for (int i = 0; i < N; i++)
{
h_A[i] = rand() / (float)RAND_MAX;
h_B[i] = rand() / (float)RAND_MAX;
}

QueryPerformanceFrequency(&frequency);
QueryPerformanceCounter(&t1);
/* Allocate device memory for the vectors */
cublasAlloc(N, sizeof(d_A[0]), (void**)&d_A);
cublasAlloc(N, sizeof(d_B[0]), (void**)&d_B);

/* Initialize the device matrices with the host vectors */
cublasSetVector(N, sizeof(h_A[0]), h_A, 1, d_A, 1);
cublasSetVector(N, sizeof(h_B[0]), h_B, 1, d_B, 1);

/* Performs operation using cublas */
float res = cublasSdot(N, d_A, 1, d_B, 1);

/* Memory clean up */
cublasFree(d_A);
cublasFree(d_B);

QueryPerformanceCounter(&t2);
double elapsedTime = (t2.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
std::cout << "GPU time = " << std::setprecision(16) << elapsedTime << std::endl;
std::cout << "GPU result = " << res << std::endl;

QueryPerformanceFrequency(&frequency);
QueryPerformanceCounter(&t1);
float sum = 0.;
for (int i = 0; i < N; i++) {
sum += h_A[i] * h_B[i];
}
QueryPerformanceCounter(&t2);
elapsedTime = (t2.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
std::cout << "CPU time = " << std::setprecision(16) << elapsedTime << std::endl;
std::cout << "CPU result = " << sum << std::endl;

free(h_A);
free(h_B);

/* Shutdown */
cublasShutdown();

getch();

return EXIT_SUCCESS;
}

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

GPU time = 164.7487009845991
GPU result = 8388851
CPU time = 45.22368030957917
CPU result = 7780599.5

Почему использование библиотеки cublas на GTX Titan в 3 раза медленнее, чем вычисления на одном ядре IvyBridge Xeon 2,4 ГГц?
Когда я увеличиваю или уменьшаю размеры вектора, я получаю те же результаты: GPU медленнее, чем CPU. Двойная точность не меняет этого.

4

Решение

Потому что скалярное произведение — это функция, которая использует каждый элемент вектора только один раз. Это означает, что время отправки его на видеокарту намного больше, чем рассчитывать все на процессоре, потому что PCIExpress намного медленнее, чем оперативная память.

9

Другие решения

Я думаю, что вы должны прочитать это:

http://blog.theincredibleholk.org/blog/2012/12/10/optimizing-dot-product/

Есть три основных момента, я кратко их прокомментирую:

  • GPU хороши в скрытие задержек с большим количеством вычислений (если вы можете балансировать между вычислениями и передачей данных), здесь к памяти обращаются много (ограниченная пропускная способность проблема) и не хватает вычислений, чтобы скрыть задержки, которые, действительно, убивают ваши выступления.

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

  • Плюс ты также время выделения времени.. это означает, что время шины PCI-E очень мало по сравнению с доступом к основной памяти.

Все вышеперечисленное отображает пример, который вы только что опубликовали, в котором ЦП превосходит массивную параллельную архитектуру, такую ​​как ваш графический процессор.

Оптимизация для такой проблемы может быть:

  • Хранение данных на устройстве в максимально возможной степени
  • Наличие потоков вычисляет больше элементов (и таким образом скрывает задержки)

Также: http://www.nvidia.com/object/nvidia_research_pub_001.html

6