3. CUDA核心与Tensor Core:计算单元的家族图谱

说到GPU里的计算单元,很多人第一反应就是「CUDA核心」。嗯,这个说法没错,但不够准确。我刚开始接触CUDA时也以为GPU里全是清一色的计算单元,后来在调优一个深度学习模型时才发现——事情没那么简单。

GPU的计算单元,其实是一个「家族图谱」。里面有负责通用计算的CUDA核心,有专门干矩阵乘法的Tensor Core,还有处理特殊函数的SFU等等。今天我就带你捋一捋这个家族里的各个成员。

3.1 CUDA核心:最通用的打工人

CUDA核心,说白了就是GPU里最基础的算术逻辑单元。每个CUDA核心都能做整数运算和浮点运算。你写的任何CUDA代码,最终都会落到这些核心上执行。

但这里有个坑——NVIDIA官方文档里其实没有「CUDA核心」这个术语。它只是我们工程师约定俗成的叫法。真正的硬件术语叫「CUDA Core」或「Shader Core」。

关键数据:

  • 每个CUDA核心包含:整数ALU + 浮点FPU
  • 支持FP32、INT32、FP64(部分型号)
  • 每个SM(流多处理器)包含几十到上百个CUDA核心

我曾经在优化一个科学计算程序时,发现FP64性能远低于预期。查了半天才发现——消费级显卡的FP64单元被砍掉了大半。嗯,这是个血泪教训。

3.2 Tensor Core:矩阵计算的加速器

Tensor Core是NVIDIA从Volta架构开始引入的专用单元。它专门干一件事——矩阵乘加运算。你想想看,深度学习里的卷积、全连接层,本质上全是矩阵运算。

为什么需要Tensor Core?因为CUDA核心做矩阵乘法太慢了。一个4x4的矩阵乘法,CUDA核心需要16次乘法和12次加法。而Tensor Core一次就能搞定。

特性 CUDA Core Tensor Core
精度支持 FP32/FP64/INT32 FP16/BF16/INT8/INT4
单次运算 1个FMA 4x4矩阵乘加
适用场景 通用计算 深度学习/矩阵运算
吞吐量 基准 8-16倍于CUDA Core

我的建议:如果你的程序涉及大量矩阵运算,优先考虑用Tensor Core。但要注意数据精度——Tensor Core默认用FP16,需要做好精度验证。

3.3 SFU与特殊函数单元

除了CUDA核心和Tensor Core,GPU里还有一类特殊单元——SFU(Special Function Unit)。它负责计算sin、cos、log、exp这些超越函数。

为什么需要单独的SFU?因为这些函数用CUDA核心算太慢了。一个sin函数可能需要几十条指令。而SFU用硬件查表+多项式逼近,几个周期就能出结果。

我记得有一次做音频处理,大量用了sin和cos。一开始用CUDA核心硬算,性能惨不忍睹。后来改成调用内置的__sinf()函数,速度直接翻了5倍。这就是SFU的威力。

3.4 计算单元的层级关系

这些计算单元不是散落在芯片上的。它们有严格的层级结构。我画了一张图,帮你理清关系:

GPU 芯片 GPC (图形处理簇) GPC (图形处理簇) SM SM SM SM CUDA Core x64 Tensor Core x4 SFU x4 CUDA Core x64 Tensor Core x4 SFU x4 CUDA Core x64 Tensor Core x4 SFU x4 CUDA Core x64 Tensor Core x4 SFU x4 共享内存 / L1 缓存 每个SM独享,容量 48KB - 128KB 线程间数据交换的枢纽 L2 缓存 所有SM共享,容量 1MB - 40MB 全局内存的缓存层

从这张图你能看到:

  • GPU芯片包含多个GPC(图形处理簇)
  • 每个GPC包含多个SM(流多处理器)
  • 每个SM内部包含CUDA核心、Tensor Core、SFU
  • SM之间通过共享内存L2缓存通信

3.5 如何选择计算单元?

写CUDA代码时,你不需要手动指定用哪个单元。编译器会自动调度。但了解它们的特性,能帮你写出更高效的代码。

避坑指南:

  • 不要假设所有GPU都有Tensor Core——老架构就没有
  • Tensor Core对数据对齐要求严格,不对齐会触发回退到CUDA Core
  • SFU的精度比CUDA Core低——对精度敏感的场景慎用

我曾经在部署一个推理模型时,发现性能比预期差很多。排查后发现——数据是INT8格式,但没走Tensor Core路径。原因是数据布局不对,编译器自动回退到了CUDA Core。调整数据布局后,性能提升了6倍。

3.6 实战:查看你的GPU计算单元

想知道你的GPU有哪些计算单元?用这个代码就能查:

// 查询GPU计算单元信息
#include <cuda_runtime.h>
#include <stdio.h>

int main() {
    cudaDeviceProp prop;
    cudaGetDeviceProperties(&prop, 0);
    
    printf("GPU型号: %s\n", prop.name);
    printf("SM数量: %d\n", prop.multiProcessorCount);
    printf("每个SM的CUDA核心数: %d\n", 
           prop.maxThreadsPerMultiProcessor / 32);
    printf("Tensor Core支持: %s\n", 
           prop.major >= 7 ? "是" : "否");
    printf("共享内存大小: %.2f KB\n", 
           prop.sharedMemPerMultiprocessor / 1024.0);
    
    return 0;
}

运行这个程序,你就能看到自己GPU的家底了。我建议你动手试试——纸上得来终觉浅。

小技巧:nvidia-smi -q -d COMPUTE也能看到计算单元信息。但代码方式更灵活,可以集成到你的性能分析工具里。

好了,这一章我们聊了GPU计算单元的家族图谱。CUDA核心是通用打工人,Tensor Core是矩阵运算专家,SFU是特殊函数快手。理解它们的特性和适用场景,能帮你写出更高效的CUDA程序。

记住一点:没有最好的计算单元,只有最适合的计算单元。选对了,性能翻倍;选错了,事倍功半。

专注资料整理