Невозможно связать объектные файлы CUDA, созданные из промежуточного представления CUBIN.

Из документации NVIDIA , когда генерируется PTX, CUBIN или FATBIN, код хоста удаляется из файла. Теперь у меня есть код хоста (main.cu) и код устройства (shared.cu). При компиляции каждого файла в *.o с использованием опции nvcc nvcc -c main.cu shared.cu или даже с nvcc -dc main.cu shared.cu и связывании их с опцией nvcc -link main.o shared.o я могу сгенерировать исполняемый файл. Но когда shared.cu компилируется в shared.cubin и далее в *.o, то линковка завершается с ошибкой tmpxft_00001253_00000000-4_main.cudafe1.cpp:(.text+0x150): undefined reference to <KERNEL FUNCTION>

Вот интересно, shared.cu содержит только код устройства и даже если код хоста удален, почему привязка должна завершиться неудачно.

Файлы исходного кода: main.cu.

#include <stdio.h>
#include <cuda_runtime_api.h>
#include <cuda_runtime.h>
#include <cuda.h>
#include "shared.h"
 int main()
{
        int a[5]={1,2,3,4,5};
        int b[5]={1,1,1,1,1};
        int c[5];
        int i;

        int *dev_a;
        int *dev_b;
        int *dev_c;

        cudaMalloc( (void**)&dev_a, 5*sizeof(int) );
        cudaMalloc( (void**)&dev_b, 5*sizeof(int) );
        cudaMalloc( (void**)&dev_c, 5*sizeof(int) );

        cudaMemcpy(dev_a, a , 5 * sizeof(int), cudaMemcpyHostToDevice);
        cudaMemcpy(dev_b, b , 5 * sizeof(int), cudaMemcpyHostToDevice);

        add<<<1,5>>>(dev_a,dev_b,dev_c);

        cudaMemcpy(&c,dev_c,5*sizeof(int),cudaMemcpyDeviceToHost);

        for(i = 0; i < 5; i++ )
        {
                printf("a[%d] + b[%d] = %d\n",i,i,c[i]);
        }
        cudaFree( dev_a);
        cudaFree( dev_b);
        cudaFree( dev_c);
        return 0;
}

shared.cu

#include<stdio.h>

__global__  void add(int *dev_a, int *dev_b, int *dev_c){

        //allocate shared memory
        __shared__ int a_shared[5];
        __shared__ int b_shared[5];
        __shared__ int c_shared[5];
        {
                //get data in shared memory
                a_shared[threadIdx.x]=dev_a[threadIdx.x];
                __syncthreads();

                b_shared[threadIdx.x]=dev_b[threadIdx.x];
                __syncthreads();

                //perform the addition in the shared memory space
                c_shared[threadIdx.x]= a_shared[threadIdx.x] + b_shared[threadIdx.x];
                __syncthreads();

                //shift data back to global memory
                dev_c[threadIdx.x]=c_shared[threadIdx.x];
                __syncthreads();
        }
}

общий.h

#ifndef header
#define header

extern __global__  void add(int *dev_a, int *dev_b, int *dev_c);

#endif

person Ginu Jacob    schedule 21.06.2016    source источник


Ответы (1)


Я полагаю, вы предполагаете, что файл «только код устройства» (например, ваш shared.cu) не содержит кода хоста. Это на самом деле не правильно.

Функция ядра генерирует конструкции кода хоста и устройства, и эти конструкции генерируются препроцессором CUDA (cudafe) и разделяются. См. траекторию компиляции CUDA в документации.

Обратите внимание, что существует первоначальное разделение кода хоста и устройства, за которым следует создание файла .cudafe1.stub.c, который затем передается на сторону хоста (т. .

Как показано на этой диаграмме, файл .cudafe1.stub.c не становится частью cubin, а входит в поток обработки на стороне хоста, в конечном итоге становясь частью файла fatbinary.

Если вы обрабатываете только cubin, вы отбрасываете этот .cudafe1.stub.c, и это необходимо для окончательной ссылки для создания исполняемого бинарного файла.

Поэтому попытка создать толстую двоичную ссылку только с кубином не удастся из-за отсутствия ссылки в файле-заглушке, ссылка на которую указана в выводе ошибки в вашем вопросе.

person Robert Crovella    schedule 21.06.2016
comment
Можно ли сгенерировать .cudafe1.stub.c отдельно и использовать его с файлом cubin/fatbin для окончательной компоновки.... Или есть возможность избежать отбрасывания конструкций хоста при создании fatbin/cubin.... - person Ginu Jacob; 22.06.2016
comment
Это невозможно с использованием стандартных подходов цепочки инструментов. Вы можете поэкспериментировать с параметрами nvcc, чтобы сохранить промежуточные файлы, а используя подробный вывод, вы сможете воспроизвести последовательность сборки самостоятельно. Я не уверен, почему вы хотите. Инструментальная цепочка уже обеспечит необходимое связывание, если вы создадите толстый бинарник стандартными методами. Использование PTX и cubin в первую очередь предназначено для поддержки методов API драйвера CUDA. - person Robert Crovella; 22.06.2016
comment
Единственная идея - немного изменить PTX. С сообщением stackoverflow.com/questions/20012318/how- to-compile-ptx-code Мне не удалось добиться успеха, и я получил следующую ошибку: - person Ginu Jacob; 22.06.2016
comment
sh: 1: bin2c: не найден В файле, включенном из t266.cudafe1.stub.c:1:0: t266.cudafe1.stub.c: В функции 'void __sti__cudaRegisterAll_12_t266_cpp1_ii_ea754d28()': t266.cudafe1.stub.c:2 :126: ошибка: «__fatDeviceText» не был объявлен в этой области *), void*)': crt/link.stub:102:60: ошибка: '__fatDeviceText' не был объявлен в этой области __cudaFatCubinHandle = __cudaRegisterFatBinary((void*)&__fatDeviceText); - person Ginu Jacob; 22.06.2016
comment
Я думаю, вы сделали что-то не так тогда? Я только что просмотрел рецепт там, и он до сих пор работает для меня. Вы пытались использовать сценарий, который я разместил, или вы действительно редактировали свой собственный сценарий из файла dryrun.out? Во всяком случае, я только что ответил на ваш комментарий по этому вопросу ссылкой на полный сеанс консоли, демонстрирующий каждый шаг процесса. Если у вас все еще есть проблемы, не пытайтесь решить их в комментариях к несвязанному вопросу — задайте новый вопрос. - person Robert Crovella; 22.06.2016