Это мой первый пост, и я должен сказать, что у меня нет опыта использования CUDA.Я строю алгоритм поиска, используя Cuda (язык C) и VS15.Я хочу найти в большом файле (в данном случае в дампе Википедии) определенное слово и напечатать все места, где слово было найдено (например, строку или позицию первого символа слова).Проблема в том, что параллельная программа намного медленнее, чем последовательная.
Я загружаю первые 1024 символа файла с помощью функции fread (), и каждый поток проверяет, совпадает ли каждая буква загруженной строки спервая буква искомого слова.Если это так, то он проверяет следующее и так далее, в противном случае разрывает цикл.Это происходит в цикле while до конца файла.Я знаю, что постоянная передача данных в gpu и обратно идет медленно, но разве это так медленно?Я хочу спросить, есть ли способ передать весь файл в gpu и вызвать ядро только один раз или есть ли лучший подход.
Ядро моей программы:
#define DATASIZE 1024
#define GRID_SIZE 1
__global__ void searchKeywordKernel(int *result, char *data, char *keyword, int *sl)
{
int i = blockDim.x*blockIdx.x + threadIdx.x;
int match = 0;
// Detect the first matching character
if (data[i] == keyword[0]) {
// Loop through next keyword character
for (int j = 1; j < *sl; j++) {
if (data[i + j] == keyword[j]) {
match =1;
}
else {
// Store the first matching character to the result list
match = 0;
break;
}
}
if (match ==1) {
result[i] = 1;
printf("Character found at position % i\n", i);
}
else { result[i] = 0; }
}
}
Основная функция:
int main()
{
//timers
clock_t start, end, tstart, tend;
double cpu_time_used, tcpu_time_used;
char data[DATASIZE];
//Search for keyword
char *keyword = "wiki";
int linenum = 0;
int result[DATASIZE] ;
char *fname = "F:\\simplewiki-20170820-pages-meta-current.xml";
// Set false value in result array
memset(result, 0, DATASIZE);
tstart = clock();
//LOAD FILE
FILE *fp;
int sl = strlen(keyword);
//hotdata(keyword);
//OPEN FILE
if ((fopen_s(&fp, fname, "r")) != NULL) {
printf("WRONG FILE");
}
int total_matches = 0;
start = clock();
while ((fread(data, DATASIZE, 1, fp) != NULL)) {
end = clock();
cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
printf("Time:%f \n", cpu_time_used);
total_time = total_time + cpu_time_used;
// Search keyword in parallel.
cudaError_t cudaStatus = searchKeyword(result, data, keyword, sl);
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "addWithCuda failed!");
return 1;
}
// Print out the string match result position
for (int i = 0; i < DATASIZE; i++) {
if (result[i] == 1 ) {
printf("LINE:%d \n", linenum);
printf("Character found at position % i\n", i);
total_matches++;
//printf("FOUND: %s \n", data);
}
}
memset(result, 0, DATASIZE);
// cudaDeviceReset must be called before exiting in order for profiling and
// tracing tools such as Parallel Nsight and Visual Profiler to show complete traces.
cudaStatus = cudaDeviceReset();
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaDeviceReset failed!");
return 1;
}
linenum++;
}
tend = clock();
tcpu_time_used = ((double)(tend - tstart)) / CLOCKS_PER_SEC;
printf("Total matches = %d\n", total_matches);
printf("Total Time:%f \n", total_time);
printf("Total Time of everything:%f \n", tcpu_time_used);
system("pause");
return 0;
}
Полезная функция, при которой происходит выделение памяти и memcopy:
cudaError_t searchKeyword(int *result, char *data, char *keyword, int sl)
{
char *dev_data = 0;
char *dev_keyword = 0;
int *dev_result = 0;
int *dev_slp = 0;
int *slp = &sl;
cudaError_t cudaStatus;
cudaStatus = cudaSetDevice(0);
// Choose which GPU to run on, change this on a multi-GPU system.
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaSetDevice failed! Do you have a CUDA-capable GPU installed?");
// goto Error;
}
// Allocate GPU buffers for result set.
cudaStatus = cudaMalloc((void**)&dev_result, DATASIZE * sizeof(int));
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMalloc failed!");
// goto Error;
}
// Allocate GPU buffers for result set.
cudaStatus = cudaMalloc((void**)&dev_data,DATASIZE * sizeof(char));
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMalloc failed!");
// goto Error;
}
// Allocate GPU buffers for keyword.
cudaStatus = cudaMalloc((void**)&dev_keyword, DATASIZE * sizeof(char));
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMalloc failed!");
// goto Error;
}
// Allocate GPU buffers for keyword.
cudaStatus = cudaMalloc((void**)&dev_slp, DATASIZE * sizeof(int));
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMalloc failed!");
// goto Error;
}
// Copy input data from host memory to GPU buffers.
cudaStatus = cudaMemcpy(dev_data, data, DATASIZE * sizeof(char), cudaMemcpyHostToDevice);
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMemcpy failed!");
goto Error;
}
// Copy input data from host memory to GPU buffers.
cudaStatus = cudaMemcpy(dev_slp, slp, DATASIZE * sizeof(char), cudaMemcpyHostToDevice);
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMemcpy failed!");
goto Error;
}
// Copy keyword from host memory to GPU buffers.
cudaStatus = cudaMemcpy(dev_keyword, keyword, DATASIZE * sizeof(char), cudaMemcpyHostToDevice);
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMemcpy failed!");
goto Error;
}
//timer
// Launch a search keyword kernel on the GPU with one thread for each element.
searchKeywordKernel <<<GRID_SIZE, DATASIZE >>>(dev_result, dev_data, dev_keyword, dev_slp);
// cudaDeviceSynchronize waits for the kernel to finish, and returns
// any errors encountered during the launch.
cudaStatus = cudaDeviceSynchronize();
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaDeviceSynchronize returned error code %d after launching addKernel!\n", cudaStatus);
goto Error;
}
// Copy result from GPU buffer to host memory.
cudaStatus = cudaMemcpy(result, dev_result, DATASIZE * sizeof(int), cudaMemcpyDeviceToHost);
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMemcpy failed!");
goto Error;
}
Error:
cudaFree(dev_result);
cudaFree(dev_data);
cudaFree(dev_keyword);
return cudaStatus;
}
Мой графический процессор - 660Ti.Пожалуйста, не обращайте внимания на некоторые логические проблемы моего кода, которые могут быть изменены, и сделайте мою программу быстрее и сосредоточьтесь на реальной проблеме, которая заключается в действительно медленном времени и «плохом» использовании CUDA memcopy внутри цикла while, который, я считаю, является моей главной проблемой.Программа примерно в 50 раз медленнее, чем серийная.Спасибо за помощь.