C++ 使用cuModuleLoad从ELF二进制文件(从argv[0]中)获取当前模块

C++ 使用cuModuleLoad从ELF二进制文件(从argv[0]中)获取当前模块,c++,cuda,gpu,C++,Cuda,Gpu,情况: 我试图使用cuModuleLoad加载当前二进制文件(ELF)的嵌入式cubin(和PTX),但它一直出错,错误代码为200。我的问题是,如果cubin被嵌入到最终的二进制文件中,为什么我不能使用cuModuleLoad来动态加载自己的文件呢?当我编译一个单独的fatbinary时,它可以工作,但当我加载一个单独的PTX模块时,当然当我尝试加载最终的二进制文件(a.out)时,它就不能工作了。我有几个理由想加载当前的可执行文件,为了不偏离主题,我将放弃它。我也在寻找一种无需使用实用工具(

情况: 我试图使用cuModuleLoad加载当前二进制文件(ELF)的嵌入式cubin(和PTX),但它一直出错,错误代码为200。我的问题是,如果cubin被嵌入到最终的二进制文件中,为什么我不能使用cuModuleLoad来动态加载自己的文件呢?当我编译一个单独的fatbinary时,它可以工作,但当我加载一个单独的PTX模块时,当然当我尝试加载最终的二进制文件(a.out)时,它就不能工作了。我有几个理由想加载当前的可执行文件,为了不偏离主题,我将放弃它。我也在寻找一种无需使用实用工具(或系统调用)即可维护单个文件的解决方案

在Linux中:

#include "cuda.h"
#include <cstdio>
#include <iostream>

using clock_value_t = long long;

__device__ void test(  )
{
  printf("Testing... : \n");
}

__device__ void sleep(clock_value_t sleep_cycles)
{
    clock_value_t start = clock64();
    clock_value_t cycles_elapsed;
    do { cycles_elapsed = clock64() - start; }
    while (cycles_elapsed < sleep_cycles);
}

extern "C" __global__ void hello_world(  )
{
  printf("Hello World from Device\n");
  sleep( 1e9 );
  test();
}


int main(int argc, char * argv[])
{

  std::cout << argv[0] << std::endl;

  // Initialize input vectors    ...
  //Initialize
  cuInit(0);
  // Get number of devices supporting CUDA
  int deviceCount = 0;
  cuDeviceGetCount(&deviceCount);

  if (deviceCount == 0)
  {
    printf("There is no device supporting CUDA.\n");
    exit (0);
  }
  else std::cout << "Number of device is "<< deviceCount << std::endl;

  // Get handle for device 0
  CUdevice cuDevice;
  cuDeviceGet(&cuDevice, 0);
  // Create context
  CUcontext cuContext;
  int ret = cuCtxCreate(&cuContext, 0, cuDevice);

  if( ret != CUDA_SUCCESS )
          std::cout << "Could not create context on device 0" << std::endl;

  // Create module from binary file
  CUmodule cuModule;

  ret = cuModuleLoad(&cuModule, argv[0]); // <---errors HERE
  
  if( ret != CUDA_SUCCESS )
  {
    std::cout << "Failed to load self fatbin : " << argv[0] << " : " << ret<< std::endl;
    return -1;
  }
}
#包括“cuda.h”
#包括
#包括
使用时钟_值_t=long;
__设备无效测试()
{
printf(“测试…:\n”);
}
__设备无效睡眠(时钟值睡眠周期)
{
clock_value_t start=clock64();
时钟\u值\u t周期\u已过;
do{cycles_appeased=clock64()-start;}
while(经过的周期<睡眠周期);
}
外部“C”\uuuuu全局\uuuuuu无效hello\u world()
{
printf(“来自设备的Hello World\n”);
睡眠(1e9);
test();
}
int main(int argc,char*argv[])
{

std::cout找到了解决方案。简言之:

  • fopen(argv[0])
  • mmap(文件)
  • 阅读ELF标题并找到“.nv_fatbin”部分
  • 解析“.nv_fatbin”与字节序列“50 ed 55 ba 01 00 10 00”对齐
  • 查找与要使用cuModuleGetFunction的全局方法相关的立方体
  • 调用基址为.nv_fatbin+特定立方偏移量的cuModuleLoadFatBinary
  • 使用cuModuleGetFunction获取函数
  • 最后调用内核
  • 请参见下面的粗略代码以供参考:

    int main(int argc, char * argv[])
    {
      std::cout << "Hello World from Host" << std::endl;
      std::cout << argv[0] << std::endl;
      void * start_ptr =NULL;
      struct stat sb;
      size_t sz =0;
    
      //read_elf_header( argv[0] );
      // Either Elf64_Ehdr or Elf32_Ehdr depending on architecture.
      ElfW(Ehdr) elf_header;
      ElfW(Shdr) header;
    
      std::cout << "opening elf file" << std::endl;
      FILE* file = fopen(argv[0], "rb");
    
      int fd = fileno( file );
    
      if (fd < 0)
      {
        printf("Could not open file for memory mapping, fd = %i\n", errno);
        exit(1);
      }
    
      std::cout << "getting file size" << std::endl;
      if (fstat(fd, &sb) == -1)          // To obtain file size
        printf("Could not find fstat");
      sz = sb.st_size;
    
      std::cout << "Mapping file to memory : " << sz << std::endl;
      start_ptr = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
    
      //check if valid elf
      bool b = elf_is_elf64( file );
      fseek( file, 0, SEEK_SET );
      std::cout << "is ELF file : " << b << std::endl;
      if( b)
      {
        std::cout << "Found valid ELF file" << std::endl;
        //get ELF_Header
        b = elf64_get_elf_header(file, &elf_header);
        fseek( file, 0, SEEK_SET );
    
        if( b )
        {
          std::cout << "-Found valid ELF Header" << std::endl;
          b = elf64_get_section_header_by_name(file, (const Elf64_Ehdr *) &elf_header, ".nv_fatbin", &header);
          fseek( file, 0, SEEK_SET );
    
          if( b )
          {
            std::cout << "Found fatbin section" << std::endl;
            cuInit(0);
            // Get number of devices supporting CUDA
            int deviceCount = 0;
            cuDeviceGetCount(&deviceCount);
    
            if (deviceCount == 0)
            {
              printf("There is no device supporting CUDA.\n");
              exit (0);
            }
            else std::cout << "Number of device is "<< deviceCount << std::endl;
    
            // Get handle for device 0
            CUdevice cuDevice;
            cuDeviceGet(&cuDevice, 0);
            // Create context
            CUcontext cuContext;
            int ret = cuCtxCreate(&cuContext, 0, cuDevice);
            if( ret != CUDA_SUCCESS )
              std::cout << "Could not create context on device 0" << std::endl;
            // Create module from binary file
            CUmodule cuModule;
            std::cout << "sh_addr = " <<  header.sh_addr << std::endl;
            unsigned long long offset = header.sh_addr;
            
            unsigned long long cuOffset = _find_cubin_offset( header, start_ptr, offset, "_Z11hello_worldv");
    
            const void * fatbin = &((unsigned char *) start_ptr)[cuOffset];
            
            std:: cout << "fat bin = " << fatbin << std::endl;
    
            ret = cuModuleLoadFatBinary(&cuModule, fatbin );
    
            if( ret != CUDA_SUCCESS )
            {
              std::cout << "Failed to load self fatbin : " << argv[0] << " : " << ret<< std::endl;
            }
    
            CUfunction khw;
            //ret = cuModuleGetFunction(&khw, cuModule, "hello_world");
            ret = cuModuleGetFunction(&khw, cuModule, "_Z11hello_worldv");
            if( ret != CUDA_SUCCESS )
            {
              std::cout << "Failed to get hello_world from " << argv[0] << " : " << ret <<  std::endl;
            }
            else ret = cuLaunchKernel(khw, 1, 1, 1, 1, 1, 1, 0, 0, NULL, 0);
    
            if( ret != CUDA_SUCCESS )
            {
              std::cout << "Failed to launch : hello_world "  << std::endl;
            }
    
            ret = cuModuleUnload(cuModule);
    
            if( ret != CUDA_SUCCESS )
            {
              std::cout << "Failed to unload self fatbin : " << argv[0] << std::endl;
              return -1;
            }
    
            if (cudaDeviceSynchronize() != cudaSuccess)
            {
              printf ("Cuda call failed\n");
            }
    
            //unmap sutff
            munmap(start_ptr, sz);
            return 0;
          }
        }
    
      }
    
      fclose(file);
    
      return 0;
    
    
    intmain(intargc,char*argv[])
    {
    
    std::cout“该文件应为nvcc输出的cubin文件,或nvcc或手写输出的PTX文件,或nvcc从toolchain 4.0或更高版本输出的fatbin文件。”--我没有看到列出主机可执行文件或elf文件。你知道吗?正确-我理解文档。我想知道它们是一个解决方法,还是一个侧门,因为二进制文件已经嵌入了它。所有的谜题都在那里,如果实现了,它可能会工作,如果没有,我想知道为什么它不工作。没有。驱动程序API不知道关于运行时API,运行时API也不能按您想要的方式工作。想想看,标准主机elf实现中甚至没有公开此类功能。您也不能神奇地延迟加载elf可执行文件的自定义部分和引导。如果您想要类似运行时API的功能,请使用runtime API!cuModuleLoadData如何?它说在Windows中我可以使用FindResource for cubin合并到可执行资源中。我不熟悉FindResource,但它似乎以一种间接的方式实现了我想要的功能。