为什么GTX Titan上的cublas比单线程CPU代码慢?

4
我正在测试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

为什么在GTX Titan上使用cublas库计算速度比一个Xeon 2.4GHz IvyBridge核心慢3倍? 当我增加或减少向量大小时,得到的结果相同:GPU比CPU慢。双精度也没有改变这种情况。


如果您查看任何GPU活动查询软件,您将看到该程序约%1的GPU使用率。也许GPU根本不会激活3D时钟频率。尝试对两个大小为4096x4096的矩阵进行乘法(dgemm/sgemm)。并且至少重复这个过程10次并获得平均时间。优化的CUDA可以比您的CPU轻松提高10倍。 - huseyin tugrul buyukisik
2个回答

9

由于点积是一个只使用每个向量元素一次的函数,这意味着将其发送到显卡的时间比在 CPU 上计算所有内容要长得多,因为 PCIExpress 比 RAM 慢得多。


6
我认为你应该阅读这篇文章:http://blog.theincredibleholk.org/blog/2012/12/10/optimizing-dot-product/。有三个主要观点,我会简要评论一下:
  • GPU擅长使用大量计算来隐藏延迟(如果您可以在计算和数据传输之间平衡),在这里内存被频繁访问(带宽受限问题)并且没有足够的计算来隐藏延迟,而延迟确实会降低性能。

  • 此外,数据仅被读取一次,因此缓存能力根本没有得到利用,而CPU非常擅长预测下一个访问的数据。

  • 再加上你也在计时分配时间...这意味着PCI-E总线时间非常慢,与主内存访问相比很慢。

以上所有内容使得你刚刚发布的示例成为CPU优于像GPU这样的大规模并行体系结构的情况。

针对这种问题的优化可能包括:

  • 尽可能将数据保留在设备上
  • 使线程计算更多的元素(从而隐藏延迟)

另外:http://www.nvidia.com/object/nvidia_research_pub_001.html


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接