Проблема с привязкой Nsight CUDA между несколькими файлами .cu, .h и .c

#c #c #cuda #nsight

#c #c #cuda #взгляд

Вопрос:

Это первый раз, когда я пытаюсь создать свое приложение CUDA в NSight Ubuntu, чтобы извлечь выгоду из оптимизации и профилирования. Это приложение отлично работает с терминала, используя nvcc (makefile) в Ubuntu 20 (или 18, 16). У меня есть несколько файлов .cu, .c и .h. Все файлы сначала включаются в файл flags.h. Мой код начинается с main.cu (имеет main() функцию), и в этом файле есть # include «flags.h», чтобы убедиться, что все файлы включены для компиляции кода. флаги.у h также есть много #define , которые позже будут использоваться в разных файлах .cu и .c.

Однако внутри NSight ни один из параметров #define, определенных во flags.h, не распознается ни в одном из файлов, и я получаю сообщение об ошибке. Ниже приведен скриншот ошибки. Я прилагаю простую задачу square_array, разделенную на 3 файла(main.cu , флаги.h и square_.cu ).

Я не могу построить это в NSight. Может кто-нибудь попробовать его построить и дайте мне знать, пожалуйста. Любая помощь или предложение будут высоко оценены.

main.cu

 #include <stdio.h>
#include <stdlib.h>

#include "flags.h"


int main(void) {

    int i;
    int *a_h, *a_d;

    CUDA_CHECK_RETURN(cudaMalloc((void**) amp;a_d, sizeof(int) * WORK_SIZE));
    a_h = (int *)malloc(sizeof(int) * WORK_SIZE);        // Allocate array on host

    for (i = 0; i < WORK_SIZE; i  )
        a_h[i] = i 2.;

    int block_size = 4;
    int n_blocks = WORK_SIZE/block_size   (WORK_SIZE%block_size == 0 ? 0:1);

    sq_array<<<n_blocks, block_size>>>(a_d);

    CUDA_CHECK_RETURN(cudaGetLastError());
    CUDA_CHECK_RETURN(cudaMemcpy(a_h, a_d, sizeof(int) * WORK_SIZE, cudaMemcpyDeviceToHost));

    for (i = 0; i < WORK_SIZE; i  )
        printf("Input value: %d n", a_h[i]  );

    CUDA_CHECK_RETURN(cudaFree((void*) a_d));
    CUDA_CHECK_RETURN(cudaDeviceReset());

    return 0;
}
  

flags.h

 #ifndef FLAGS_H_
#define FLAGS_H_

#include "square_.cu"
#define CUDA_CHECK_RETURN(value) {                                          
    cudaError_t _m_cudaStat = value;                                        
    if (_m_cudaStat != cudaSuccess) {                                       
        fprintf(stderr, "Error %s at line %d in file %sn",                 
                cudaGetErrorString(_m_cudaStat), __LINE__, __FILE__);       
        exit(1);                                                            
    } }


#define WORK_SIZE 29

#endif /* FLAGS_H_ */
  

square_.cu

 __global__ void sq_array( int *a) {
    int idx = blockIdx.x * blockDim.x   threadIdx.x;
    if (idx< WORK_SIZE) a[idx] = a[idx] * a[idx];

}
  

введите описание изображения здесь

Комментарии:

1. Вы #include редактируете .cu файл и компилируете .cu файл, что означает, что у вас будет два определения sq_array . Когда он компилируется отдельно, определение файла заголовка WORK_SIZE не указано. Не включайте файлы .cu или .c — компилируйте отдельно и связывайте. Вам нужно организовать все так, чтобы sq_array и вызов ядра находились в одном файле, который компилируется один раз.

2. @wcocharan Я надеюсь, что это должен быть процесс сборки в один клик, потому что он работает в терминале с помощью команды make в одну строку. Это короткий код, объясняющий мою проблему, но мой реальный код длинный и сложный с десятками ядер, поэтому я не могу поместить вызов ядра и определение ядра в один файл, как вы предложили. Кроме того, когда у меня есть десятки файлов, компилировать и связывать их по отдельности будет довольно утомительно. будет полезно посмотреть какое-нибудь видео на YouTube.

3. Это работает в командной строке, потому что вы явно не компилируете .cu файл, но IDE это сделает. Вы должны организовать все по-другому. Я работаю над массивными кодовыми базами, которые используют CUDA, и наша обычная стратегия заключается в создании функций «оболочки хоста», которые инкапсулируют код ядра CUDA и вызов. Использование #include "square_.cu" — это просто плохая идея — (вы бы не стали делать этого с .c файлом) — каждый фрагмент отдельно скомпилированного кода, который включает flags.h , будет определять еще одну версию sq_array функции.

4. можете ли вы опубликовать решение, не помещая весь код в один файл? Я опубликовал эту простую проблему здесь, чтобы понять, как «собрать» большой код (разбитый на несколько файлов) в Nsight IDE.

Ответ №1:

Проблема в том, что ваша среда разработки компилируется square_.cu и компилируется main.cu , которая также компилируется square_.cu снова из-за #include "square_.cu" in flags.h , который дает вам два определения sq_array . При square_.cu компиляции WORK_SIZE макрос не определен, что приводит к ошибке во время компиляции. При компиляции в командной строке вы не компилировались square_.cu , поэтому вы избежали этой ошибки.

В любом случае, это плохая идея для #include .cu (или .c файлов). Они должны быть скомпилированы отдельно, а затем связаны вместе.

Вы должны организовать вещи по-другому. Я не знаю деталей вашего кода, но вы можете сделать что-то вроде этого:

square.cu :

 #include "square.h"
  
__global__ void sq_array( int *a) {
    int idx = blockIdx.x * blockDim.x   threadIdx.x;
    if (idx< WORK_SIZE) a[idx] = a[idx] * a[idx];

}
   
void host_sq_array(int *a_d) {
   int block_size = 4;
   int n_blocks = WORK_SIZE/block_size   (WORK_SIZE%block_size == 0 ? 0:1);   
   sq_array<<<n_blocks, block_size>>>(a_d);
}
  

square.h :

 #ifndef SQUARE_H
#define SQUARE_H

#include "flags.h"  // REMOVE #include of .cu file!!!
void host_sq_array(int *a_d);

#endif
  

Вы можете безопасно #include square.h включать только константы, определения типов и прототипы функций.