我是一名CUDA初学者并正在阅读一些推力教程.我写了一个简单但非常有组织的代码并试图找出推力的加速度.(这个想法是否正确?).我尝试通过在cpu上添加数组并在gpu上添加device_vector,将两个向量(10000000 int)添加到另一个向量.
这是事情:
#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;
}
Run Code Online (Sandbox Code Playgroud)
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);
Run Code Online (Sandbox Code Playgroud)
这是我__global__添加GPU阵列的简单功能:
__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;
}
}
Run Code Online (Sandbox Code Playgroud)
并且该函数被称为:
for(int j=0;j<10;j++)
{
add<<<(N+127)/128,128>>>(dev_a,dev_b,dev_c);//GPU array adding
}
Run Code Online (Sandbox Code Playgroud)
我将向量a [N]和b [N]添加到向量c [N]中,循环次数为10次:
N = 10000000
我得到了结果:
这让我很困惑,我不熟悉模板库的实现.容器和原始数据结构之间的性能真的差异很大吗?
大多数执行时间都花费在初始化X [i]和Y [i]的循环中.虽然这是合法的,但它是初始化大型设备向量的一种非常缓慢的方式.最好创建主机向量,初始化它们,然后将它们复制到设备中.作为测试,修改你的代码(在你初始化设备向量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
Run Code Online (Sandbox Code Playgroud)
然后,您将看到GPU计时结果几乎在添加的行打印出来之后立即出现.因此,您等待的所有时间都花在直接从主机代码初始化这些设备向量上.
当我在笔记本电脑上运行时,我得到的CPU时间大约为40,GPU时间大约为5,因此对于实际计时的代码段,GPU运行速度比CPU快8倍.
如果创建X和Y作为主机向量,然后创建类似的d_X和d_Y设备向量,则总体执行时间将更短,如下所示:
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;
Run Code Online (Sandbox Code Playgroud)
并将转换调用更改为:
thrust::transform(d_X.begin(), d_X.end(),
d_Y.begin(),
Z.begin(),
thrust::plus<int>());
Run Code Online (Sandbox Code Playgroud)
好的,所以你现在已经表明CPU运行测量比GPU测量快.对不起,我跳到了结论.我的笔记本电脑是惠普笔记本电脑,配备2.6GHz核心i7和Quadro 1000M gpu.我正在运行centos 6.2 linux.一些评论:如果您在GPU上运行任何繁重的显示任务,可能会降低性能.此外,在对这些事情进行基准测试时,通常的做法是使用相同的机制进行比较,如果需要,可以将cudaEvents用于两者,它可以将CPU代码的时间与GPU代码相同.此外,它与推力做热身跑就是不定时的通行做法,然后重复测试测量,同样是常见的做法来运行测试在一个循环10次以上,然后除以获得一个平均水平.在我的情况下,我可以告诉clock()测量是非常粗糙的,因为连续运行将给我30,40或50.在GPU测量我得到像5.18256.其中一些可能有所帮助,但我不能确切地说为什么你的结果和我的结果差别很大(在GPU方面).
好的我做了另一个实验.编译器将在CPU方面产生很大的不同.我用-O3开关编译和CPU时间下降到0.然后我转换CPU定时测量从时钟()方法来cudaEvents,和我的12.4(与-O3优化)和GPU仍然5.1 CPU测量的时间侧.
您的里程将根据计时方法和您在CPU端使用的编译器而有所不同.
| 归档时间: |
|
| 查看次数: |
4548 次 |
| 最近记录: |