nvJitLink

nvJitLink 库的用户指南。

1. 简介

JIT Link API 是一组 API,可以在运行时用于链接 GPU 设备代码。

这些 API 接受多种格式的输入,包括主机对象、主机库、fatbin(包括可重定位的 ptx)、设备 cubin、PTX、索引文件或 LTO-IR。 输出是一个链接的 cubin,可以通过 CUDA 驱动程序 API 的 cuModuleLoadDatacuModuleLoadDataEx 加载。

当给定 LTO-IR 或包含 LTO-IR 的更高级别格式时,也可以执行链接时优化。

如果输入不包含 GPU 汇编代码,则首先编译,然后再链接。

此库中的功能类似于 CUDA 驱动程序中的 cuLink* API,但具有以下优势

  • cuLink* API 已被弃用,不建议与 LTO-IR 一起使用

  • 支持链接时优化

  • 允许用户将运行时链接与作为 CUDA 工具包发布一部分支持的最新工具包版本一起使用。 如果应用程序在系统上安装了较旧的驱动程序,则 CUDA 驱动程序 API 中可能不提供此支持。 有关更多详细信息,请参阅 CUDA 兼容性

  • 客户端可以获得细粒度的控制,并且可以在链接期间指定低级编译器选项。

2. 入门指南

2.1. 系统要求

JIT Link 库需要以下系统配置

  • 非 Windows 平台的 POSIX 线程支持。

  • GPU:任何具有 CUDA 计算能力 3.5 或更高的 GPU。

  • CUDA 工具包和驱动程序。

2.2. 安装

JIT Link 库是 CUDA 工具包版本的一部分,组件按如下方式组织在 CUDA 工具包安装目录中

  • 在 Windows 上

    • include\nvJitLink.h

    • lib\x64\nvJitLink.dll

    • lib\x64\nvJitLink_static.lib

    • doc\pdf\nvJitLink_User_Guide.pdf

  • 在 Linux 上

    • include/nvJitLink.h

    • lib64/libnvJitLink.so

    • lib64/libnvJitLink_static.a

    • doc/pdf/nvJitLink_User_Guide.pdf

3. 用户界面

本章介绍 JIT Link API。 API 的基本用法在 基本用法 中进行了解释。

3.1. 错误代码

枚举

nvJitLinkResult

枚举类型 nvJitLinkResult 定义 API 调用结果代码。

3.1.1. 枚举

enum nvJitLinkResult

枚举类型 nvJitLinkResult 定义 API 调用结果代码。

nvJitLink API 返回 nvJitLinkResult 代码以指示结果。

3.2. 链接

枚举

nvJitLinkInputType

枚举类型 nvJitLinkInputType 定义可以传递给 nvJitLinkAdd* API 的输入类型。

函数

nvJitLinkResult nvJitLinkAddData(nvJitLinkHandle handle, nvJitLinkInputType inputType, const void *data, size_t size, const char *name)

nvJitLinkAddData 将数据映像添加到链接中。

nvJitLinkResult nvJitLinkAddFile(nvJitLinkHandle handle, nvJitLinkInputType inputType, const char *fileName)

nvJitLinkAddFile 从文件读取数据并将其链接到链接中。

nvJitLinkResult nvJitLinkComplete(nvJitLinkHandle handle)

nvJitLinkComplete 执行实际链接。

nvJitLinkResult nvJitLinkCreate(nvJitLinkHandle *handle, uint32_t numOptions, const char **options)

nvJitLinkCreate 使用给定的输入选项创建 nvJitLinkHandle 的实例,并设置输出参数 handle

nvJitLinkResult nvJitLinkDestroy(nvJitLinkHandle *handle)

nvJitLinkDestroy 释放与给定句柄关联的内存,并将其设置为 NULL。

nvJitLinkResult nvJitLinkGetErrorLog(nvJitLinkHandle handle, char *log)

nvJitLinkGetErrorLog 将任何错误消息放入日志中。

nvJitLinkResult nvJitLinkGetErrorLogSize(nvJitLinkHandle handle, size_t *size)

nvJitLinkGetErrorLogSize 获取错误日志的大小。

nvJitLinkResult nvJitLinkGetInfoLog(nvJitLinkHandle handle, char *log)

nvJitLinkGetInfoLog 将任何信息消息放入日志中。

nvJitLinkResult nvJitLinkGetInfoLogSize(nvJitLinkHandle handle, size_t *size)

nvJitLinkGetInfoLogSize 获取信息日志的大小。

nvJitLinkResult nvJitLinkGetLinkedCubin(nvJitLinkHandle handle, void *cubin)

nvJitLinkGetLinkedCubin 获取链接的 cubin。

nvJitLinkResult nvJitLinkGetLinkedCubinSize(nvJitLinkHandle handle, size_t *size)

nvJitLinkGetLinkedCubinSize 获取链接的 cubin 的大小。

nvJitLinkResult nvJitLinkGetLinkedPtx(nvJitLinkHandle handle, char *ptx)

nvJitLinkGetLinkedPtx 获取链接的 ptx。

nvJitLinkResult nvJitLinkGetLinkedPtxSize(nvJitLinkHandle handle, size_t *size)

nvJitLinkGetLinkedPtxSize 获取链接的 ptx 的大小。

nvJitLinkResult nvJitLinkVersion(unsigned int *major, unsigned int *minor)

nvJitLinkVersion 返回 nvJitLink 的当前版本。

类型定义

nvJitLinkHandle

nvJitLinkHandle 是链接的单元,也是程序的 opaque 句柄。

3.2.1. 枚举

enum nvJitLinkInputType

枚举类型 nvJitLinkInputType 定义可以传递给 nvJitLinkAdd* API 的输入类型。

3.2.2. 函数

static inline nvJitLinkResult nvJitLinkAddData(nvJitLinkHandle handle, nvJitLinkInputType inputType, const void *data, size_t size, const char *name)

nvJitLinkAddData 将数据映像添加到链接中。

参数
  • handle[in] nvJitLink 句柄。

  • inputType[in] 输入类型。

  • data[in] 指向内存中数据映像的指针。

  • size[in] 数据的大小。

  • name[in] 输入对象的名称。

返回值

static inline nvJitLinkResult nvJitLinkAddFile(nvJitLinkHandle handle, nvJitLinkInputType inputType, const char *fileName)

nvJitLinkAddFile 从文件读取数据并将其链接到链接中。

参数
  • handle[in] nvJitLink 句柄。

  • inputType[in] 输入类型。

  • fileName[in] 文件名。

返回值

static inline nvJitLinkResult nvJitLinkComplete(nvJitLinkHandle handle)

nvJitLinkComplete 执行实际链接。

参数

handle[in] nvJitLink 句柄。

返回值

static inline nvJitLinkResult nvJitLinkCreate(nvJitLinkHandle *handle, uint32_t numOptions, const char **options)

nvJitLinkCreate 使用给定的输入选项创建 nvJitLinkHandle 的实例,并设置输出参数 handle

它支持 支持的链接选项 中列出的选项。

另请参阅

nvJitLinkDestroy

参数
  • handle[out] nvJitLink 句柄的地址。

  • numOptions[in] 传递的选项数量。

  • options[in] 大小为 numOptions 的选项字符串数组。

返回值

static inline nvJitLinkResult nvJitLinkDestroy(nvJitLinkHandle *handle)

nvJitLinkDestroy 释放与给定句柄关联的内存,并将其设置为 NULL。

另请参阅

nvJitLinkCreate

参数

handle[in] nvJitLink 句柄的地址。

返回值

static inline nvJitLinkResult nvJitLinkGetErrorLog(nvJitLinkHandle handle, char *log)

nvJitLinkGetErrorLog 将任何错误消息放入日志中。

用户负责分配足够的空间来容纳 log

另请参阅

nvJitLinkGetErrorLogSize

参数
  • handle[in] nvJitLink 句柄。

  • log[out] 错误日志。

返回值

static inline nvJitLinkResult nvJitLinkGetErrorLogSize(nvJitLinkHandle handle, size_t *size)

nvJitLinkGetErrorLogSize 获取错误日志的大小。

另请参阅

nvJitLinkGetErrorLog

参数
  • handle[in] nvJitLink 句柄。

  • size[out] 错误日志的大小。

返回值

static inline nvJitLinkResult nvJitLinkGetInfoLog(nvJitLinkHandle handle, char *log)

nvJitLinkGetInfoLog 将任何信息消息放入日志中。

用户负责分配足够的空间来容纳 log

另请参阅

nvJitLinkGetInfoLogSize

参数
  • handle[in] nvJitLink 句柄。

  • log[out] 信息日志。

返回值

static inline nvJitLinkResult nvJitLinkGetInfoLogSize(nvJitLinkHandle handle, size_t *size)

nvJitLinkGetInfoLogSize 获取信息日志的大小。

另请参阅

nvJitLinkGetInfoLog

参数
  • handle[in] nvJitLink 句柄。

  • size[out] 信息日志的大小。

返回值

static inline nvJitLinkResult nvJitLinkGetLinkedCubin(nvJitLinkHandle handle, void *cubin)

nvJitLinkGetLinkedCubin 获取链接的 cubin。

用户负责分配足够的空间来容纳 cubin

另请参阅

nvJitLinkGetLinkedCubinSize

参数
  • handle[in] nvJitLink 句柄。

  • cubin[out] 链接的 cubin。

返回值

static inline nvJitLinkResult nvJitLinkGetLinkedCubinSize(nvJitLinkHandle handle, size_t *size)

nvJitLinkGetLinkedCubinSize 获取链接的 cubin 的大小。

另请参阅

nvJitLinkGetLinkedCubin

参数
  • handle[in] nvJitLink 句柄。

  • size[out] 链接的 cubin 的大小。

返回值

static inline nvJitLinkResult nvJitLinkGetLinkedPtx(nvJitLinkHandle handle, char *ptx)

nvJitLinkGetLinkedPtx 获取链接的 ptx。

仅在使用 -lto 选项时,链接的 PTX 才可用。 用户负责分配足够的空间来容纳 ptx

另请参阅

nvJitLinkGetLinkedPtxSize

参数
  • handle[in] nvJitLink 句柄。

  • ptx[out] 链接的 PTX。

返回值

static inline nvJitLinkResult nvJitLinkGetLinkedPtxSize(nvJitLinkHandle handle, size_t *size)

nvJitLinkGetLinkedPtxSize 获取链接的 ptx 的大小。

仅在使用 -lto 选项时,链接的 PTX 才可用。

另请参阅

nvJitLinkGetLinkedPtx

参数
  • handle[in] nvJitLink 句柄。

  • size[out] 链接的 PTX 的大小。

返回值

nvJitLinkResult nvJitLinkVersion(unsigned int *major, unsigned int *minor)

nvJitLinkVersion 返回 nvJitLink 的当前版本。

参数
  • major[out] 主版本号。

  • minor[out] 次版本号。

返回值

3.2.3. 类型定义

typedef struct nvJitLink *nvJitLinkHandle

nvJitLinkHandle 是链接的单元,也是程序的 opaque 句柄。

要链接输入,必须首先使用 nvJitLinkCreate() 创建 nvJitLinkHandle 的实例。

4. 基本用法

本文档的此部分使用一个简单的示例来说明如何使用 JIT Link API 链接程序。为了简洁和可读性,未显示 API 返回值的错误检查。

此示例假设我们要为 sm_80 链接,但应使用系统上安装的任何架构。我们可以创建链接器并获取其句柄,如图 1所示。

图 1. 链接器创建和程序初始化

nvJitLink_t linker;
const char* link_options[] = { "-arch=sm_80" };
nvJitLinkCreate(&linker, 1, link_options);

假设我们已经有两个可重定位的输入文件(a.o 和 b.o),可以使用 nvcc -dc 命令创建。我们可以添加输入文件,如图 2所示。

nvJitLinkAddFile(linker, NVJITLINK_INPUT_OBJECT, "a.o");
nvJitLinkAddFile(linker, NVJITLINK_INPUT_OBJECT, "b.o");

现在可以完成实际链接,如图 3所示。

图 3. PTX 程序的链接

nvJitLinkComplete(linker);

现在可以获得链接的 GPU 汇编代码。为了获得此代码,我们首先为其分配内存。为了分配内存,我们需要查询链接的 GPU 汇编代码映像的大小,如图 4所示。

图 4. 查询链接的汇编映像的大小

nvJitLinkGetLinkedCubinSize(linker, &cubinSize);

现在可以查询链接的 GPU 汇编代码映像,如图 5所示。然后可以通过将此映像传递给 CUDA 驱动程序 API 在 GPU 上执行此映像。

图 5. 查询链接的汇编映像

elf = (char*) malloc(cubinSize);
nvJitLinkGetLinkedCubin(linker, (void*)elf);

当不再需要链接器时,可以销毁它,如图 6所示。

图 6. 销毁链接器

nvJitLinkDestroy(&linker);

5. 兼容性

nvJitLink 库在同一发行版的小版本之间兼容,但在主版本之间可能不兼容。库版本本身必须 >= 输入的最大版本,并且共享库版本必须 >= 与其链接的版本。

例如,如果您的 nvJitLink 库版本为 12.x,其中 x >= 1,则可以链接使用 12.0 创建的对象和使用 12.1 创建的对象。如果它是与 12.1 链接的,那么您可以替换并使用任何版本为 12.x 的 nvJitLink 共享库,其中 x >= 1。另一方面,您不能使用 12.0 链接 12.1 对象,也不能使用 12.0 nvJitLink 库来运行 12.1 代码。

跨主版本(例如 11.x 与 12.x)的链接适用于 ELF 和 PTX 输入,但不适用于 LTOIR 输入。如果使用 LTO,则仅在主版本内保证兼容性。

将扩展 ISA 源(如 sm_90a)与任何其他 sm 版本链接将始终失败。

只要最终链接是所有被链接的架构中最新的,链接来自不同架构(例如 compute_89 和 compute_90)的 PTX 源就可以工作。也就是说,对于任何 compute_X 和 compute_Y,如果目标是 sm_N,其中 N >= max(X,Y),则链接有效。

只要最终链接是所有被链接的架构中最新的,链接来自不同架构(例如 lto_89 和 lto_90)的 LTO 源就可以工作。也就是说,对于任何 lto_X 和 lto_Y,如果目标是 sm_N,其中 N >= max(X,Y),则链接有效。

与非 PTX、非 LTO 源的链接仅限于链接兼容的架构,例如 sm_70 和 sm_75 可以相互链接,但不能与 sm_80 链接。