Arrays CUDA 2D阵列-使用元素
我正在学习cuda,并设法在那里得到了一个2D数组,并返回了一个2D数组的双打,还有一些小问题。现在,我想,例如,将所有值设置为所有值加倍的250,但我似乎无法通过第一行。我似乎无法正确地循环。我怀疑这是块/线程的数量还是代码本身。这是我的完整代码:Arrays CUDA 2D阵列-使用元素,arrays,cuda,2d,Arrays,Cuda,2d,我正在学习cuda,并设法在那里得到了一个2D数组,并返回了一个2D数组的双打,还有一些小问题。现在,我想,例如,将所有值设置为所有值加倍的250,但我似乎无法通过第一行。我似乎无法正确地循环。我怀疑这是块/线程的数量还是代码本身。这是我的完整代码: #include <stdio.h> #include <vector> using namespace std; #define THETA 10 // Error checking. // #define gpu
#include <stdio.h>
#include <vector>
using namespace std;
#define THETA 10
// Error checking.
//
#define gpuErrorCheck(ans) { gpuAssert((ans), __FILE__, __LINE__); }
inline void gpuAssert(cudaError_t code, char *file, int line, bool abort=true)
{
if (code != cudaSuccess)
{
fprintf(stderr, "GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
if (abort) exit(code);
}
}
// Pass 2-dim array to GPU and change it there.
//
__global__
void addArrays(double *twoDimArray, size_t pitch)
{
printf("\n\nOn GPU array : thread : %d\n", threadIdx.x);
int tidx = blockIdx.x * blockDim.x + threadIdx.x; //// tidx = Columns in CUDA
int tidy = blockIdx.y * blockDim.y + threadIdx.y; //// tidy = Rows In cuda
if ((tidx < THETA) && (tidy < THETA))
{
double tempval = 0;
for(int i=0; i < THETA ; i++)
{
tempval = 250;
}
twoDimArray[tidy * THETA + tidx]=tempval;
}
}
int main()
{
//
// 2-Dimensional Array
//
printf("\n*******************\n2-DIMENSIONAL ARRAY\n*******************\n\n");
// Create 2-dim array on the CPU.
//
double arrayOnCpu[THETA][THETA];
double arrayOnCpu2[THETA][THETA];
// Initialise the vector of vector on the CPU.
//
for (int i = 0; i < THETA; i++) // Aantal buitenste vectoren.
{
for (int j = 0; j < THETA; j++) // Aantal binnenste elementen.
{
arrayOnCpu2[i][j] = j;
}
}
// Print the vector of vectors.
//
for (int i = 0; i < THETA; i++)
{
for (int j = 0; j < THETA; j++)
{
printf("%2.2f\t", arrayOnCpu2[i][j]);
}
printf("\n");
}
// Create corresponding double array on the GPU.
//
double *pToArrayOnGpu;
size_t pitch;
gpuErrorCheck( cudaMallocPitch((void **)&pToArrayOnGpu, &pitch, THETA * sizeof(double), THETA) );
// Copy CPU data to vector on GPU.
//
gpuErrorCheck( cudaMemcpy2D(pToArrayOnGpu, pitch, arrayOnCpu2, pitch, THETA * sizeof(double), THETA, cudaMemcpyHostToDevice) );
// Launch GPU code with THETA threads, one per vector element.
//
addArrays<<<1, THETA>>>(pToArrayOnGpu, pitch);
gpuErrorCheck( cudaDeviceSynchronize() );
// Copy array from GPU back to CPU.
//
gpuErrorCheck( cudaMemcpy2D(arrayOnCpu2, pitch, pToArrayOnGpu,pitch, THETA * sizeof(double), THETA, cudaMemcpyDeviceToHost) );
// Print the vector of vectors.
//
for (int i = 0; i < THETA; i++) // Aantal buitenste vectoren.
{
for (int j = 0; j < THETA; j++) // Aantal binnenste elementen.
{
printf("%2.2f\t", arrayOnCpu2[i][j]);
}
printf("\n");
}
printf("\n\n");
// Free up the array on the GPU.
//
gpuErrorCheck( cudaFree(pToArrayOnGpu) );
return 0;
}
首先,如果可以的话,您通常希望避免在GPU上使用double。虽然现在基本上所有支持CUDA的消费级GPU都在某种程度上支持双精度运算,但它通常比单精度运算慢得多 除此之外,对于不同的音高意味着什么,似乎存在一些困惑。通常,数组的节距是指从一行开头跳到下一行开头所需的字节数。驱动程序可能选择/需要在2D阵列的行之间添加填充,以使分配满足硬件的对齐要求和/或允许更优化的内存访问。这意味着,对于GPU上的2D阵列,间距可能大于元素大小*宽度 然而,对于您的CPU阵列,间距仅为θ*sizeofdouble。GPU阵列的基音将从CudamAllocPicch返回给您。在调用cudaMemcpy2D时,将GPU阵列的基音同时传递为GPU和CPU基音。为CPU阵列使用正确的间距。在设备代码中,您可以通过twoDimArray[tidy*THETA+tidx]访问GPU阵列。在这里,您可以有效地使用θ*sizeofdouble的间距来访问GPU数据。您应该使用阵列的实际螺距。例如:
double* my_row = reinterpret_cast<double*>(reinterpret_cast<char*>(twoDimArray) + tidy * pitch);
my_row[tidx] = tempval;
代码的主要问题是您混淆了主机端和设备端的2D阵列的间距概念。下面是一个简单的介绍 在主机中,存储在“\u column*sizeofelement+column*sizeofelement”的+行*width\u中的[行][列]。但在cuda的全局内存访问中,从256字节对齐的地址addr=0、256、512、。。。是最有效的。因此,为了提高内存访问的效率,可以使用cudaMallocPitch功能 在cudaMallocPitch分配的内存中,数组每行的第一个元素的地址是对齐的。由于每行的数据未定义,因此_column*sizeofelement的行*width_不一定是256的倍数。因此,为了确保数组每行的第一个元素的起始地址对齐,CudamAllocPictch在分配内存时为每行分配更多字节,以确保\u列的宽度\u*sizeofelement+额外分配的字节 256的倍数对齐。此外,从CudamAllocPicch返回的音高应添加额外分配的内存。 功能原型如下:
__host__ cudaError_t cudaMemcpy2D ( void* dst, size_t dpitch, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind )
因此,当您使用cudaMemcpy2D时,您应该给出正确的基音,这意味着基音在主机和设备阵列中不同。在您的情况下,应该是这样的:
gpuErrorCheck(cudaMemcpy2D(pToArrayOnGpu, pitch, arrayOnCpu2, THETA * sizeof(double), THETA * sizeof(double), THETA, cudaMemcpyHostToDevice));
第一个PitchPitch是从Cudamalocpitch返回的,而最后一个PitchPitch是THETA*sizeofdouble。
你可以在这里获得更多信息
我对您的代码做了一个简短的更改,可以在我的机器上正确运行
env: Ubuntu 16.04 Tesla P100
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#include <stdio.h>
#include <vector>
using namespace std;
#define THETA 10
// Error checking.
#define gpuErrorCheck(ans) { gpuAssert((ans), __FILE__, __LINE__); }
inline void gpuAssert(cudaError_t code, char *file, int line, bool abort = true)
{
if (code != cudaSuccess)
{
fprintf(stderr, "GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
if (abort) exit(code);
}
}
// Pass 2-dim array to GPU and change it there.
//
__global__
void addArrays(double *twoDimArray, size_t pitch){
int tidx = threadIdx.x;
if ((tidx < THETA) /*&& (tidy < THETA)*/){
double tempval = 250;
for (int i = 0; i < THETA; i++){
double* row = (double*)((char*)twoDimArray + i * pitch);
row[tidx] *= tempval;
}
}
}
int main(){
double arrayOnCpu2[THETA][THETA];
// Initialise the vector of vector on the CPU.
for (int i = 0; i < THETA; i++){ // Aantal buitenste vectoren.
for (int j = 0; j < THETA; j++) // Aantal binnenste elementen.
arrayOnCpu2[i][j] = j;
}
// Print the vector of vectors.
printf("Before:\n");
for (int i = 0; i < THETA; i++){
for (int j = 0; j < THETA; j++)
printf("%2.2f\t", arrayOnCpu2[i][j]);
printf("\n");
}
// Create corresponding double array on the GPU.
double *pToArrayOnGpu;
size_t pitch;
gpuErrorCheck(cudaMallocPitch((void **)&pToArrayOnGpu, &pitch, THETA * sizeof(double), THETA));
// Copy CPU data to vector on GPU.
gpuErrorCheck(cudaMemcpy2D(pToArrayOnGpu, pitch, arrayOnCpu2, THETA * sizeof(double), THETA * sizeof(double), THETA, cudaMemcpyHostToDevice));
// Launch GPU code with THETA threads, one per vector element.
addArrays << <1, THETA >> >(pToArrayOnGpu, pitch);
gpuErrorCheck(cudaDeviceSynchronize());
// Copy array from GPU back to CPU.
gpuErrorCheck(cudaMemcpy2D(arrayOnCpu2, THETA * sizeof(double), pToArrayOnGpu, pitch, THETA * sizeof(double), THETA, cudaMemcpyDeviceToHost));
// Print the vector of vectors.
printf("After:\n");
for (int i = 0; i < THETA; i++){ // Aantal buitenste vectoren.
for (int j = 0; j < THETA; j++) // Aantal binnenste elementen.
printf("%2.2f\t", arrayOnCpu2[i][j]);
printf("\n");
}
printf("\n\n");
// Free up the array on the GPU.
gpuErrorCheck(cudaFree(pToArrayOnGpu));
return 0;
}
非常感谢你。这对我来说是个解决办法
Before:
0.00 1.00 2.00 3.00 4.00 5.00 6.00 7.00 8.00 9.00
0.00 1.00 2.00 3.00 4.00 5.00 6.00 7.00 8.00 9.00
0.00 1.00 2.00 3.00 4.00 5.00 6.00 7.00 8.00 9.00
0.00 1.00 2.00 3.00 4.00 5.00 6.00 7.00 8.00 9.00
0.00 1.00 2.00 3.00 4.00 5.00 6.00 7.00 8.00 9.00
0.00 1.00 2.00 3.00 4.00 5.00 6.00 7.00 8.00 9.00
0.00 1.00 2.00 3.00 4.00 5.00 6.00 7.00 8.00 9.00
0.00 1.00 2.00 3.00 4.00 5.00 6.00 7.00 8.00 9.00
0.00 1.00 2.00 3.00 4.00 5.00 6.00 7.00 8.00 9.00
0.00 1.00 2.00 3.00 4.00 5.00 6.00 7.00 8.00 9.00
After:
0.00 250.00 500.00 750.00 1000.00 1250.00 1500.00 1750.00 2000.00 2250.00
0.00 250.00 500.00 750.00 1000.00 1250.00 1500.00 1750.00 2000.00 2250.00
0.00 250.00 500.00 750.00 1000.00 1250.00 1500.00 1750.00 2000.00 2250.00
0.00 250.00 500.00 750.00 1000.00 1250.00 1500.00 1750.00 2000.00 2250.00
0.00 250.00 500.00 750.00 1000.00 1250.00 1500.00 1750.00 2000.00 2250.00
0.00 250.00 500.00 750.00 1000.00 1250.00 1500.00 1750.00 2000.00 2250.00
0.00 250.00 500.00 750.00 1000.00 1250.00 1500.00 1750.00 2000.00 2250.00
0.00 250.00 500.00 750.00 1000.00 1250.00 1500.00 1750.00 2000.00 2250.00
0.00 250.00 500.00 750.00 1000.00 1250.00 1500.00 1750.00 2000.00 2250.00
0.00 250.00 500.00 750.00 1000.00 1250.00 1500.00 1750.00 2000.00 2250.00