nvJitLink

nvJitLink库的用户指南。

1. 简介

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

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

当提供包含LTO-IR的LTO中间表示或更高级格式时,也可以执行链接时优化。

如果输入内容不包含GPU汇编代码,则会先进行编译再链接。

该库的功能与CUDA驱动中的cuLink* API类似,具有以下优势:

  • cuLink* API 已弃用与 LTO-IR 配合使用

  • 支持链接时间优化

  • 允许用户使用运行时链接功能,该功能支持作为CUDA Toolkit发布的一部分的最新工具包版本。如果应用程序在系统中安装了较旧的驱动程序上运行,则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_用户指南.pdf

3. 用户界面

本章介绍JIT Link API。API的基本用法在Basic Usage中有详细说明。

3.1. 错误代码

枚举

nvJitLinkResult

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

3.1.1. 枚举

enum nvJitLinkResult

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

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

取值:

3.2. 链接

枚举

nvJitLinkInputType

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

Functions

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是链接的基本单位,也是程序的不透明句柄。

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 将数据映像添加到链接中。

Parameters
  • handle[输入] nvJitLink句柄。

  • inputType[in] 输入类型。

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

  • size[in] 数据的大小。

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

Returns

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

nvJitLinkAddFile 从文件中读取数据并进行链接。

Parameters
  • handle[输入] nvJitLink句柄。

  • inputType[in] 输入类型。

  • fileName[in] 文件名。

Returns

static inline nvJitLinkResult nvJitLinkComplete(nvJitLinkHandle handle)

nvJitLinkComplete 执行实际的链接操作。

Parameters

handle[输入] nvJitLink句柄。

Returns

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

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

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

另请参阅

nvJitLinkDestroy

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

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

  • options[输入]numOptions个选项字符串组成的数组。

Returns

static inline nvJitLinkResult nvJitLinkDestroy(nvJitLinkHandle *handle)

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

另请参阅

nvJitLinkCreate

Parameters

handle[输入] nvJitLink句柄的地址。

Returns

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

nvJitLinkGetErrorLog 将任何错误信息记录到日志中。

用户需负责分配足够的空间来存储log

另请参阅

nvJitLinkGetErrorLogSize

Parameters
  • handle[输入] nvJitLink句柄。

  • log[out] 错误日志。

Returns

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

nvJitLinkGetErrorLogSize 获取错误日志的大小。

另请参阅

nvJitLinkGetErrorLog

Parameters
  • handle[输入] nvJitLink句柄。

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

Returns

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

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

用户需负责分配足够的空间来存储log

另请参阅

nvJitLinkGetInfoLogSize

Parameters
  • handle[输入] nvJitLink句柄。

  • log[out] 信息日志。

Returns

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

nvJitLinkGetInfoLogSize 获取信息日志的大小。

另请参阅

nvJitLinkGetInfoLog

Parameters
  • handle[输入] nvJitLink句柄。

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

Returns

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

nvJitLinkGetLinkedCubin 获取已链接的cubin文件。

用户需负责分配足够的空间来存储cubin

另请参阅

nvJitLinkGetLinkedCubinSize

Parameters
  • handle[输入] nvJitLink句柄。

  • cubin[out] 链接后的cubin文件。

Returns

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

nvJitLinkGetLinkedCubinSize 获取已链接cubin的大小。

另请参阅

nvJitLinkGetLinkedCubin

Parameters
  • handle[输入] nvJitLink句柄。

  • size[out] 关联cubin文件的大小。

Returns

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

nvJitLinkGetLinkedPtx 获取已链接的ptx。

链接PTX仅在启用-lto选项时可用。用户需自行分配足够空间来存储ptx

另请参阅

nvJitLinkGetLinkedPtxSize

Parameters
  • handle[输入] nvJitLink句柄。

  • ptx[输出] 链接的PTX。

Returns

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

nvJitLinkGetLinkedPtxSize 获取已链接ptx的大小。

链接PTX仅在启用-lto选项时可用。

另请参阅

nvJitLinkGetLinkedPtx

Parameters
  • handle[输入] nvJitLink句柄。

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

Returns

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

nvJitLinkVersion 返回当前 nvJitLink 的版本。

Parameters
  • major[out] 主版本号。

  • minor[out] 次要版本号。

Returns

3.2.3. 类型定义

typedef struct nvJitLink *nvJitLinkHandle

nvJitLinkHandle是链接的单位,也是程序的不透明句柄。

要链接输入,首先需要使用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命令创建。我们可以按照Figure 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版本(x >= 1)替换并使用nvJitLink共享库。反之,您不能使用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源文件(例如lto_89和lto_90)可以正常工作,只要最终链接是所有被链接架构中最新的。也就是说,对于任何lto_X和lto_Y,如果目标是sm_N且N >= max(X,Y),则该链接是有效的。

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