CUDA内核未返回值

时间:2018-12-19 15:45:13

标签: cuda openmp thrust

我正在使用具有多个GPU的服务器。我正在使用openMP一次在多个GPU上启动内核。我看到的问题是我正在运行的内核似乎没有更新传递的推力设备矢量中的值。下面的代码应该为设备向量中的所有元素输出值1,但输出值为0。该代码编译并运行,并向我显示内核成功执行。

我不明白为什么这段代码的行为不符合预期。

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

char *strwordsep ( char *str, char *word, size_t *stop) {
    char *parse = str;
    size_t space = 0;
    size_t span = 0;

    while ( *parse){//parse not pointing to zero terminator
        space = strspn ( parse, " \n\t");//leading whitespace
        parse += space;//advance past whitespace
        span = strcspn ( parse, " \n\t");//not whitespace
        if ( span) {
            // printf("word is: %.*s\n", (int)span, parse);//prints span number of characters
            if ( 0 == strncmp ( word, parse, span)) {
                // printf ( "\tword matches delimiter: %s\n", word);//found match
                // *parse = 0;//zero terminate
                *stop = parse - str;
                parse += span;//advance past delimiter
                space = strspn ( parse, " \n\t");//leading whitespace
                parse += space;//advance past whiteespace
                return parse;
            }
        }
        parse += span;//advance past non whitespace for next word
    }
    return NULL;
}

char **freelines ( char **ppc) {
    int each = 0;
    while ( ppc[each]) {//loop until sentinel NULL
        free ( ppc[each]);//free memory
        each++;
    }
    free ( ppc);//free pointers
    return NULL;
}

char **addline ( char **ppc, int *lines, char *add, int length) {
    char **temp = NULL;
    if ( ( temp = realloc ( ppc, sizeof ( *temp) * ( *lines + 2)))) {//add pointer
        ppc = temp;//assign reallocated pointer to original
        if ( ( ppc[*lines] = malloc ( length + 1))) {//allocate memory to pointer
            strncpy ( ppc[*lines], add, length);//copy lenght characters to pointer
            ppc[*lines][length] = 0;
        }
        else {
            fprintf ( stderr, "problem malloc\n");
            ppc = freelines ( ppc);//release memory
            return ppc;
        }
        ppc[*lines + 1] = NULL;//sentinel NULL
        *lines = *lines + 1;
    }
    else {
        fprintf ( stderr, "problem realloc\n");
        ppc = freelines ( ppc);//release memory
        return ppc;
    }
    return ppc;
}

void showlines ( char **ppc) {
    int each = 0;
    while ( ppc[each]) {
        printf ( "output[%d]= %s\n", each, ppc[each]);
        each++;
    }
}

int main() {
    char data[]="Jason, I am on the phone, could you please turn on the TV";
    char word[5]="on";
    char **output = NULL;//pointer to pointer to store sub-strings
    char *lead = data;
    char *trail = data;
    int lines = 0;
    size_t stop = 0;
    while ( ( trail = strwordsep ( lead, word, &stop))) {
        if ( ! ( output = addline ( output, &lines, lead, (int)stop))) {
            return 0;
        }
        lead = trail;
    }
    if ( *lead) {
        if ( ! ( output = addline ( output, &lines, lead, (int)strlen ( lead)))) {
            return 0;
        }
    }
    showlines ( output);
    output = freelines ( output);
    return 0;
}

任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:2)

某些输出值已设置为1,有些则没有。问题归因于以下语句:

// Calculate Global index (Generic 3D block, 3D thread)
long idx = ( blockIdx.x + blockIdx.y * gridDim.x * gridDim.y * blockIdx.z )
          * ( threadIdx.z * ( blockDim.x*blockDim.y ) ) + threadIdx.y 
          * blockDim.x + threadIdx.x;

这不是我所说的将3D网格/块正确转换为全球唯一的1D索引的正确方法,我认为这是您的意图。让我们仅举一个例子来证明它已损坏。假设您正在启动由1D块组成的1D网格(这是您正在做的)。然后,所有(block,thread)Idx.y和.z变量都将为零。在该启动配置中,只有blockIdx.x和threadIdx.x可以采用非零值。

在这种情况下,您的表情会减少为:

// Calculate Global index (Generic 3D block, 3D thread)
long idx = ( blockIdx.x + 0 * gridDim.x * gridDim.y * 0 )
          * ( 0 * ( blockDim.x*blockDim.y ) ) + 0 
          * blockDim.x + threadIdx.x;

即它减少为:

long idx = threadIdx.x;

因此,数组(a,b,c,d)的第一个(块大小)元素已正确设置,其余元素未正确设置。由于threadIdx.x在一个块与下一个块之间不是唯一的,因此这不是正确的全局唯一线程ID,因此每个块都在写 same 输出位置,而不是每个位置都在写数组的单独部分。

那么什么是可能的(正确的)通用3D到1D索引转换?

here(可能还有其他地方)都回答了。该答案实际上仅将3D网格和1D块配置转换为全局唯一的ID,但这对于演示此代码中的错误是足够的。

当我用该代码替换idx的内核计算时,根据我的测试,您的内核会用1.0填充所有数组条目。