在cuda中分配字符串数组

在cuda中分配字符串数组,cuda,gpu,Cuda,Gpu,假设我们有以下字符串需要存储在CUDA数组中 “你好” “这是” “谁是” 我们如何在GPU上声明一个数组来实现这一点。我尝试使用C++ 字符串< /C> >但不起作用。< p>必须使用C风格字符串 char *STR 。在谷歌上搜索“CUDA字符串”会给你这个CUDA“Hello World”的例子作为第一次点击: 在这里,您可以看到如何在CUDA中使用char*-字符串。请注意,CUDA中不提供标准C功能,如strcpy或strcmp 如果需要字符串数组,只需使用char**(如C/C++)

假设我们有以下字符串需要存储在CUDA数组中

“你好”

“这是”

“谁是”


我们如何在GPU上声明一个数组来实现这一点。我尝试使用C++ <代码>字符串< /C> >但不起作用。

< p>必须使用C风格字符串<代码> char *STR 。在谷歌上搜索“CUDA字符串”会给你这个CUDA“Hello World”的例子作为第一次点击: 在这里,您可以看到如何在CUDA中使用
char*
-字符串。请注意,CUDA中不提供标准C功能,如
strcpy
strcmp


如果需要字符串数组,只需使用
char**
(如C/C++)。至于
strcmp
和类似的功能,这在很大程度上取决于您想要做什么。CUDA不太适合字符串操作,如果你能提供更多关于你想做什么的细节,也许会有所帮助。

你必须使用C风格的字符串
char*str
。在谷歌上搜索“CUDA字符串”会给你这个CUDA“Hello World”的例子作为第一次点击: 在这里,您可以看到如何在CUDA中使用
char*
-字符串。请注意,CUDA中不提供标准C功能,如
strcpy
strcmp


如果需要字符串数组,只需使用
char**
(如C/C++)。至于
strcmp
和类似的功能,这在很大程度上取决于您想要做什么。CUDA不太适合字符串操作,如果您能提供更多关于您想要执行的操作的详细信息,可能会有所帮助。

最好的方法可能是使用类似于普通压缩稀疏矩阵格式的结构。将压缩的字符数据存储到单个线性内存中,然后使用单独的整数数组存储起始索引,或者使用第三个数组存储字符串长度。后者的存储开销可能比为数据中的每个条目存储字符串终止字节并尝试在GPU代码中解析终止符更有效

所以你可能会有这样的想法:

struct gpuStringArray {
    unsigned int * pos; 
    unsigned int * length;  // could be a smaller type if strings are short
    char4 * data; // 32 bit data type will improve memory throughput, could be 8 bit
} 
__device__ __host__
int cmp4(const char4 & c1, const char4 & c2)
{
    int result;

    result = c1.x - c2.x; if (result !=0) return result; 
    result = c1.y - c2.y; if (result !=0) return result; 
    result = c1.z - c2.z; if (result !=0) return result; 
    result = c1.w - c2.w; if (result !=0) return result; 

    return 0;
}

__device__ __host__
int strncmp4(const char4 * s1, const char4 * s2, const unsigned int nwords)
{
    for(unsigned int i=0; i<nwords; i++) {
        int result = cmp4(s1[i], s2[i]);
        if (result != 0) return result;
    }

    return 0;
}

__global__
void tkernel(const struct gpuStringArray a, const gpuStringArray b, int * result)
{
    int idx = threadIdx.x + blockIdx.x * blockDim.x;

    char4 * s1 = a.data + a.pos[idx];
    char4 * s2 = b.data + b.pos[idx];
    unsigned int slen = min(a.length[idx], b.length[idx]);

    result[idx] = strncmp4(s1, s2, slen);
}
注:我对字符串数据使用了
char4
类型;向量类型将提供更好的内存吞吐量,但这意味着字符串需要对齐/适当填充到4字节边界。这可能是问题,也可能不是问题,这取决于应用程序中典型的真实字符串的外观。此外,(可选)长度参数的类型可能应选择为反映允许的最大字符串长度。如果您有很多非常短的字符串,那么使用8位或16位无符号类型作为长度以节省内存可能是值得的


比较以
strcmp
样式存储的字符串的非常简单的代码可能如下所示:

struct gpuStringArray {
    unsigned int * pos; 
    unsigned int * length;  // could be a smaller type if strings are short
    char4 * data; // 32 bit data type will improve memory throughput, could be 8 bit
} 
__device__ __host__
int cmp4(const char4 & c1, const char4 & c2)
{
    int result;

    result = c1.x - c2.x; if (result !=0) return result; 
    result = c1.y - c2.y; if (result !=0) return result; 
    result = c1.z - c2.z; if (result !=0) return result; 
    result = c1.w - c2.w; if (result !=0) return result; 

    return 0;
}

__device__ __host__
int strncmp4(const char4 * s1, const char4 * s2, const unsigned int nwords)
{
    for(unsigned int i=0; i<nwords; i++) {
        int result = cmp4(s1[i], s2[i]);
        if (result != 0) return result;
    }

    return 0;
}

__global__
void tkernel(const struct gpuStringArray a, const gpuStringArray b, int * result)
{
    int idx = threadIdx.x + blockIdx.x * blockDim.x;

    char4 * s1 = a.data + a.pos[idx];
    char4 * s2 = b.data + b.pos[idx];
    unsigned int slen = min(a.length[idx], b.length[idx]);

    result[idx] = strncmp4(s1, s2, slen);
}
\uuuuu设备\uuuuuu主机__
内部cmp4(常量字符4和c1,常量字符4和c2)
{
int结果;
result=c1.x-c2.x;如果(result!=0)返回结果;
result=c1.y-c2.y;如果(result!=0)返回结果;
result=c1.z-c2.z;如果(result!=0)返回结果;
result=c1.w-c2.w;如果(result!=0)返回结果;
返回0;
}
__设备主机__
int strncmp4(常量char4*s1,常量char4*s2,常量无符号int nwords)
{

对于(unsigned int i=0;i最好的方法可能是使用类似于普通压缩稀疏矩阵格式的结构。将压缩的字符数据存储到单个线性内存中,然后使用单独的整数数组存储起始索引,或者使用第三个数组存储字符串长度后者可能比为数据中的每个条目存储字符串终止字节并尝试在GPU代码中解析终止符更有效

所以你可能会有这样的想法:

struct gpuStringArray {
    unsigned int * pos; 
    unsigned int * length;  // could be a smaller type if strings are short
    char4 * data; // 32 bit data type will improve memory throughput, could be 8 bit
} 
__device__ __host__
int cmp4(const char4 & c1, const char4 & c2)
{
    int result;

    result = c1.x - c2.x; if (result !=0) return result; 
    result = c1.y - c2.y; if (result !=0) return result; 
    result = c1.z - c2.z; if (result !=0) return result; 
    result = c1.w - c2.w; if (result !=0) return result; 

    return 0;
}

__device__ __host__
int strncmp4(const char4 * s1, const char4 * s2, const unsigned int nwords)
{
    for(unsigned int i=0; i<nwords; i++) {
        int result = cmp4(s1[i], s2[i]);
        if (result != 0) return result;
    }

    return 0;
}

__global__
void tkernel(const struct gpuStringArray a, const gpuStringArray b, int * result)
{
    int idx = threadIdx.x + blockIdx.x * blockDim.x;

    char4 * s1 = a.data + a.pos[idx];
    char4 * s2 = b.data + b.pos[idx];
    unsigned int slen = min(a.length[idx], b.length[idx]);

    result[idx] = strncmp4(s1, s2, slen);
}
注:我对字符串数据使用了
char4
类型;向量类型将提供更好的内存吞吐量,但这意味着字符串需要对齐/适当填充到4字节边界。这可能是个问题,也可能不是问题,取决于应用程序中典型的实字符串的外观。此外,向量类型(可选)可能应该选择length参数来反映允许的最大字符串长度。如果您有许多非常短的字符串,则可能值得使用8位或16位无符号类型来表示长度,以节省内存


比较以
strcmp
样式存储的字符串的非常简单的代码可能如下所示:

struct gpuStringArray {
    unsigned int * pos; 
    unsigned int * length;  // could be a smaller type if strings are short
    char4 * data; // 32 bit data type will improve memory throughput, could be 8 bit
} 
__device__ __host__
int cmp4(const char4 & c1, const char4 & c2)
{
    int result;

    result = c1.x - c2.x; if (result !=0) return result; 
    result = c1.y - c2.y; if (result !=0) return result; 
    result = c1.z - c2.z; if (result !=0) return result; 
    result = c1.w - c2.w; if (result !=0) return result; 

    return 0;
}

__device__ __host__
int strncmp4(const char4 * s1, const char4 * s2, const unsigned int nwords)
{
    for(unsigned int i=0; i<nwords; i++) {
        int result = cmp4(s1[i], s2[i]);
        if (result != 0) return result;
    }

    return 0;
}

__global__
void tkernel(const struct gpuStringArray a, const gpuStringArray b, int * result)
{
    int idx = threadIdx.x + blockIdx.x * blockDim.x;

    char4 * s1 = a.data + a.pos[idx];
    char4 * s2 = b.data + b.pos[idx];
    unsigned int slen = min(a.length[idx], b.length[idx]);

    result[idx] = strncmp4(s1, s2, slen);
}
\uuuuu设备\uuuuuu主机__
内部cmp4(常量字符4和c1,常量字符4和c2)
{
int结果;
result=c1.x-c2.x;如果(result!=0)返回结果;
result=c1.y-c2.y;如果(result!=0)返回结果;
result=c1.z-c2.z;如果(result!=0)返回结果;
result=c1.w-c2.w;如果(result!=0)返回结果;
返回0;
}
__设备主机__
int strncmp4(常量char4*s1,常量char4*s2,常量无符号int nwords)
{

对于(unsigned int i=0;iDo)您真正的意思是“CUDA数组”(如用于纹理和曲面的空间有序数据)还是“可用于内核内一般全局内存访问的数组”?@Talonmes:我只需要创建一个字符串数组并在全局内存中访问它。类似于C中的char**array。我们如何为GPU做到这一点。此外,由于CUDA中没有strcmp函数,解决方法是什么?你真正的意思是“CUDA数组”(如用于纹理和曲面的空间顺序数据)还是“可用于内核内常规全局内存访问的阵列“?@Talonmes:我只需要创建一个字符串数组并在全局内存中访问它。类似于C中的char**array。我们如何为GPU做到这一点。此外,由于CUDA中没有strcmp函数,解决方法是什么?这并没有真正回答问题-他想知道如何在GP中存储和管理字符串数组