我对理解SM中的CUDA线程处理有一些疑问。以下命题是从我读过的内容中推断出来的: 我的GPU是:GTX650Ti。
是吗?
因此,如果我在我的内核中有一个10M元素的向量,这意味着我必须在每个8192个元素的1221个作业(内核启动)中对其进行分割?
这个任务的产生是因为我正在比较顺序程序和我的CUDA程序之间的时间性能。但我只能看到CPU超越了GPU。我还尝试使用最大启动参数,例如<<<<<<<<<<<<<<<<<结果非常相似。
那么,我在做什么或配置错误?
这是我使用的代码:
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <math.h>
#include <time.h>
#include "C:\cdev.h"
#include <thrust/device_vector.h>
using namespace thrust;
using namespace std;
#define N (1024 * 16384)
cdev devices;
__global__ void eucliDist(double *c, double *a, double *b)
{
int i = blockDim.x * blockIdx.x + threadIdx.x;
if (i < N)
c[i] = sqrt(pow(a[i], 2) + pow(b[i], 2));
}
int main()
{
clock_t start, end;
double elapsed;
static double A[N];
static double B[N];
for (int i = 0; i < N; i++)
{
A[i] = double(i);
B[i] = double(i);
}
static double C[N];
// Sequential execution of F(x,y) = sqrt((x^2 + y^2))
start = clock();
for (int i = 0; i < N; i++)
C[i] = sqrt(pow(A[i], 2) + pow(B[i], 2));
end = clock();
elapsed = double(end - start) / CLOCKS_PER_SEC;
cout << "Elapsed time for sequential processing is: " << elapsed << " seconds." << endl;
// CUDA Initialization
unsigned int threadNum;
unsigned int blockNum;
cudaError_t cudaStatus;
threadNum = devices.ID[0].maxThreadsPerBlock;
blockNum = ceil(double(N) / double(threadNum));
// Parallel execution with Thrust of F(x,y) = sqrt((x^2 + y^2))
vector<double> vectorA(N);
vector<double> vectorB(N);
for (int i = 0; i < N; i++)
{
vectorA[i] = double(i);
vectorB[i] = double(i);
}
vector<double> vectorC(N);
start = clock();
device_vector<double> thrustA(N);
cudaStatus = cudaGetLastError();
if (cudaStatus != cudaSuccess)
{
cerr << "Device vector allocation failed: " << cudaGetErrorString(cudaStatus) << " (thrustA)" << endl;
cin.get();
return 1;
}
device_vector<double> thrustB(N);
cudaStatus = cudaGetLastError();
if (cudaStatus != cudaSuccess)
{
cerr << "Device vector allocation failed: " << cudaGetErrorString(cudaStatus) << " (thrustB)" << endl;
cin.get();
return 1;
}
device_vector<double> thrustC(N);
cudaStatus = cudaGetLastError();
if (cudaStatus != cudaSuccess)
{
cerr << "Device vector allocation failed: " << cudaGetErrorString(cudaStatus) << " (thrustC)" << endl;
cin.get();
return 1;
}
thrustA = vectorA;
cudaStatus = cudaGetLastError();
if (cudaStatus != cudaSuccess)
{
cerr << "Host to device copy failed (Thrust): " << cudaGetErrorString(cudaStatus) << " (vectorA -> thrustA)" << endl;
cin.get();
return 1;
}
thrustB = vectorB;
cudaStatus = cudaGetLastError();
if (cudaStatus != cudaSuccess)
{
cerr << "Host to device copy failed (Thrust): " << cudaGetErrorString(cudaStatus) << " (vectorB -> thrustB)" << endl;
cin.get();
return 1;
}
eucliDist <<<blockNum, threadNum>>>(raw_pointer_cast(thrustC.data()), raw_pointer_cast(thrustA.data()), raw_pointer_cast(thrustB.data()));
cudaStatus = cudaGetLastError();
if (cudaStatus != cudaSuccess)
{
cerr << "Kernel launch failed (Thrust): " << cudaGetErrorString(cudaStatus) << " (euclidDist)" << endl;
cin.get();
return 1;
}
thrust::copy(thrustC.begin(), thrustC.end(), vectorC.begin());
cudaStatus = cudaGetLastError();
if (cudaStatus != cudaSuccess)
{
cerr << "Device to host copy failed: " << cudaGetErrorString(cudaStatus) << " (thrustC -> vectorC)" << endl;
cin.get();
return 1;
}
end = clock();
elapsed = double(end - start) / CLOCKS_PER_SEC;
cout << "Elapsed time parallel processing is (Thrust): " << elapsed << " seconds." << endl;
cin.get();
return 0;
}
建议将不胜感激。
答案 0 :(得分:3)
让我们首先纠正你在问题中发布的很多内容:
因此,如果我在我的内核中有一个10M元素的向量,这意味着我必须在每个8192个元素的1221个作业(内核启动)中对其进行分割?
不,您将在单个内核启动中启动9766个1024个线程的块。或者启动足够的块以完全占用GPU(最多64个,具体取决于资源),并让每个线程处理输入向量的多个元素。
答案 1 :(得分:0)
你应该打破每次操作的时间;你可能每个元素的工作量很少,以至于你花费大部分时间在主机和设备之间来回复制内存。
如果计算确实是问题,那么可能是您尝试进行的操作。 pow(x,2)
并不是一种特别有效的方法。虽然这在CPU上很糟糕,但在GPU上却特别糟糕,因为它可能意味着你必须使用特殊的功能单元,并且其中很多都没有,所以它会产生瓶颈,因为它和#39;是您计算的主要部分。
(除此之外:单精度(倒数)平方根在不同的功能单元中处理,具有更多可用的吞吐量)
更糟糕的是,你使用的是双精度浮点数; GPU设计用于处理单精度浮点数。虽然它可以做到双倍精度,但它的吞吐量却要低得多。
因此,你应该
x*x
而非pow(x,2)
float
代替double
(如果适用于您的应用)答案 2 :(得分:0)
我的应用程序使用thrust :: device_vector在设备中分配内存。这就是试图在我的计划中进行推力工作的原因。 我终于找到了提高CPU性能的问题和解决方案。这对于决定使用device_vectors而不是数组的其他用户非常有用。
正如@Hurkyl对我说的那样:我正在测量主机和设备之间副本的延迟,反之亦然。所有这些长时间延迟都是由于使用了以下说明:
这两项操作是我代码中的瓶颈。
考虑变量:
vector<double> A;
device_vector<double> thrustA;
解决方案非常简单。我只是用众所周知的cudaMemcpy()函数替换了这两个指令,即
从主机复制到设备:
cudaMemcpy(raw_pointer_cast(thrustA.data()), raw_pointer_cast(A.data()), A.size(), cudaMemcpyHostToDevice);
从设备复制到主机:
cudaMemcpy(raw_pointer_cast(A.data()), raw_pointer_cast(thrustA.data()), A.size(), cudaMemcpyDeviceToHost);
感谢所有花时间解决我问题的人。你的意见非常丰富,让我更了解CUDA。