我是 CUDA 初学者,正在阅读一些推力教程。我编写了一个简单但组织严密的代码,并试图计算出推力的加速度。(这个想法正确吗?)。我尝试通过在 cpu 上添加数组并在 gpu 上添加 device_vector 来将两个 vector (具有 10000000 int)添加到另一个 vector 。
事情是这样的:
#include <iostream>
#include "cuda.h"
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <thrust/device_vector.h>
#include <thrust/host_vector.h>
#define N 10000000
int main(void)
{
float time_cpu;
float time_gpu;
int *a = new int[N];
int *b = new int[N];
int *c = new int[N];
for(int i=0;i<N;i++)
{
a[i]=i;
b[i]=i*i;
}
clock_t start_cpu,stop_cpu;
start_cpu=clock();
for(int i=0;i<N;i++)
{
c[i]=a[i]+b[i];
}
stop_cpu=clock();
time_cpu=(double)(stop_cpu-start_cpu)/CLOCKS_PER_SEC*1000;
std::cout<<"Time to generate (CPU):"<<time_cpu<<std::endl;
thrust::device_vector<int> X(N);
thrust::device_vector<int> Y(N);
thrust::device_vector<int> Z(N);
for(int i=0;i<N;i++)
{
X[i]=i;
Y[i]=i*i;
}
cudaEvent_t start, stop;
cudaEventCreate(&start);
cudaEventCreate(&stop);
cudaEventRecord(start,0);
thrust::transform(X.begin(), X.end(),
Y.begin(),
Z.begin(),
thrust::plus<int>());
cudaEventRecord(stop,0);
cudaEventSynchronize(stop);
float elapsedTime;
cudaEventElapsedTime(&elapsedTime,start,stop);
std::cout<<"Time to generate (thrust):"<<elapsedTime<<std::endl;
cudaEventDestroy(start);
cudaEventDestroy(stop);
getchar();
return 0;
}
CPU 结果看起来非常快,但是 gpu 在我的机器上运行非常慢(i5-2320,4G,GTX 560 Ti),CPU 时间大约是 26,GPU 时间大约是 30!我只是在我的代码中犯了愚蠢的错误吗?还是有更深层次的原因?
作为一名 C++ 菜鸟,我一遍又一遍地检查我的代码,但在 GPU 上的推力速度仍然较慢,所以我做了一些实验来展示用五种不同的方法计算 vectorAdd 的差异。
我使用 Windows API QueryPerformanceFrequency()
作为统一的时间测量方法。
每个实验看起来像这样:
f = large_interger.QuadPart;
QueryPerformanceCounter(&large_interger);
c1 = large_interger.QuadPart;
for(int j=0;j<10;j++)
{
for(int i=0;i<N;i++)//CPU array adding
{
c[i]=a[i]+b[i];
}
}
QueryPerformanceCounter(&large_interger);
c2 = large_interger.QuadPart;
printf("Time to generate (CPU array adding) %lf ms\n", (c2 - c1) * 1000 / f);
这是我用于添加 GPU 数组的简单 __global__
函数:
__global__ void add(int *a, int *b, int *c)
{
int tid=threadIdx.x+blockIdx.x*blockDim.x;
while(tid<N)
{
c[tid]=a[tid]+b[tid];
tid+=blockDim.x*gridDim.x;
}
}
函数被称为:
for(int j=0;j<10;j++)
{
add<<<(N+127)/128,128>>>(dev_a,dev_b,dev_c);//GPU array adding
}
我将 vector a[N] 和 b[N] 添加到 vector c[N] 循环 10 次:
- 在 CPU 上添加数组
- 在 CPU 上添加 std::vector
- 在 CPU 上添加 thrust::host_vector
- 在 GPU 上添加 thrust::device_vector
- 在 GPU 上添加数组。这是结果
N=10000000
我得到了结果:
- CPU 阵列增加 268.992968ms
- CPU std::vector 添加 1908.013595ms
- CPU Thrust::host_vector 添加 10776.456803ms
- GPU Thrust::device_vector 添加 297.156610ms
- GPU 阵列增加 5.210573ms
这让我很困惑,我不熟悉模板库的实现。容器和原始数据结构之间的性能真的相差如此之大吗?
最佳答案
大部分执行时间花在初始化 X[i] 和 Y[i] 的循环中。虽然这是合法的,但这是一种初始化大型设备 vector 的非常缓慢的方法。最好创建宿主 vector ,初始化它们,然后将它们复制到设备。作为测试,像这样修改代码(在初始化设备 vector X[i] 和 Y[i] 的循环之后):
} // this is your line of code
std::cout<< "Starting GPU run" <<std::endl; //add this line
cudaEvent_t start, stop; //this is your line of code
然后您会看到 GPU 时序结果几乎在添加的行打印出来后立即出现。因此,您等待的所有时间都花在了直接从主机代码初始化这些设备 vector 上。
当我在我的笔记本电脑上运行它时,我得到大约 40 的 CPU 时间和大约 5 的 GPU 时间,因此对于您实际计时的代码部分,GPU 的运行速度比 CPU 快大约 8 倍。
如果创建 X 和 Y 作为主机 vector ,然后创建类似的 d_X 和 d_Y 设备 vector ,整体执行时间会更短,如下所示:
thrust::host_vector<int> X(N);
thrust::host_vector<int> Y(N);
thrust::device_vector<int> Z(N);
for(int i=0;i<N;i++)
{
X[i]=i;
Y[i]=i*i;
}
thrust::device_vector<int> d_X = X;
thrust::device_vector<int> d_Y = Y;
并将您的转换调用更改为:
thrust::transform(d_X.begin(), d_X.end(),
d_Y.begin(),
Z.begin(),
thrust::plus<int>());
好的,您现在已经指出 CPU 运行测量比 GPU 测量快。对不起,我仓促下了结论。我的笔记本电脑是 HP 笔记本电脑,配备 2.6GHz 核心 i7 和 Quadro 1000M GPU。我正在运行 centos 6.2 linux。一些评论:如果您在 GPU 上运行任何繁重的显示任务,这可能会降低性能。此外,在对这些东西进行基准测试时,通常的做法是使用相同的机制进行比较,如果需要,您可以对两者使用 cudaEvents,它可以为 CPU 代码计时,与 GPU 代码计时相同。此外,推力的常见做法是进行不计时的热身运行,然后重复测试以进行测量,同样,通常的做法是循环运行测试 10 次或更多次,然后除以得到平均值。在我的例子中,我可以看出 clocks() 测量值非常粗略,因为连续运行会给我 30、40 或 50。在 GPU 测量值上,我得到类似 5.18256 的值。其中一些可能会有所帮助,但我无法确切说明为什么您的结果和我的结果差异如此之大(在 GPU 方面)。
好的,我做了另一个实验。编译器将在 CPU 方面产生很大的不同。我用 -O3 开关编译,CPU 时间下降到 0。然后我将 CPU 计时测量从 clocks() 方法转换为 cudaEvents,我得到的 CPU 测量时间为 12.4(使用 -O3 优化),在 GPU 上仍然为 5.1边。
您的里程会因计时方法和您在 CPU 端使用的编译器而异。
关于c++ - 在我的机器上操作大 vector 时 CUDA 推力变慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12623574/