让我们假设我们需要将以下字符串存储在CUDA数组中。
“你好”
“这是”
“谁是”
我们如何在GPU上声明一个数组来执行此操作。我尝试使用C ++ strings
,但它不起作用。
答案 0 :(得分:2)
执行此操作的最佳方法可能是使用类似于常见压缩稀疏矩阵格式的结构。将打包的字符数据存储到单个线性内存中,然后使用单独的整数数组来存储起始索引,也可以使用第三个数组来存储字符串长度。后者的存储开销可能更有效,即为数据中的每个条目存储字符串终止字节,并尝试解析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
}
注意我使用char4
类型作为字符串数据;向量类型将提供更好的内存吞吐量,但这意味着字符串需要对齐/适当填充到4字节边界。这可能是也可能不是问题,具体取决于应用程序中典型的真实字符串。此外,应该选择(可选)长度参数的类型以反映最大允许字符串长度。如果你有很多非常短的字符串,那么使用8或16位无符号类型来节省内存的长度可能是值得的。
一个真正简单的代码来比较以strcmp
样式存储的字符串可能看起来像这样:
__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);
}
[免责声明:从未编译过,从未测试过,没有真实或暗示的保证,使用风险自负]
这里有一些极端情况和假设可能会根据代码中的真实字符串的确切方式将您识别出来,但我会将这些作为练习留给读者解决。您应该能够适应并扩展到您想要做的任何事情。
答案 1 :(得分:-1)
您必须使用C风格的字符串char *str
。在谷歌上搜索“CUDA字符串”会给你这个CUDA“Hello World”示例作为第一个命中:http://computer-graphics.se/hello-world-for-cuda.html
在那里,您可以看到如何在CUDA中使用char*
- 字符串。请注意,CUDA中不提供strcpy
或strcmp
等标准C函数!
如果你想要一个字符串数组,你只需要使用char**
(如在C / C ++中)。至于strcmp
和类似的功能,它在很大程度上取决于你想做什么。 CUDA不太适合字符串操作,如果你能提供一些关于你想做什么的更多细节,它可能会有所帮助。