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