【问题标题】:CUDA kernel function taking longer than equivalent host functionCUDA 内核函数比等效的主机函数花费更长的时间
【发布时间】:2011-11-05 05:07:39
【问题描述】:

我正在关注http://code.google.com/p/stanford-cs193g-sp2010/ 和在线发布的视频讲座,做其中一个发布的问题集(第一个)我遇到了一些稍微违反直觉的事情,至少就问题的提问方式而言。该问题要求我根据我自己机器上运行的示例应用程序的时序假设线性缩放假设在 cpu 和 gpu 上执行时间的时序模型。

- 插入您计算机上代码打印的计时数字 研究该等式并报告盈亏平衡点 (当 cpu 版本和 gpu 版本一样快时)会。

我遇到的问题是我的内核比等效功能的主机版本花费的时间要长得多(我将在下面发布两者),因此没有收支平衡点。我得到的数字如下。

done with copy to gpu kernel
copy to gpu took 26.30630 ms
done with gpu shift cypher kernel
gpu shift cypher took 7.33203 ms
done with copy from gpu kernel
copy from gpu took 28.54141 ms
host shift cypher took 0.00186 ms
Worked! CUDA and reference output match. 

你认为我做事的方式有问题吗?这是内核和主机函数。

// This kernel implements a per element shift
__global__ void shift_cypher(unsigned int *input_array, unsigned int *output_array, 
    unsigned int shift_amount, unsigned int alphabet_max, unsigned int array_length)
{
    int gid = blockIdx.x * blockDim.x + threadIdx.x;
    output_array[gid] = (input_array[gid] + shift_amount)%(alphabet_max+1);
}

void host_shift_cypher(unsigned int *input_array, unsigned int *output_array, unsigned int shift_amount, unsigned int alphabet_max, unsigned int array_length)
{
  for(unsigned int i=0;i<array_length;i++)
  {
    int element = input_array[i];
    int shifted = element + shift_amount;
    if(shifted > alphabet_max)
    {
      shifted = shifted % (alphabet_max + 1);
    }
    output_array[i] = shifted;
  }
}

示例应用程序使用 16MB 的整数元素运行,块大小为 512。这是相关文件的完整源代码http://pastebin.com/htYH0bA2

【问题讨论】:

  • 您使用哪种 CPU 和 GPU 进行测试?斯坦福课堂的作业假设硬件类似于学生在实验室资源中提供的硬件(基本上是离散游戏 GPU)。对于您的硬件,如果您的 GPU 有点贫乏(例如,许多笔记本电脑型号),则可能没有收支平衡点。您知道您正在测试的 GPU 中有多少个 SM?
  • 我有一台 GT430(确切地说是这个 newegg.com/Product/Product.aspx?Item=N82E16814162067),CPU 是 AMD Phenom II X4 (3.4Ghz)。维基百科说 GPU 有 2 个流式多处理器。主机性能运行时间对您来说是典型的吗?它似乎非常短。
  • 这是我在一台大约 3 岁的笔记本电脑上的结果:host shift cypher took 280.5 ms。所以,主机版的时间似乎确实很遥远。
  • 我刚刚添加了一个睡眠时间为 1000 毫秒的睡眠功能,使用 start_timer/stop_timer 时报告为 0.00173 毫秒。您可以看到程序停止了 1 秒钟。我应该在我在 Windows 上的原始帖子中提到,也许它处理同步的方式有所不同,并且在主机函数完成之前调用了 stop_timer。我会尝试在我的 ubuntu 分区上设置它,看看会得到什么样的结果。
  • 我不必在我的 ubuntu 分区上设置它,我通过将 cudaThreadSynchronize 添加到 start_timer 来修复它。我现在得到大约 150 毫秒的主机代码和 1000 毫秒的 1 秒睡眠。

标签: c cuda gpgpu


【解决方案1】:

主机移位密码耗时 0.00186 毫秒

这看起来很奇怪。无论您在 CPU 上使用 16MB 做什么,都应该花费不到一毫秒的时间。

通过查看 pastebin 代码,您似乎可以使用 CUDA 事件来计时。虽然我没有使用它们,但我的猜测是你测量 GPU 内核执行的实际时间。在仅调用主机代码的情况下,这几乎没有。这真的是他们衡量在斯坦福课程中执行的主机代码的方式吗?

只要用任何类型的 C 计时器检查这个结果,你就可以证明我错了。

【讨论】:

  • 是的,它们提供了除 cuda 内核之外的所有内容,您应该将其编写为基本练习,我想知道定时器在 unix/windows 机器上的功能是否不同,我将把定时器功能换成主机代码看看进展如何。
【解决方案2】:

正如 w.m 所指出的,这是计时器的问题。我认为,问题在于计时器中的事件记录功能在记录事件之前将控制权移交给了基于 cpu 的主机功能。这有点令人困惑,因为您会认为记录事件会在主机代码执行期间发生,但似乎它正在做一些更像是同时记录开始和停止事件的事情,都是在主机代码完成执行之后。在开始计时器中添加cudaThreadSynchronize(); 似乎可以解决问题(确保在继续使用主机代码之前记录事件。这可能是仅 Windows 的差异或基于我的 CUDA 版本或硬件等,我不确定。在无论如何,我的新的、更正常的结果如下。

done with copy to gpu kernel
copy to gpu took 25.75683 ms
done with gpu shift cypher kernel
gpu shift cypher took 7.45667 ms
done with copy from gpu kernel
copy from gpu took 29.10922 ms
host shift cypher took 153.98772 ms
1 second sleep took 999.85291 ms
Worked! CUDA and reference output match. 

【讨论】:

  • 是的,我认为这是 windows 的问题,cudaEvent_t 在 *nix 系统中运行良好,我认为 clock_t 计时或 QueryPerformanceCounter/QueryPerformanceFrequency 在 windows 中应该是更好的选择。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-11-22
  • 2012-02-18
  • 1970-01-01
  • 2014-06-19
  • 2012-04-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多