cuda - 无法访问blockDim.x?

时间:2017-06-03 13:32:24

标签: cuda

我正在制作一个cuda程序来处理2D图像。

问题是,当我尝试访问blockDim.xblockId.x时,内核始终无法启动并输出unknown error

此外,如果我使用3x5图片,我可以访问threadId.x,而我使用的2048x2048图片则无法访问。

当我使用PyCuda时,我的内核代码运行正常,但现在我必须切换到cuda C

我认为问题可能与

有关
  • 我传递数组指针的方式,cudaMalloc
  • 出错了
  • 我的块大小和网格大小的配置(但相同的配置在PyCuda中运行良好,所以我不知道如何纠正它。)

我使用cuda-memcheck,我得到了unknown error 30,我搜索了解决方案,但没有任何有用的信息。

__global__ void extractor(const unsigned char* in, unsigned char* out, int* debug)
{
    int idx = (threadIdx.x) + blockDim.x * blockIdx.x ;
    debug[idx] = threadIdx.x; // debug variable is used for debugging
}

int main(int arg, char* args[])
{
    // ...
    int size = w*h; // w is image width and h is image height
    unsigned char *in = 0;
    unsigned char *out = 0;
    int* debug = 0;

    // Allocate GPU buffers for the images
    cudaMalloc((void**)&in, size * sizeof(unsigned char));
    cudaMalloc((void**)&out, num_sample_per_point * size * sizeof(unsigned char));
    cudaMalloc((void**)&debug, size * sizeof(int));

    // Copy image data from host memory to GPU buffers.
    cudaMemcpy(in, &img_data[0], size * sizeof(unsigned char),cudaMemcpyHostToDevice);

    dim3 b_dim(BLOCK_SIZE, 1, 1);   // (1024, 1, 1)
    dim3 g_dim(int(w*h/BLOCK_SIZE)+1, 1, 1);    // (4097, 1, 1)
    extractor<<<g_dim, b_dim>>>(in, out, debug);

    // clean up code and processing result
}

现在我无法获得预期的索引,所以我无法在内核中进行处理,可能是什么问题?

修改

我想使用1D索引,这意味着我假设图像数组是一个“扁平”的1D数组并进行索引。

修改

我添加了线程检查后,仍然有问题。

__global__ void extractor(const unsigned char* in, unsigned char* out, int* debug)
{
    int idx = (threadIdx.x) + blockDim.x * blockIdx.x ;
    int y; int x;
    int temp_x; int temp_y; int temp_idx;
    int check = width*height;
    if (idx < check) {
        debug[0] = 1;    // get kernel launch failed "unknown error"
    }
}

我试图将debug[0]=1;表达式都放在线程检查块和块中,这两个表达式都会出现同样的错误。

所以我怀疑memalloc没有正确完成?

顺便说一句,我使用了nvprof并且说

=22344== Warning: Found 2 invalid records in the result.
==22344== Warning: This can happen if device ran out of memory or if a device kernel was stopped due to an assertion.

修改

完整代码:

#include "cuda_runtime.h"
#include "device_launch_parameters.h"

#include <cmath>
#include <iostream>

#include "PNG.h"

#define L 3
#define INC1 1
#define INC2 1
#define R_IN 2
#define N_P 4
#define BLOCK_SIZE 1024
#define PI 3.14159265358979323846

using namespace std;

__global__ void extractor(const unsigned char* in, unsigned char* out, int* debug, int* disX, int* disY, int width, int height, int pad, int num_sample)
{
    int idx = (threadIdx.x) + blockDim.x * blockIdx.x ;
    int y; int x;
    int temp_x; int temp_y; int temp_idx;
    int check = width*height;

       if (idx < check) {
        debug[idx] = threadIdx.x;
        y = idx/width;
        x = idx%width;
            if ((x < pad) || (x >= (width-pad)) || (y < pad) || (y >= (height-pad))) {
                // need padding
                for (int i = 0; i < num_sample; ++i){
                    temp_x = x + disX[i];
                    temp_y = y + disY[i];

                    if (!((temp_x < 0)||(temp_x > (width-1)) || (temp_y < 0) ||(temp_y>(height-1)))) {
                    temp_idx = temp_y*width + temp_x;   // sampled index
                    out[(idx*num_sample)+i] = in[temp_idx]; // copy sampled value to result
                }
                }
            } else {
                for (int i = 0; i < num_sample; ++i)
                {
                    temp_x = x + disX[i];
                    temp_y = y + disY[i];
                    temp_idx = temp_y*width + temp_x;   // sampled index
                    out[(idx*num_sample)+i] = in[temp_idx]; // copy sampled value to result
                }
            }
       }
  }

vector<int> getCirclePos() {
    int r = 0;
    vector <int> circlePos;
    while (!(r>(L/2))) {
        circlePos.push_back(r);
        if (r < R_IN) r += INC1;
        else r += INC2;
    }
    cout << "circlePos:" << endl;
    for (auto i = circlePos.begin(); i != circlePos.end(); ++i)
    {cout << *i << ' ';}
    cout << endl;
    return circlePos;
}

int main(int arg, char* args[])
{
    cudaError_t cudaStatus;
    vector<int> circlePos = getCirclePos();

    // get disX, disY
    int num_sample_per_point = circlePos.size() * N_P;
    int* disX = new int[num_sample_per_point];
    int* disY = new int[num_sample_per_point];
    int r; int cnt = 0;
    for (int i = 0; i < circlePos.size(); ++i)
    {
        r = circlePos[i];
        float angle;
        for (int j = 0; j < N_P; ++j)
        {
            angle = j*360.0/N_P;
            disX[cnt] = r*cos(angle*M_PI/180.0);
            disY[cnt] = r*sin(angle*M_PI/180.0);
            // cout nvpro   << disX[cnt] << "|" << disY[cnt]<< endl;

            cnt++;
        }
    }

    PNG inPng("test.png");
    // PNG outPng;
    // outPng.Create(inPng.w, inPng.h);

    //store width and height so we can use them for our output image later
    const unsigned int w = inPng.w;
    const unsigned int h = inPng.h;
    cout << "w: " << w << " h: " << h << endl;
    //4 because there are 4 color channels R, G, B, and A
    int size = w * h;

    unsigned char *in = 0;
    unsigned char *out = 0;
    int* debug = 0;

    // Allocate GPU buffers for the images
    cudaMalloc((void**)&in, size * sizeof(unsigned char));
    cudaMalloc((void**)&out, num_sample_per_point * size * sizeof(unsigned char));
    cudaMalloc((void**)&debug, size * sizeof(int));


    vector<unsigned char> img_data;
    for (int i = 0; i < size; ++i)
    {
        img_data.push_back(inPng.data[i*4]);
    }

    // debug
    cout << "========= img_data ==========" << endl;
    for (int i = 0; i < size; ++i)
    {
        cout << int(img_data[i]) << "," ;
    }
    cout << endl;

    // Copy image data from host memory to GPU buffers.
    cudaMemcpy(in, &img_data[0], size * sizeof(unsigned char), cudaMemcpyHostToDevice);

    //free the input image because we do not need it anymore
    inPng.Free();

    // Launch a kernel on the GPU with one thread for each element.
    dim3 b_dim(BLOCK_SIZE, 1, 1);   // (1024, 1, 1)
    dim3 g_dim(int(w*h/BLOCK_SIZE)+1, 1, 1);    // (4097, 1, 1)
    int pad = L/2;

    // __global__ void extractor(const unsigned char* in, unsigned char* out, vector<int> disX, vector<int> disY, int width, int height, int pad, int num_sample)
    extractor<<<g_dim, b_dim>>>(in, out, debug, disX, disY, w, h, pad, num_sample_per_point);

    cudaStatus = cudaGetLastError();
    if (cudaStatus != cudaSuccess)
    {
        std::cout << "Kernel launch failed: " << cudaGetErrorString(cudaStatus) << std::endl;
        cudaFree(in);
        cudaFree(out);
        cudaFree(debug);
        exit(1);
    }

    auto tmp = new unsigned char[size*num_sample_per_point];
    auto tmp_debug = new int [size];

    cudaMemcpy(tmp_debug, debug, size * sizeof(int), cudaMemcpyDeviceToHost);
    cudaMemcpy(tmp, out, num_sample_per_point * size * sizeof(unsigned char), cudaMemcpyDeviceToHost);

    cout << "========= out =========" << endl;
    for (int i = 0; i < size*num_sample_per_point; ++i)
    {
        cout << int(tmp[i]) << ", ";
    }
    cout << endl;

    cout << "========debug=======" << endl;
    for (int i = 0; i < size; ++i)
    {
        cout << tmp_debug[i] << ", ";
    }
    cout << endl;

    cudaFree(in);
    cudaFree(out);
    cudaFree(debug);

    delete[] tmp; delete[] tmp_debug;

    return 0;
}

1 个答案:

答案 0 :(得分:3)

这(根据你的评论)每块定义1024个线程:

dim3 b_dim(BLOCK_SIZE, 1, 1);   // (1024, 1, 1)

根据您的问题文本,wh在失败的情况下均为2048,所以:

dim3 g_dim(int(w*h/BLOCK_SIZE)+1, 1, 1);    // (4097, 1, 1)

正在创建4097个区块,正如您在评论中指出的那样。

每个1024个线程的4097个块总共有4195328个线程,但是您的分配大小仅提供2048 * 2048个元素,或总共4194304个元素。因此,您只启动4195328个线程,只有4194304个元素,剩下1024个线程。

那么1024个额外的线程做什么呢?他们仍然运行内核代码并尝试在分配空间的末尾之外访问您的debug数组。

这导致C和C ++中的未定义行为。

解决此问题的常用方法是将问题大小传递给内核并添加&#34;线程检查&#34;在你的内核代码中,如下所示:

__global__ void extractor(const unsigned char* in, unsigned char* out, int* debug, int n)
{
    int idx = (threadIdx.x) + blockDim.x * blockIdx.x ;
    if (idx < n)
      debug[idx] = threadIdx.x; // debug variable is used for debugging
}

阻止&#34;额外&#34;做任何事情的线程。

如果您在cuda标记上搜索&#34;线程检查&#34;你会发现很多其他问题的例子。

例如,根据您显示的代码片段,以下运行对我没有错误:

$ cat t147.cu
const int width = 2048;
const int height = 2048;
const int BLOCK_SIZE = 1024;
__global__ void extractor(const unsigned char* in, unsigned char* out, int* debug)
{
    int idx = (threadIdx.x) + blockDim.x * blockIdx.x ;
//    int y; int x;
//    int temp_x; int temp_y; int temp_idx;
    int check = width*height;
    if (idx < check) {
        debug[idx] = 1;    // get kernel launch failed "unknown error"
    }
}
int main(int arg, char* args[])
{

    const int w = width;
    const int h = height;
    const int num_sample_per_point = 1;
    int size = w*h; // w is image width and h is image height
    unsigned char *in = 0;
    unsigned char *out = 0;
    int* debug = 0;

    // Allocate GPU buffers for the images
    cudaMalloc((void**)&in, size * sizeof(unsigned char));
    cudaMalloc((void**)&out, num_sample_per_point * size * sizeof(unsigned char));
    cudaMalloc((void**)&debug, size * sizeof(int));

    // Copy image data from host memory to GPU buffers.
//    cudaMemcpy(in, &img_data[0], size * sizeof(unsigned char),cudaMemcpyHostToDevice);

    dim3 b_dim(BLOCK_SIZE, 1, 1);   // (1024, 1, 1)
    dim3 g_dim(int(w*h/BLOCK_SIZE)+1, 1, 1);    // (4097, 1, 1)
    extractor<<<g_dim, b_dim>>>(in, out, debug);
    cudaDeviceSynchronize();
}
$ nvcc -arch=sm_61 -o t147 t147.cu
$ cuda-memcheck ./t147
========= CUDA-MEMCHECK
========= ERROR SUMMARY: 0 errors
$

在完整的代码中,您的内核中只存在非法访问问题。我已修改它以删除对PNG的依赖,如果省略除调试设置之外的内核代码,它运行正常。但是,如果我们包含您的内核代码,并使用cuda-memcheck运行,我们将获得各种越界访问。将来,您可以使用here描述的方法来调试这些:

$ cat t146.cu
#include <cmath>
#include <iostream>
#include <vector>

#define L 3
#define INC1 1
#define INC2 1
#define R_IN 2
#define N_P 4
#define BLOCK_SIZE 1024
#define PI 3.14159265358979323846

using namespace std;

__global__ void extractor(const unsigned char* in, unsigned char* out, int* debug, int* disX, int* disY, int width, int height, int pad, int num_sample)
{
    int idx = (threadIdx.x) + blockDim.x * blockIdx.x ;
    int y; int x;
    int temp_x; int temp_y; int temp_idx;
    int check = width*height;

       if (idx < check) {
        debug[idx] = threadIdx.x;
        y = idx/width;
        x = idx%width;
#ifdef  FAIL
            if ((x < pad) || (x >= (width-pad)) || (y < pad) || (y >= (height-pad))) {
                // need padding
                for (int i = 0; i < num_sample; ++i){
                    temp_x = x + disX[i];
                    temp_y = y + disY[i];

                    if (!((temp_x < 0)||(temp_x > (width-1)) || (temp_y < 0) ||(temp_y>(height-1)))) {
                    temp_idx = temp_y*width + temp_x;   // sampled index
                    out[(idx*num_sample)+i] = in[temp_idx]; // copy sampled value to result
                }
                }
            } else {
                for (int i = 0; i < num_sample; ++i)
                {
                    temp_x = x + disX[i];
                    temp_y = y + disY[i];
                    temp_idx = temp_y*width + temp_x;   // sampled index
                    out[(idx*num_sample)+i] = in[temp_idx]; // copy sampled value to result
                }
            }
#endif
       }
  }

vector<int> getCirclePos() {
    int r = 0;
    vector <int> circlePos;
    while (!(r>(L/2))) {
        circlePos.push_back(r);
        if (r < R_IN) r += INC1;
        else r += INC2;
    }
    cout << "circlePos:" << endl;
    for (auto i = circlePos.begin(); i != circlePos.end(); ++i)
    {//cout << *i << ' ';
      }
    cout << endl;
    return circlePos;
}

int main(int arg, char* args[])
{
    cudaError_t cudaStatus;
    vector<int> circlePos = getCirclePos();

    // get disX, disY
    int num_sample_per_point = circlePos.size() * N_P;
    int* disX = new int[num_sample_per_point];
    int* disY = new int[num_sample_per_point];
    int r; int cnt = 0;
    for (int i = 0; i < circlePos.size(); ++i)
    {
        r = circlePos[i];
        float angle;
        for (int j = 0; j < N_P; ++j)
        {
            angle = j*360.0/N_P;
            disX[cnt] = r*cos(angle*M_PI/180.0);
            disY[cnt] = r*sin(angle*M_PI/180.0);
            // cout nvpro   << disX[cnt] << "|" << disY[cnt]<< endl;

            cnt++;
        }
    }

    const unsigned int w = 2048;
    const unsigned int h = 2048;
    cout << "w: " << w << " h: " << h << endl;
    //4 because there are 4 color channels R, G, B, and A
    int size = w * h;

    unsigned char *in = 0;
    unsigned char *out = 0;
    int* debug = 0;

    // Allocate GPU buffers for the images
    cudaMalloc((void**)&in, size * sizeof(unsigned char));
    cudaMalloc((void**)&out, num_sample_per_point * size * sizeof(unsigned char));
    cudaMalloc((void**)&debug, size * sizeof(int));


    vector<unsigned char> img_data;
    for (int i = 0; i < size; ++i)
    {
        img_data.push_back(0);
    }

    // debug
    cout << "========= img_data ==========" << endl;
    for (int i = 0; i < size; ++i)
    {
 //       cout << int(img_data[i]) << "," ;
    }
    cout << endl;

    // Copy image data from host memory to GPU buffers.
    cudaMemcpy(in, &img_data[0], size * sizeof(unsigned char), cudaMemcpyHostToDevice);


    // Launch a kernel on the GPU with one thread for each element.
    dim3 b_dim(BLOCK_SIZE, 1, 1);   // (1024, 1, 1)
    dim3 g_dim(int(w*h/BLOCK_SIZE)+1, 1, 1);    // (4097, 1, 1)
    int pad = L/2;

    // __global__ void extractor(const unsigned char* in, unsigned char* out, vector<int> disX, vector<int> disY, int width, int height, int pad, int num_sample)
    extractor<<<g_dim, b_dim>>>(in, out, debug, disX, disY, w, h, pad, num_sample_per_point);

    cudaStatus = cudaGetLastError();
    if (cudaStatus != cudaSuccess)
    {
        std::cout << "Kernel launch failed: " << cudaGetErrorString(cudaStatus) << std::endl;
        cudaFree(in);
        cudaFree(out);
        cudaFree(debug);
        exit(1);
    }

    auto tmp = new unsigned char[size*num_sample_per_point];
    auto tmp_debug = new int [size];

    cudaMemcpy(tmp_debug, debug, size * sizeof(int), cudaMemcpyDeviceToHost);
    cudaMemcpy(tmp, out, num_sample_per_point * size * sizeof(unsigned char), cudaMemcpyDeviceToHost);

    cout << "========= out =========" << endl;
    for (int i = 0; i < size*num_sample_per_point; ++i)
    {
   //     cout << int(tmp[i]) << ", ";
    }
    cout << endl;

    cout << "========debug=======" << endl;
    for (int i = 0; i < size; ++i)
    {
     //   cout << tmp_debug[i] << ", ";
    }
    cout << endl;

    cudaFree(in);
    cudaFree(out);
    cudaFree(debug);

    delete[] tmp; delete[] tmp_debug;

    return 0;
}
$ nvcc -std=c++11 -o t146 t146.cu -arch=sm_61 -lineinfo
t146.cu(18): warning: variable "y" was set but never used

t146.cu(18): warning: variable "x" was set but never used

t146.cu(19): warning: variable "temp_x" was declared but never referenced

t146.cu(19): warning: variable "temp_y" was declared but never referenced

t146.cu(19): warning: variable "temp_idx" was declared but never referenced

t146.cu(18): warning: variable "y" was set but never used

t146.cu(18): warning: variable "x" was set but never used

t146.cu(19): warning: variable "temp_x" was declared but never referenced

t146.cu(19): warning: variable "temp_y" was declared but never referenced

t146.cu(19): warning: variable "temp_idx" was declared but never referenced

$ cuda-memcheck ./t146
========= CUDA-MEMCHECK
circlePos:

w: 2048 h: 2048
========= img_data ==========

========= out =========

========debug=======

========= ERROR SUMMARY: 0 errors
$ nvcc -std=c++11 -o t146 t146.cu -arch=sm_61 -lineinfo -DFAIL
$ cuda-memcheck ./t146
...
========= Invalid __global__ read of size 4
=========     at 0x00000418 in /home/ubuntu/bobc/misc/t146.cu:41:extractor(unsigned char const *, unsigned char*, int*, int*, int*, int, int, int, int)
=========     by thread (197,0,0) in block (17,0,0)
=========     Address 0x00c8b290 is out of bounds
=========     Saved host backtrace up to driver entry point at kernel launch time
=========     Host Frame:/usr/lib/x86_64-linux-gnu/libcuda.so.1 (cuLaunchKernel + 0x2c5) 
...
(and much more output like this)

以上输出指向代码中的第41行,该行从disX读取。

事实证明,您的disX是主机分配的变量:

int* disX = new int[num_sample_per_point];

但您尝试将其传递给设备代码:

extractor<<<g_dim, b_dim>>>(in, out, debug, disX, disY, w, h, pad, num_sample_per_point);
                                            ^^^^

这完全被打破了。你不能在CUDA中做到这一点。您需要制作该变量的设备副本,以及disY当我解决该问题时,修改后的代码对我运行没有错误:

$ cat t146.cu
#include <cmath>
#include <iostream>
#include <vector>

#define L 3
#define INC1 1
#define INC2 1
#define R_IN 2
#define N_P 4
#define BLOCK_SIZE 1024
#define PI 3.14159265358979323846

using namespace std;

__global__ void extractor(const unsigned char* in, unsigned char* out, int* debug, int* disX, int* disY, int width, int height, int pad, int num_sample)
{
    int idx = (threadIdx.x) + blockDim.x * blockIdx.x ;
    int y; int x;
    int temp_x; int temp_y; int temp_idx;
    int check = width*height;

       if (idx < check) {
        debug[idx] = threadIdx.x;
        y = idx/width;
        x = idx%width;
#ifdef  FAIL
            if ((x < pad) || (x >= (width-pad)) || (y < pad) || (y >= (height-pad))) {
                // need padding
                for (int i = 0; i < num_sample; ++i){
                    temp_x = x + disX[i];
                    temp_y = y + disY[i];

                    if (!((temp_x < 0)||(temp_x > (width-1)) || (temp_y < 0) ||(temp_y>(height-1)))) {
                    temp_idx = temp_y*width + temp_x;   // sampled index
                    out[(idx*num_sample)+i] = in[temp_idx]; // copy sampled value to result
                }
                }
            } else {
                for (int i = 0; i < num_sample; ++i)
                {
                    temp_x = x + disX[i];
                    temp_y = y + disY[i];
                    temp_idx = temp_y*width + temp_x;   // sampled index
                    out[(idx*num_sample)+i] = in[temp_idx]; // copy sampled value to result
                }
            }
#endif
       }
  }

vector<int> getCirclePos() {
    int r = 0;
    vector <int> circlePos;
    while (!(r>(L/2))) {
        circlePos.push_back(r);
        if (r < R_IN) r += INC1;
        else r += INC2;
    }
    cout << "circlePos:" << endl;
    for (auto i = circlePos.begin(); i != circlePos.end(); ++i)
    {//cout << *i << ' ';
      }
    cout << endl;
    return circlePos;
}

int main(int arg, char* args[])
{
    cudaError_t cudaStatus;
    vector<int> circlePos = getCirclePos();

    // get disX, disY
    int num_sample_per_point = circlePos.size() * N_P;
    int* disX = new int[num_sample_per_point];
    int* disY = new int[num_sample_per_point];
    int r; int cnt = 0;
    for (int i = 0; i < circlePos.size(); ++i)
    {
        r = circlePos[i];
        float angle;
        for (int j = 0; j < N_P; ++j)
        {
            angle = j*360.0/N_P;
            disX[cnt] = r*cos(angle*M_PI/180.0);
            disY[cnt] = r*sin(angle*M_PI/180.0);
            // cout nvpro   << disX[cnt] << "|" << disY[cnt]<< endl;

            cnt++;
        }
    }

    int *d_disX, *d_disY;
    cudaMalloc(&d_disX, num_sample_per_point*sizeof(int));
    cudaMalloc(&d_disY, num_sample_per_point*sizeof(int));
    cudaMemcpy(d_disX, disX, num_sample_per_point*sizeof(int), cudaMemcpyHostToDevice);
    cudaMemcpy(d_disY, disY, num_sample_per_point*sizeof(int), cudaMemcpyHostToDevice);
    const unsigned int w = 2048;
    const unsigned int h = 2048;
    cout << "w: " << w << " h: " << h << endl;
    //4 because there are 4 color channels R, G, B, and A
    int size = w * h;

    unsigned char *in = 0;
    unsigned char *out = 0;
    int* debug = 0;

    // Allocate GPU buffers for the images
    cudaMalloc((void**)&in, size * sizeof(unsigned char));
    cudaMalloc((void**)&out, num_sample_per_point * size * sizeof(unsigned char));
    cudaMalloc((void**)&debug, size * sizeof(int));


    vector<unsigned char> img_data;
    for (int i = 0; i < size; ++i)
    {
        img_data.push_back(0);
    }

    // debug
    cout << "========= img_data ==========" << endl;
    for (int i = 0; i < size; ++i)
    {
 //       cout << int(img_data[i]) << "," ;
    }
    cout << endl;

    // Copy image data from host memory to GPU buffers.
    cudaMemcpy(in, &img_data[0], size * sizeof(unsigned char), cudaMemcpyHostToDevice);


    // Launch a kernel on the GPU with one thread for each element.
    dim3 b_dim(BLOCK_SIZE, 1, 1);   // (1024, 1, 1)
    dim3 g_dim(int(w*h/BLOCK_SIZE)+1, 1, 1);    // (4097, 1, 1)
    int pad = L/2;

    // __global__ void extractor(const unsigned char* in, unsigned char* out, vector<int> disX, vector<int> disY, int width, int height, int pad, int num_sample)
    extractor<<<g_dim, b_dim>>>(in, out, debug, d_disX, d_disY, w, h, pad, num_sample_per_point);

    cudaStatus = cudaGetLastError();
    if (cudaStatus != cudaSuccess)
    {
        std::cout << "Kernel launch failed: " << cudaGetErrorString(cudaStatus) << std::endl;
        cudaFree(in);
        cudaFree(out);
        cudaFree(debug);
        exit(1);
    }

    auto tmp = new unsigned char[size*num_sample_per_point];
    auto tmp_debug = new int [size];

    cudaMemcpy(tmp_debug, debug, size * sizeof(int), cudaMemcpyDeviceToHost);
    cudaMemcpy(tmp, out, num_sample_per_point * size * sizeof(unsigned char), cudaMemcpyDeviceToHost);

    cout << "========= out =========" << endl;
    for (int i = 0; i < size*num_sample_per_point; ++i)
    {
   //     cout << int(tmp[i]) << ", ";
    }
    cout << endl;

    cout << "========debug=======" << endl;
    for (int i = 0; i < size; ++i)
    {
     //   cout << tmp_debug[i] << ", ";
    }
    cout << endl;

    cudaFree(in);
    cudaFree(out);
    cudaFree(debug);

    delete[] tmp; delete[] tmp_debug;

    return 0;
}
$ nvcc -std=c++11 -o t146 t146.cu -arch=sm_61 -lineinfo -DFAIL
$ cuda-memcheck ./t146
========= CUDA-MEMCHECK
circlePos:

w: 2048 h: 2048
========= img_data ==========

========= out =========

========debug=======

========= ERROR SUMMARY: 0 errors
$