【问题标题】:Why cublas on GTX Titan is slower than single threaded CPU code?为什么 GTX Titan 上的 cublas 比单线程 CPU 代码慢?
【发布时间】:2014-02-28 21:33:23
【问题描述】:

我正在我的 GTX Titan 上测试 Nvidia Cublas 库。我有以下代码:

#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 活动查询软件,您将看到该程序的 GPU 使用率约为 %1。也许 GPU 根本不会激活 3d 时钟频率。尝试将两个大小分别为 4096x4096 的矩阵相乘 (dgemm/sgemm)。还要重复此操作至少 10 次并获得平均时间。优化后的 cuda 可以轻松地比您的 cpu 好 10 倍。

标签: c++ performance cuda gpgpu cublas


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    我认为您应该阅读以下内容:

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

    主要有三点,我将简要评论一下:

    • GPU 擅长通过大量计算隐藏延迟(如果您可以在计算和数据传输之间取得平衡),这里的内存访问量很大(带宽有限 strong> 问题)并且没有足够的计算来隐藏延迟,这确实会影响您的性能。

    • 此外,数据只读取一次,因此缓存功能根本不会被利用,而 CPU 非常擅长预测接下来将访问哪些数据。

    • 另外,您还要对分配时间进行计时..这意味着与主内存访问相比,PCI-E 总线时间非常慢。

    以上所有内容都呈现了您刚刚发布的示例,其中 CPU 优于 GPU 等大规模并行架构。

    针对此类问题的优化可能是:

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

    还有:http://www.nvidia.com/object/nvidia_research_pub_001.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-17
      • 2017-08-09
      • 2016-08-08
      • 2014-07-21
      • 1970-01-01
      • 2015-07-09
      • 1970-01-01
      • 2021-02-09
      相关资源
      最近更新 更多