该代码用于并行化字符串匹配算法(强力)。为什么只有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]);
}
}
答案 0 :(得分:1)
每当您遇到CUDA代码时遇到问题,最好通过cuda-memcheck
来演示和使用proper cuda error checking 和运行您的代码。如果您使用cuda-memcheck
运行此代码,则会报告可能有用的错误。
目前尚不清楚为什么要询问17个主题。在CUDA中,可以从内核启动中推断出启动的线程数,简而言之,它是内核启动配置中前两个数字的乘积(<<<...>>>
):
pattern_search<<<1,50>>>(d_txt,d_pat,d_result,N,M);
所以在这种情况下,它应该启动50个线程。即使您的问题仅限于N
,您发布的代码的数量N
也是18,而不是17。
cudaMalloc
,与主机端malloc
一样,在 bytes 中分配内存。因此,对于这种情况,这样的使用是不正确的:
cudaMalloc((void**)&d_result,N);
而你应该做这样的事情:
cudaMalloc((void**)&d_result,N*sizeof(int));
因为在这种情况下,您希望存储N
个数量为int
的数量。使用cuda-memcheck
可以发现此错误,由于此分配错误,该错误将报告无效的__global__
写入。
cudaMemcpy
次调用也会出现类似问题,这些问题也会在字节上运行(就像主机memcpy
一样)。而不是:
cudaMemcpy(d_result,result,N,cudaMemcpyHostToDevice);
我们想要这个:
cudaMemcpy(d_result,result,N*sizeof(int),cudaMemcpyHostToDevice);
并且需要在内核之后的调用上进行类似的修正。
您的内核有一个越界索引错误:
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
读取可能会发现此错误。
以下代码解决了上述问题,并且对我运行没有错误:
$ 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 expects和MCVE的问题类别。你提供了一个完整的代码,这很好。可能还有一些其他方面可以改进:
更清楚地说明问题所在。关于运行多少个线程的问题不是很清楚。对于一个好的MCVE,您应该解释预期结果是什么并显示实际结果。在某些情况下,提及您正在使用的CUDA版本,编译命令行和平台(主机操作系统)可能也很有用。
演示并使用cuda-memcheck
正确的cuda错误检查和使用。即使您不理解错误输出,也请在您的问题中描述或包含它 - 对于那些试图帮助您的人来说,它会很有用。