2013-01-06 98 views
2

要練習用CUDA編碼,我做了一個小測試場景,我有三個文件:CUDA錯誤 - 未指定發射失敗

  • memory.c舉行純C代碼
  • memory_kernels.h聲明爲CUDA內核和功能推出仁仁
  • memory_kernels.cu定義

什麼程序應該做的是創造一個整數數組,將其複製到設備並查詢元素。內核將打印出一些細節。

不過,我得到的錯誤:

Error in memory_kernels.cu at line 43 with error code "unspecified launch failure"

三個文件的源代碼給出如下:

/** 
* memory.c 
* 
* Test copying large arrays to device 
* and printing from kernel 
*/ 

/* Include standard libraries */ 
#include <stdlib.h> 
#include <stdio.h> 

/* Include local header files */ 
#include "memory_kernels.h" 

int main() { 

    /* Size of array */ 
    int i, N = 1024; 

    /* Array */ 
    int *intArr = (int *) malloc(N * sizeof(int)); 

    /* Fill array */ 
    for(i = 0; i < N; i++) { 
    intArr[i] = i; 
    } 

    /* Run CUDA code */ 
    cuda_mem(&intArr); 

    /* Clean up device */ 
    cudaDeviceReset(); 

    /* Everything done */ 
    exit(EXIT_SUCCESS); 
} 
/** 
* memory_kernels.h 
* 
* Declarations for CUDA kernels 
*/ 

/* Determine compiler */ 
#ifdef __cplusplus 
#define EXTCFUNC extern "C" 
#else 
#define EXTCFUNC extern 
#endif 

#ifndef KERNELS_H 
#define KERNELS_H 

/* Standard libraries (only needed for debugging) */ 
#include <stdio.h> 

/* Include CUDA header files */ 
#include <cuda.h> 
#include <cuda_runtime.h> 

#define CUDA_CALL(x) do { if((x) != cudaSuccess) {               \ 
    printf("Error in %s at line %d with error code \"%s\"\n",__FILE__,__LINE__,cudaGetErrorString(x));  \ 
    exit(x);}} while(0) 

/* Device globals */ 
__device__ int *d_intArr; 

/* Device kernels */ 
__global__ void mem(); 

/* Host access functions */ 
EXTCFUNC void cuda_mem(int **intArr); 

#endif 
/** 
* memory_kernels.cu 
* 
* CUDA kernel implementations 
*/ 

/* Include header file */ 
#include "memory_kernels.h" 

__global__ void mem() { 
    int i = threadIdx.x; 
    int a = d_intArr[i]; 

    printf("i = %d a = %d\n",i,a); 
} 

/* Determine compiler */ 
#ifdef __cplusplus 
#define EXTCFUNC extern "C" 
#else 
#define EXTCFUNC extern 
#endif 

/** 
* cuda_mem() 
* 
* Test copying large array to device 
* and printing from kernel 
*/ 
EXTCFUNC void cuda_mem(int **intArr) { 
    /* Local variables */ 
    int N = 1024; 

    /* Initialise device variables */ 
    CUDA_CALL(cudaMalloc((void **) &d_intArr, sizeof(int) * N)); 

    /* Copy to device initial values */ 
    CUDA_CALL(cudaMemcpy(d_intArr, *intArr, sizeof(int) * N, cudaMemcpyHostToDevice)); 

    /* Run kernel */ 
    mem <<< 1,N >>>(); 
    CUDA_CALL(cudaPeekAtLastError()); 
    CUDA_CALL(cudaDeviceSynchronize()); 

    /* Free local scoped dynamically allocated memory */ 
    CUDA_CALL(cudaFree(d_intArr)); 
} 

編譯與done以下命令:

nvcc -c -o memory.o memory.c -arch=sm_20 
nvcc -c -o memory_kernels.o memory_kernels.cu -arch=sm_20 
nvcc -o memory memory.o memory_kernels.o -arch=sm_20 

在NVIDIA®(英偉達™)Tesla M2050上運行CUDA 4.0。計算能力2.0需要在內核中使用printf()

在四處尋找解決方案後,錯誤代碼表明在從全局內存讀取時,內核中存在分段錯誤。但是,我正在啓動與數組大小相同的線程數。

經過實驗,我有一種感覺,錯誤是由於將intArr複製到設備造成的。也許我正在把我的指針混淆起來?

我明白如果文件結構有點奇怪,但它是一個較大程序的一部分,但我已將錯誤減少到這個較小的情況。

+0

.H持有聲明和.C持有的定義。 –

+0

啊,是的,對不起。讓我編輯它。 – gobbledygook88

+0

未指定的啓動錯誤通常意味着內核內存訪問超出界限。你有沒有試過用cuda-memcheck運行代碼? – talonmies

回答

2

由於無法直接由內核讀取/寫入全局數組,因此引發了錯誤。 正確的方法是將全局數組的指針作爲參數傳遞給內核。

聲明和定義的內核:

__global__ void mem(int *dArr); 

__global__ void mem(int *dArr) 
{ 
    int i = threadIdx.x; 
    int a = dArr[i]; 

    printf("i = %d a = %d\n",i,a); 
} 

調用內核爲:

mem <<< 1,N >>> (d_intArr); 

以上上前解決了這個問題對我來說,程序完美的作品。

其他考慮:

不能使用直接與一個__device__修改在主機代碼中聲明的變量。當我和CUDA 5編譯你的代碼,我得到警告說

warning: a device variable "d_intArr" cannot be directly read in a host function

下面的函數調用生成警告:

CUDA_CALL(cudaMemcpy(d_intArr, *intArr, sizeof(int) * N, cudaMemcpyHostToDevice)); 

爲了保持全球效果,你可以通過指針作爲參數到你的函數而不是聲明全局數組。

+0

感謝您的幫助,併爲額外提示!使用'__device__'標識符可以從內核直接訪問(和這個答案我相信證明)。正確的方法將數據複製到這樣的區域使用cudaMemcpyToSymbol宣佈 – gobbledygook88

+1

的生活在全球存儲陣列。我承認這個答案似乎有效,我無法解釋。 –

+0

也許統一編址被引入時,這成爲可能,但這是cudaMemcpyToSymbol()'仍然在文檔,因爲它需要針對老年架構中使用。 –

1

我想對@ sgar91提供了答案擴展到提供一些額外的觀點(我自己)。正如我所看到的,在全局內存中,至少有兩種方法來實例化可從主機和設備訪問的陣列。

a。使用在主機端創建的動態定位/分配數組。碼序列大致如下:

int main(){ 
    int *arr, *d_arr; 
    arr = (int *)malloc(N*sizeof(int)); 
    cudaMalloc((void **) &d_arr, N*sizeof(int)); 
    cudaMemcpy(d_arr, arr, N*sizeof(int), cudaMemcpyHostToDevice); 
    ... 
    } 

灣使用靜態定位(也許分配)數組。碼序列大致如下:

__device__ int d_arr[N]; 
... 
int main(){ 
    int *arr; 
    arr = (int *)malloc(N*sizeof(int)); 
    cudaMemcpyToSymbol(d_arr, arr, N*sizeof(int)); 
    ... 
    } 

與第一種方法,我必須d_arr的地址傳遞給內核作爲參數。使用第二種方法我不需要這樣做,因爲數組是靜態定位的,因此編譯器和運行時能夠在加載時找到它並正確地修復代碼。使用第二種方法,我可以直接從內核訪問d_arr,即使我沒有將它作爲參數傳遞給內核。

注意,這是可能的,以使用所述第二方法的動態尺寸(但位於靜態)陣列,但爲了簡潔起見,我不示出了在這裏。

由sgar91提供的答案並不完全符合這些方法的執行,所以例如警告仍然存在有關在主機代碼中使用的設備地址(即使它似乎工作)。

+0

我的不好,我完全忘記了'cudaMemcpyToSymbol'。其實警告仍然存在,但不知何故代碼正在工作。 – sgarizvi

相關問題