Почему мой алгоритм поиска Cuda медленнее, чем последовательный? - PullRequest
1 голос
/ 17 мая 2019

Это мой первый пост, и я должен сказать, что у меня нет опыта использования 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 раз медленнее, чем серийная.Спасибо за помощь.

...