DeepSeek开源DeepJIT:统一华为昇腾和英伟达CUDA接口

DeepSeek开源DeepJIT:统一华为昇腾和英伟达CUDA接口

💡 原文中文,约5800字,阅读约需14分钟。
📝

内容提要

DeepSeek开源C++20库DeepJIT,为英伟达CUDA与华为昇腾NPU提供统一的内核JIT编译、缓存与启动接口,统一的是编译外围流程而非编译器本身。核心亮点是含自定义签名的多级缓存与分布式共享缓存,可减少集群重复编译。相比Triton、CuPy各有取舍,目前缓存预热和Python API尚未完成。

🔎

延伸解读

统一的是流程,不是编译器

DeepJIT 常被误解为“写一份 CUDA 代码就能跑在昇腾上”,但文章明确指出,它统一的是编译外围流程:配置管理、缓存键计算、内核加载与启动。编译本身仍依赖 NVCC 和毕昇编译器两条独立路径,CUDA 与昇腾内核的写法差异(如 global 与 global aicore)也无法抹平。因此,它节省的是维护两套缓存与绑定逻辑的样板代码,而非内核代码本身。

缓存键设计的收益与代价

DeepJIT 的缓存键综合源码、头文件依赖、编译器版本与选项,以及应用层自定义签名。自定义签名允许把 SM 数量、共享内存大小等运行时参数纳入缓存,避免不同配置互相污染。但文章提醒,缓存键越复杂,计算开销越大,在极短内核调用场景下可能成为瓶颈。延迟初始化只省去启动阶段的固定开销,并未消除缓存键计算本身的成本。

分布式共享缓存的隐藏前提

DeepJIT 支持将缓存目录挂载到分布式文件系统,让多节点共享已编译内核,直接回应大规模训练中重复编译的痛点。但文章指出,这要求文件系统提供 POSIX 语义,而一些为 AI 训练优化的并行文件系统可能牺牲了部分一致性保证,导致共享缓存在某些集群上无法运行。此外,README 未详细说明并发写入冲突的处理方式,这本身值得警惕。

与 Triton、CuPy 的路线差异

Triton 让开发者用新 DSL 写内核,由它翻译到不同后端,上手门槛低但灵活性受限;DeepJIT 不发明新语言,直接编译原生 CUDA 或昇腾代码,门槛更高但上限更高。CuPy 走 NVRTC 路线,编译快但只支持 NVIDIA GPU,与 DeepJIT 不在同一赛道。DeepJIT 的分布式缓存不依赖 Redis,运维更轻,但目前只有文件系统一种后端,不如 Triton 可插拔。

Q&A

DeepJIT 是什么?它主要解决什么问题?

DeepJIT 是 DeepSeek 开源的一个轻量级、header-only 的 C++20 运行时库,用于在 NVIDIA CUDA GPU 和华为昇腾 NPU 上运行时编译(JIT)内核代码。它旨在为 C++/Python 扩展开发者提供统一的接口,处理内核源代码的编译、二进制缓存、加载到设备以及启动等流程,解决同时维护 CUDA 和昇腾两套内核代码时缓存管理、编译配置和 Python 绑定等重复工作的问题。

DeepJIT 统一了 CUDA 和昇腾的哪些环节?哪些环节没有统一?

DeepJIT 统一的是编译之前和编译之后的环节,包括配置管理、缓存键计算、内核加载和启动调用等外围工作。它没有统一编译器本身:CUDA 后端依赖 NVCC 将 CUDA 源码编译成 CUBIN,昇腾后端依赖毕昇编译器和 ld.lld 编译链接昇腾内核源码。此外,内核代码写法(如 CUDA 用 global 修饰,昇腾用 global aicore 修饰)和启动参数(CUDA 用 grid_dim/block_dim,昇腾用 num_blocks)也无法统一。

DeepJIT 的缓存键包含哪些信息?为什么这样设计?

DeepJIT 的缓存键综合了四类信息:内核源码、被追踪的头文件依赖、编译器版本和有效编译选项、以及应用层提供的自定义依赖签名。这样设计是为了让不同配置的内核各自独立缓存,互不污染。例如,矩阵乘法内核的性能可能取决于 GPU 的 SM 数量、共享内存大小或启动时的 block 维度,这些运行时信息可以通过自定义签名纳入缓存键,确保编译产物的正确性和性能。

DeepJIT 的分布式共享缓存有什么作用?可能存在哪些限制?

分布式共享缓存允许将同一个缓存目录挂载到分布式文件系统上,让多个用户、进程或计算节点共享已编译内核缓存,从而减少集群中的重复编译。例如在 128 卡集群上,第一张卡编译后,其余 127 张可直接读缓存。限制在于:文件系统必须提供 POSIX 语义,而一些为 AI 训练优化的并行文件系统可能牺牲了 POSIX 一致性,导致共享缓存无法运行;此外,大量进程同时缓存未命中时并发写入冲突的处理方式在 README 中未详细说明。

DeepJIT 与 Triton 在缓存和编译路线上有什么不同?

Triton 是 OpenAI 开源的 Python DSL,让你用新语言写内核,由 Triton 负责翻译到不同后端,其缓存用 SHA-256 哈希源码和依赖,支持通过 RemoteCacheManager 接入 Redis 做分布式缓存。DeepJIT 不发明新语言,你写原生 CUDA C++ 或昇腾内核代码,它只负责编译和缓存。DeepJIT 的分布式缓存不依赖 Redis 等外部服务,直接用文件系统共享,但缓存后端目前只有文件系统一种选择;Triton 的缓存后端可插拔替换。

DeepJIT 目前有哪些功能尚未完成?对用户有什么影响?

DeepJIT 的 README 中写明两个功能还在开发中:一是“缓存预热”,根据历史缓存记录预测未来可能需要的内核并提前编译,以减少运行时编译延迟;二是“Python 编译 API”,允许直接从 Python 传内核源码给 DeepJIT 编译。目前这两个功能都不可用,因此用户必须写 C++ 扩展并通过 pybind11 暴露接口给 Python,无法在 Jupyter Notebook 中直接编译运行内核。

🏷️

标签

➡️

继续阅读