【问题标题】:even odd sort behavior on a GPU using a kernel of one thread with sequential implementation使用具有顺序实现的一个线程的内核在 GPU 上的偶数奇数排序行为
【发布时间】:2018-05-06 01:23:16
【问题描述】:
__global__ void sort_single(int *size , int *arr){
for ( int m = 0; m < *size / 2; m++)
{
    for (int  i = 0; i < *size; i += 2)
    {
        if (arr[i + 1] > arr[i])
        {
            int temp = arr[i];
            arr[i] = arr[i + 1];
            arr[i + 1] = temp;
        }
    }
    /*for (int i = 0; i < size; i++)
    printf("%d ", arr[i]);
    printf("\n");*/
    for ( int i = 1; i < *size; i += 2)
    {
        if (arr[i + 1] > arr[i])
        {
            int temp = arr[i];
            arr[i] = arr[i + 1];
            arr[i + 1] = temp;
        }
    }
 }
}

这是一个用于 CUDA GPU 的内核代码。它进行奇偶排序。 为了调用它,我在准备好所有数据后从 main 使用它。 sort_single<<<1,1>>>(d_a,d_b); 我的问题是为什么它在这里给出不正确的结果,而如果我将此代码作为常规 C/C++ 函数代码运行它会给出正确的结果。如果我删除内核中的外循环并在该循环中调用内核它可以正常工作下面。

for ( int m = 0; m < N / 2; m++)
sort_single<<<1,1>>>(d_a,d_b);

我在这里做同样的事情 我认为它必须与该算法所需的步骤数有关,例如每次迭代需要 2 个步骤。

  1. 比较偶数索引和下一个索引。

  2. 比较奇数索引和下一个索引。

由于我使用的是单 GPU 线程,所以当您增加数组中的元素数量时,我无法理解为什么会发生这种情况。为了理解当前的行为,我需要明确 GPU 单线程与 CPU 的不同之处。 the whole single file link on drive

以下是文件内容:

#include "stdio.h"
__global__ void add(int *a , int *b ,int*c){

        c[blockIdx.x] = a[blockIdx.x] + b[blockIdx.x];

}
__global__ void sort_single(int *size , int *arr){

    for ( int m = 0; m < *size / 2; m++)
    {   
        for (int  i = 0; i < *size; i += 2)
        {
            if (arr[i + 1] > arr[i])
            {
                int temp = arr[i];
                arr[i] = arr[i + 1];
                arr[i + 1] = temp;

            }
        }
        /*for (int i = 0; i < size; i++)
        printf("%d ", arr[i]);
        printf("\n");*/
        for ( int i = 1; i < *size; i += 2)
        {
            if (arr[i + 1] > arr[i])
            {
                int temp = arr[i];
                arr[i] = arr[i + 1];
                arr[i + 1] = temp;

            }
        }

    }

}
void random_ints(int *a, int N)
{
   int i;
   for (i = 0; i < N; ++i)
    a[i] = rand() %5000;
}
void uniform_ints(int *a, int N)
{
   int i;
   for (i = 0; i < N; ++i)
    a[i] = i+1;

}

int main(int argc , char**argv){
    int N = 8;
    if(argc>1)
      {
          N=atoi(argv[1]);
      }
    int *a , *b  ;
    int *d_a , *d_b ;
    int isize = N * sizeof(int);

    a = (int *)malloc(sizeof(int));a[0] = N;
    b = (int *)malloc(isize);uniform_ints(b , N);


    cudaError_t cudaStatus;
    // Choose which GPU to run on, change this on a multi-GPU system.
    cudaStatus = cudaSetDevice(0);
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaSetDevice failed!  Do you have a CUDA-capable GPU installed?");
        goto Error;
    }
    cudaStatus = cudaMalloc((void**)&d_a,sizeof(int));

    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMalloc failed!");
        goto Error;
    }
    cudaStatus = cudaMalloc((void**)&d_b,isize);
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMalloc failed!");
        goto Error;
    }    

    cudaStatus = cudaMemcpy(d_a, a , sizeof(int),cudaMemcpyHostToDevice);
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMemcpy failed!");
        goto Error;
    }
    cudaStatus = cudaMemcpy(d_b, b , isize,cudaMemcpyHostToDevice);
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMemcpy failed!");
        goto Error;
    }

    sort_single<<<1,1>>>(d_a,d_b);
    // Check for any errors launching the kernel
    cudaStatus = cudaGetLastError();
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "addKernel launch failed: %s\n", cudaGetErrorString(cudaStatus));
        goto Error;
    }

    // cudaDeviceSynchronize waits for the kernel to finish, and returns
    // any errors encountered during the launch.
    cudaStatus = cudaDeviceSynchronize();
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaDeviceSynchronize returned error code %d after launching addKernel!\n", cudaStatus);
        goto Error;
    }

    cudaStatus = cudaMemcpy(b, d_b , isize,cudaMemcpyDeviceToHost);
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMemcpy failed!");
        goto Error;
    }
    for (int i = 0; i < N; i++)
        printf("%d ", b[i]);
    printf("\n");
    Error:
    cudaFree(d_a);
    cudaFree(d_b);
    return cudaStatus;
}

【问题讨论】:

  • 请在您的问题中编辑正确的minimal reproducible example。很难或不可能说出 out on 可能有什么问题。
  • 在可能的其他问题中,您的代码将在此行进行非法的越界访问(奇数,即第二次扫描,如果整体大小是偶数):if (arr[i + 1] &gt; arr[i])。使用cuda-memcheck 运行您的代码。由于 for 循环上升到 *size[i+1] 将索引越界。这只是损坏的代码,并不是 CPU 或 GPU 实现所独有的。
  • @talonmies 其他代码实际上是文件的可编译代码,您可以使用 nvcc 下载和编译。我不知道为什么它显示内容,我不知道如何关闭它们.
  • @RobertCrovella 对不起,我没有提到它,但我目前只对数组中的偶数个元素执行此操作。
  • 数组中的元素个数为偶数时,奇数扫描仍会被调用,并且仍会产生越界访问。使用cuda-memcheck运行代码

标签: linux sorting cuda


【解决方案1】:

代码在简单的 C/C++ 函数以及 cuda 内核中编译,因为它基于数组大小是偶数的假设。它给出了正确的结果,错误是mallocking。无论如何感谢您的回复。

【讨论】:

    猜你喜欢
    • 2019-08-01
    • 1970-01-01
    • 2021-12-31
    • 1970-01-01
    • 2016-04-25
    • 2021-07-12
    • 2017-07-07
    • 1970-01-01
    • 2011-02-14
    相关资源
    最近更新 更多