Arrays CUDA 2D阵列-使用元素

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

我正在学习cuda,并设法在那里得到了一个2D数组,并返回了一个2D数组的双打,还有一些小问题。现在,我想,例如,将所有值设置为所有值加倍的250,但我似乎无法通过第一行。我似乎无法正确地循环。我怀疑这是块/线程的数量还是代码本身。这是我的完整代码:

#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