为什么只有少量线程正在启​​动?

时间:2015-10-31 23:11:53

标签: c algorithm cuda

该代码用于并行化字符串匹配算法(强力)。为什么只有5个线程正在启​​动而不是17?

#include<stdio.h>
#include<string.h>

__global__ void pattern_search(char* d_txt,char* d_pat,int* d_result,int N,int M){
    int id=threadIdx.x+blockIdx.x*blockDim.x;
    if(id<=(N)){
        int j=0;
        for(j=0;j<M;j++){
            if(d_txt[id+j]!=d_pat[j]){
                break;
            }
        }
        //if(j==M){
            d_result[id]=id;
        //}

    }
}

int main(){
    char txt[]="AABAACAADAABAAABAA";
    char pat[]="AABA";

    int N=strlen(txt);
    int M=strlen(pat);
    char* d_pat;
    cudaMalloc((void **)&d_pat,M);
    char* d_txt;
    cudaMalloc((void **)&d_txt,N);

    int result[N];
    for(int i=0;i<N;i++){
        result[i]=0;
    }

    int* d_result;
    cudaMalloc((void**)&d_result,N);
    cudaMemcpy(d_txt,txt,N,cudaMemcpyHostToDevice);
    cudaMemcpy(d_pat,pat,M,cudaMemcpyHostToDevice);
    cudaMemcpy(d_result,result,N,cudaMemcpyHostToDevice);
    pattern_search<<<1,50>>>(d_txt,d_pat,d_result,N,M);

    cudaMemcpy(result,d_result,N,cudaMemcpyDeviceToHost);

    for(int k=0;k<N;k++){

        printf("pattern found at:%d\n",result[k]);
    }
}

1 个答案:

答案 0 :(得分:1)

  1. 每当您遇到CUDA代码时遇到问题,最好通过cuda-memcheck来演示和使用proper cuda error checking 运行您的代码。如果您使用cuda-memcheck运行此代码,则会报告可能有用的错误。

  2. 目前尚不清楚为什么要询问17个主题。在CUDA中,可以从内核启动中推断出启动的线程数,简而言之,它是内核启动配置中前两个数字的乘积(<<<...>>>):

    pattern_search<<<1,50>>>(d_txt,d_pat,d_result,N,M);
    

    所以在这种情况下,它应该启动50个线程。即使您的问题仅限于N,您发布的代码的数量N也是18,而不是17。

  3. cudaMalloc,与主机端malloc一样,在 bytes 中分配内存。因此,对于这种情况,这样的使用是不正确的:

    cudaMalloc((void**)&d_result,N);
    

    而你应该做这样的事情:

    cudaMalloc((void**)&d_result,N*sizeof(int));
    

    因为在这种情况下,您希望存储N个数量为int的数量。使用cuda-memcheck可以发现此错误,由于此分配错误,该错误将报告无效的__global__写入。

  4. cudaMemcpy次调用也会出现类似问题,这些问题也会在字节上运行(就像主机memcpy一样)。而不是:

    cudaMemcpy(d_result,result,N,cudaMemcpyHostToDevice);
    

    我们想要这个:

    cudaMemcpy(d_result,result,N*sizeof(int),cudaMemcpyHostToDevice);
    

    并且需要在内核之后的调用上进行类似的修正。

  5. 您的内核有一个越界索引错误:

    if(id<=(N)){
        int j=0;
        for(j=0;j<M;j++){
            if(d_txt[id+j]!=d_pat[j]){
    

    上面的代码将允许for循环索引超出数组d_txt的末尾,该数组仅限于N长度。为了解决这个问题,我们可以将循环行为限制为仅在有足够的&#34;索引空间&#34;对于j循环的完整迭代:

    if((id+M)<=(N)){
        int j=0;
        for(j=0;j<M;j++){
            if(d_txt[id+j]!=d_pat[j]){
    

    (并且可能还有很多其他方法可以解决此问题。)__global__报告的无效cuda-memcheck读取可能会发现此错误。

  6. 以下代码解决了上述问题,并且对我运行没有错误:

    $ cat t964.cu
    #include<stdio.h>
    #include<string.h>
    
    #define cudaCheckErrors(msg) \
        do { \
            cudaError_t __err = cudaGetLastError(); \
            if (__err != cudaSuccess) { \
                fprintf(stderr, "Fatal error: %s (%s at %s:%d)\n", \
                    msg, cudaGetErrorString(__err), \
                    __FILE__, __LINE__); \
                fprintf(stderr, "*** FAILED - ABORTING\n"); \
                exit(1); \
            } \
        } while (0)
    
    
    __global__ void pattern_search(char* d_txt,char* d_pat,int* d_result,int N,int M){
        int id=threadIdx.x+blockIdx.x*blockDim.x;
        if((id+M)<=(N)){
            int j=0;
            for(j=0;j<M;j++){
                if(d_txt[id+j]!=d_pat[j]){
                    break;
                }
            }
            //if(j==M){
                d_result[id]=id;
            //}
    
        }
    }
    
    int main(){
        char txt[]="AABAACAADAABAAABAA";
        char pat[]="AABA";
    
        int N=strlen(txt);
        int M=strlen(pat);
        char* d_pat;
        cudaMalloc((void **)&d_pat,M);
        char* d_txt;
        cudaMalloc((void **)&d_txt,N);
    
        int result[N];
        for(int i=0;i<N;i++){
            result[i]=0;
        }
    
        int* d_result;
        cudaMalloc((void**)&d_result,N*sizeof(int));
        cudaMemcpy(d_txt,txt,N,cudaMemcpyHostToDevice);
        cudaMemcpy(d_pat,pat,M,cudaMemcpyHostToDevice);
        cudaMemcpy(d_result,result,N*sizeof(int),cudaMemcpyHostToDevice);
        cudaCheckErrors("1");
        pattern_search<<<1,50>>>(d_txt,d_pat,d_result,N,M);
    
        cudaMemcpy(result,d_result,N*sizeof(int),cudaMemcpyDeviceToHost);
        cudaCheckErrors("2");
        for(int k=0;k<N;k++){
    
            printf("pattern found at:%d\n",result[k]);
        }
    }
    

    你还没有确切地指出你期望的输出,但结果似乎对我来说是合理的。

    请注意,我对上面第5项的应用修补意味着只有第一个N-M+1个主题会报告结果。如果你想要某种不同的行为(不确定你想要什么样的模式匹配),当然还有其他方法来修改它。

    将来,如果你想避免投票和关闭投票,我的建议是要注意你的问题主要是要求调试帮助(&#34;为什么这个代码不起作用? &#34;)因此它属于SO expectsMCVE的问题类别。你提供了一个完整的代码,这很好。可能还有一些其他方面可以改进:

    1. 更清楚地说明问题所在。关于运行多少个线程的问题不是很清楚。对于一个好的MCVE,您应该解释预期结果是什么并显示实际结果。在某些情况下,提及您正在使用的CUDA版本,编译命令行和平台(主机操作系统)可能也很有用。

    2. 演示并使用cuda-memcheck正确的cuda错误检查和使用。即使您不理解错误输出,也请在您的问题中描述或包含它 - 对于那些试图帮助您的人来说,它会很有用。