一、样例demo透析: 旨在透过简单的demo样例刨析,FlexGV系统的工作原理。 demo地址:https://github.com/J-StrawHat/cuda-hook-demo/blob/master/build.sh
首先什么是解释一下什么是CMake项目: CMake 是一个 跨平台的构建系统,用于生成编译配置文件(如 Makefile、Visual Studio 解决方案等)。CMake 本身不会编译代码,但它会为不同的平台和编译器生成适合的构建配置文件,从而让开发者可以使用 make 或 ninja 等工具完成编译。
一个 CMake 项目,通常指的是使用 CMake 构建的 C/C++ 项目,其中包含:
CMakeLists.txt(CMake 配置文件)
源代码(.cpp、.h 等)
CMake 生成的构建文件(Makefile、Visual Studio 解决方案 等)
CMake 不是编译器,它用于生成编译配置文件(如 Makefile)。 CMake 项目 是指使用 CMakeLists.txt 组织的 C/C++ 项目。 使用 CMake 的好处:
跨平台:支持 Linux、Windows、MacOS。
自动查找依赖(如 find_package(OpenCV))。
支持构建动态/静态库。
你可以把 CMake 理解为 “项目构建的指挥官”,它负责告诉编译器怎么编译你的项目。
1.build.sh (主要用于构建编译系统,提前创建好如何编译和处理文件。) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 #!/bin/bash set -o errexitset -o pipefailset -o nounsetecho_cmd () { echo $1 $1 } WORK_PATH=$(cd $(dirname $0 ) && pwd ) && cd $WORK_PATH compile () { isSample=$1 if [[ $isSample == 1 ]]; then cmakeFlag="-DBUILD_SAMPLE=ON" else cmakeFlag="-DBUILD_HOOK=ON" fi echo_cmd "rm -rf build" echo_cmd "mkdir build" echo_cmd "cd build" echo_cmd "cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$WORK_PATH /out $cmakeFlag -DCMAKE_SKIP_RPATH=ON .." echo_cmd "make -j2" echo_cmd "make install" echo_cmd "cd $WORK_PATH " } echo_cmd "rm -rf out" compile 0 compile 1
这个脚本的主要流程是:
确保所有命令在当前脚本所在目录下执行。 清除 out 目录,确保干净环境。 定义 compile 函数,接收 0 或 1 选择不同的 cmake 选项。 先编译 hook 版本(-DBUILD_HOOK=ON)。 再编译 sample 版本(-DBUILD_SAMPLE=ON)。 这样可以确保 hook 和 sample 版本都被正确编译和安装。
2.cuda_hook.cpp //这里相当于拦截层 这个文件主要用于创建cuda_hook,来截取用户的请求也就是CUDA_API。逻辑流程就是在执行用户的需求时也就是执行main.cu文件的时候,首先在终端通过LD_PRELOAD 将main.cu加载到对应的cuda_hook所在的目录里,在main.cu执行的时候,LD_PRELOAD=./libhook.so,系统在 动态链接库解析阶段 发现 libhook.so 里提供了 cudaMalloc,所以会优先调用 libhook.so 里的 cudaMalloc。
LD_PRELOAD原理:预加载一个共享库,在动态链接时优先使用自己的 cudaMalloc。不影响 原始 CUDA 运行时库(只是拦截)
在 LD_PRELOAD 机制下:
1.程序启动时,LD_PRELOAD 里的 libhook.so 先被加载。
2.cudaMalloc 被调用时,动态链接器优先使用 libhook.so 里的 cudaMalloc。
3.如果 libhook.so 里的 cudaMalloc 需要调用原始 cudaMalloc,它会用 dlsym(RTLD_NEXT, "cudaMalloc") 找到 CUDA 运行时库里的真正 cudaMalloc 并调用它。这里可以实现拦截和真实函数的衔接。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <stdio.h> #include <cuda_runtime.h> #include <dlfcn.h> typedef cudaError_t (*cudaMalloc_t) (void **devPtr, size_t size) ;static cudaMalloc_t real_cudaMalloc = nullptr ;cudaError_t cudaMalloc (void **devPtr, size_t size) { if (!real_cudaMalloc) { real_cudaMalloc = (cudaMalloc_t) dlsym (RTLD_NEXT, "cudaMalloc" ); if (!real_cudaMalloc) { fprintf (stderr, "[hook] Error: unable to find real cudaMalloc\n" ); return cudaErrorUnknown; } } printf ("[hook] Intercepted cudaMalloc call: size = %zu bytes\n" , size); return real_cudaMalloc (devPtr, size); }
3.main.cu //这里相当于用户层 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include <cstdio> #include <cassert> #include <cuda_runtime.h> int main () { void *devPtr; cudaError_t err = cudaMalloc (&devPtr, 1024 ); if (err != cudaSuccess) { printf ("[main] cudaMalloc failed: %s\n" , cudaGetErrorString (err)); } else { printf ("[main] cudaMalloc succeeded\n" ); assert (cudaFree (devPtr) == cudaSuccess); } return 0 ; }
4.CMakeLists.txt CMakeLists.txt 是 CMake 的配置文件,它定义了 如何构建(编译、链接、安装)一个 C/C++ 项目。
CMake 是一个跨平台的 构建工具,可以生成适用于不同编译器(GCC、Clang、MSVC)和构建系统(Makefile、Ninja、Visual Studio)的项目文件。 CMakeLists.txt 主要用于 描述源码结构、指定编译选项、链接库 等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 cmake_minimum_required(VERSION 3.12) project(CudaHook)set (CMAKE_POSITION_INDEPENDENT_CODE ON)set (CMAKE_C_FLAGS "-std=c17" )set (CMAKE_C_FLAGS_DEBUG "$ENV {CFLAGS} -O0 -g2 -ggdb -DHOOK_BUILD_DEBUG" )set (CMAKE_C_FLAGS_RELEASE "$ENV {CFLAGS} -O3" )set (CMAKE_CXX_FLAGS "-std=c++17" )set (CMAKE_CXX_FLAGS_DEBUG "$ENV {CXXFLAGS} -O0 -g2 -ggdb -DHOOK_BUILD_DEBUG" )set (CMAKE_CXX_FLAGS_RELEASE "$ENV {CXXFLAGS} -O3" )set (CMAKE_SHARED_LINKER_FLAGS "-s -Wl,--exclude-libs,ALL" )set (CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed" ) option(BUILD_SAMPLE "Build the sample main program" OFF) option(BUILD_HOOK "Build the CUDA hook library" OFF)if (BUILD_HOOK) find_package(CUDA REQUIRED) include_directories(${CUDA_INCLUDE_DIRS} ) add_library(cuda_hook SHARED cuda_hook.cpp) set_target_properties(cuda_hook PROPERTIES POSITION_INDEPENDENT_CODE ON) target_link_libraries(cuda_hook ${CUDA_LIBRARIES} dl) install(TARGETS cuda_hook LIBRARY DESTINATION lib64) endif()if (BUILD_SAMPLE) find_package(CUDA REQUIRED) unset (CUDA_USE_STATIC_CUDA_RUNTIME CACHE) option (CUDA_USE_STATIC_CUDA_RUNTIME OFF) include_directories(${CUDA_INCLUDE_DIRS} ) set (CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS} -std=c++17" ) cuda_add_executable(main main.cu) target_link_libraries(main ${CUDA_LIBRARIES} dl) install(TARGETS main RUNTIME DESTINATION .) endif()