Linux GPU/NPU加速器总体架构:CPU、GPU、NPU的本质区别

第1章:CPU、GPU、NPU到底有什么本质区别——执行模型、调度模型和内存模型

后面学习Linux GPU/NPU驱动时,我们会连续遇到context、job、queue、ring、firmware、GPUVM、IOMMU、partition、tile和fence。

如果直接把它们套进CPU调度器的task_struct → runqueue → CPU模型,很容易得到错误结论。例如:把一个GPU Job理解成一个Linux线程,把GPU Scheduler理解成CFS,或者认为CPU与集成GPU共享DDR就不再需要GPU虚拟内存。

本章先建立整个专题的坐标系:

1
2
3
4
5
6
7
硬件执行模型
↓ 决定
软件对象模型
↓ 决定
调度模型、内存模型、同步模型
↓ 最终表现为
Linux内核中的Context / Job / Queue / GPUVM / Fence等对象

0. 源码基线与阅读边界

本文使用截至2026年10月8日的最新Linux主线发布候选版本:

1
2
3
4
repository: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
tag: v7.3-rc6
commit: a90ee4305c4a5df72c11b31dacfdc76e00fcf78a
version: Linux 7.3-rc6

主要源码与文档坐标:

1
2
3
4
5
6
7
8
9
10
11
12
13
drivers/gpu/drm/
drivers/gpu/drm/scheduler/
drivers/accel/
drivers/accel/amdxdna/

include/drm/gpu_scheduler.h
include/drm/drm_gpuvm.h
include/linux/dma-fence.h

Documentation/gpu/
Documentation/accel/
Documentation/accel/amdxdna/
Documentation/driver-api/dma-buf.rst

这一章讲稳定的架构概念,并用主线中的DRM、accel和AMD XDNA作为落点;不会假设所有GPU都采用同一种硬件命名,也不会把某一家NPU实现推广为统一标准。

1.1 为什么要先比较CPU、GPU、NPU

CPU调度主链容易形成直觉:

1
2
3
4
5
6
7
task_struct
↓
sched_entity
↓
runqueue
↓
CPU core

但加速器驱动管理的对象通常更粗:

1
2
3
4
5
6
7
8
9
10
11
Linux Process
↓ open/ioctl/mmap
Device File
↓
Client / Context
↓
Queue / Job / Workload
↓
Firmware或Hardware Queue
↓
GPU Engine / NPU Partition

CPU、GPU、NPU并不是简单的“快慢差别”。硬件为了不同目标做出的取舍,决定了Linux应该在什么粒度管理它们。

1.2 不要先从“算力”理解CPU/GPU/NPU

常见概括是:

1
2
3
CPU:通用计算
GPU:并行计算
NPU:AI计算

对入门有用,但对源码不够。更适合系统软件的表述是:

处理器 典型首要目标 典型手段
CPU 单线程延迟与复杂控制 分支预测、乱序执行、大缓存、推测执行
GPU 大规模数据并行吞吐 SIMT、大量Lane、大量驻留Wave、宽内存带宽
NPU 张量/Dataflow的吞吐与能效 矩阵单元、Tile、显式本地存储、DMA、编译期规划

“典型”非常重要:现代CPU有向量单元,GPU有专用矩阵单元,NPU也可能包含可编程核心,三者边界会交叉。但设计重心仍然不同。

1.3 CPU的核心设计目标

CPU希望尽快推进一条充满依赖、分支、异常和系统调用的指令流:

1
2
3
4
5
6
7
低Latency
强单线程性能
复杂控制流
快速精确异常
通用ISA
完整虚拟内存
快速上下文切换

CPU愿意为此投入大量晶体管实现预测和乱序结构。它追求的不是同时放入最多算术单元,而是让一条通用指令流尽量少停顿。

1.4 CPU的执行模型

从Linux视角看:

1
2
3
4
5
6
Process
└─ Thread
└─ task_struct
└─ CPU Scheduler
└─ CPU Core
└─ Instruction Stream

线程的可恢复执行状态至少包含:

1
2
3
4
5
6
Program Counter
General Registers
Stack Pointer
Scheduling State
Address-space association
Architecture-specific state

调度器保存prev并恢复next,CPU随后直接继续执行next的指令流。

1.5 Process、Thread、task_struct和Core

Linux使用task_struct统一表示可调度任务。用户口中的进程和线程都对应task;区别主要在于它们是否共享mm_struct、文件表、信号处理等资源。

1
2
3
4
5
6
7
Process A
├─ Thread A0 -> task_struct A0
└─ Thread A1 -> task_struct A1
↓
CPU runqueue
↓
CPU Core

CPU调度器的对象是task,而不是整个地址空间。一个多线程进程的不同线程可以同时运行在不同CPU Core上。

1.6 CPU为什么适合复杂控制流

典型高性能CPU包含:

1
2
3
4
5
6
Branch Predictor
Out-of-Order Engine
Reorder Buffer
Speculative Execution
Large Multi-level Cache
Precise Exception Machinery

遇到分支时先预测,遇到独立指令时乱序执行,发生异常时恢复精确架构状态。这些机制昂贵,却能降低单线程可见延迟。

1.7 CPU为什么重度依赖Cache

1
Core → L1 → L2 → LLC → DRAM

DRAM延迟远高于CPU周期。Cache利用时间与空间局部性,把常用数据留在离执行单元更近的层级。CPU一般让硬件自动决定命中、替换和回填,软件只提供布局与预取提示。

因此可以把CPU内存层次概括为:

1
以自动Cache为中心,主要优化单次访问Latency

1.8 CPU调度的本质:时间复用

一个Core不能在同一时刻执行多个普通task:

1
2
时间 ──────────────────────>
Core0: [Task A][Task B][Task C][Task A]...

Linux CPU调度主要解决:

1
2
3
4
谁现在运行?
运行多久?
何时抢占?
在哪个CPU运行?

这是一种以时间复用为核心的调度。

1.9 GPU为什么会出现

假设要处理一百万个像素:

1
pixel[i] = transform(pixel[i]);

若各元素执行近似相同的运算,继续堆叠复杂CPU控制逻辑并不经济。GPU把更多面积用于算术Lane、寄存器和带宽,通过大量并行工作换取总体吞吐。

1.10 GPU的核心设计目标

GPU典型目标:

1
2
3
4
5
Throughput
Massive Parallelism
Latency Hiding
SIMT
High Memory Bandwidth

一句话:

GPU通常不追求让每个逻辑线程最快,而追求单位时间完成尽可能多的工作。

1.11 GPU的执行模型

概念层级:

1
2
3
4
5
6
7
8
9
10
11
12
13
Application
↓ Dispatch / Draw
GPU Compute Kernel / Shader
↓
Grid
↓
Workgroup / Thread Block
↓
Warp / Wave
↓
Lane / Work-item
↓
SM / CU / WGP

这里的GPU Compute Kernel是设备程序,不是Linux Kernel。厂商术语不同,但“粗粒度Dispatch逐层展开为大量硬件执行Lane”是稳定概念。

1.12 Kernel、Grid、Workgroup、Warp、Wave和Lane

层级 含义
Kernel/Shader 在GPU上运行的程序
Grid/Dispatch 一次完整并行工作域
Workgroup/Block 可协作、共享局部资源的一组work-item
Warp/Wave 硬件以相近指令步调执行的一组Lane
Lane/Work-item 最细的逻辑数据元素执行实例

真正需要建立的边界是:

1
2
Linux KMD管理Job/Queue
GPU内部硬件管理Workgroup/Wave/Lane

1.13 GPU Thread为什么不等于Linux Thread

Linux Thread:

1
2
3
4
有task_struct
可被CPU调度器抢占和迁移
拥有内核栈及CPU寄存器上下文
通常关联mm_struct

GPU Thread/Lane:

1
2
3
4
是设备内部的逻辑执行实例
状态位于GPU寄存器文件和硬件上下文中
由GPU硬件/固件按Wave等粒度管理
不对应一个task_struct

若给百万GPU Lane各创建一个task_struct,管理成本会完全不可接受,而且CPU调度器也不了解GPU寄存器、共享内存和SIMT执行掩码。

1.14 SIMT到底解决什么问题

SIMT(Single Instruction, Multiple Threads)让一组逻辑线程以相同指令流处理不同数据:

1
2
3
4
Lane0: data[0] ─┐
Lane1: data[1] ─┤
Lane2: data[2] ─┼─> 一个Warp/Wave推进指令
Lane3: data[3] ─┘

每个Lane仍有自己的寄存器数据与逻辑身份,但控制和取指可以共享。若Lane走不同分支,就会出现branch divergence:硬件通常需要使用执行掩码分批推进不同路径,吞吐下降。

1.15 GPU为什么需要大量硬件并发

GPU访问显存也会等待。它隐藏延迟的重要方法不是只依靠超大Cache,而是保留大量可运行Wave:

1
2
3
Wave A发起内存访问 -> 等待
Scheduler切换到Wave B -> 计算
Wave B等待 -> 运行Wave C

这里的切换主要发生在GPU内部,不是Linux schedule()。大量驻留上下文要求很大的寄存器文件,程序的寄存器/共享内存占用也会反过来限制occupancy。

1.16 GPU调度到底有几层

“GPU Scheduler”至少可能指:

1
2
3
4
5
Application/Runtime:决定何时产生Dispatch
UMD:组织Command Buffer和用户队列
KMD:在不同Client/Context间调度Job或Queue
Firmware:把逻辑队列映射到硬件槽位、管理抢占/恢复
Hardware:选择Workgroup、Warp/Wave在计算单元执行

看到scheduler时第一问必须是:

它调度的对象是什么,运行在哪一层,控制哪种资源?

1.17 GPU Context是什么

GPU Context可理解为某个Client在设备上的一组执行环境:

1
2
3
4
5
6
GPU Address Space或其引用
Command Queues
Priority
Scheduler Entity
Firmware Context
Fault/Reset状态

具体字段由驱动决定。一个Process可以拥有多个Context,用于不同Engine、优先级或隔离域;因此Process != GPU Context。

1.18 GPU Job是什么

Job是KMD能够跟踪、排序、提交并等待完成的一份工作。它可能代表:

1
2
3
4
5
Draw
Compute Dispatch
Copy/DMA
Command Buffer Batch
VM更新工作

Job仍然比GPU Thread高很多层:

1
Job → Command Stream → Dispatch → Workgroup → Wave → Lane

Linux主线DRM调度器用struct drm_sched_job表达公共调度对象,但厂商驱动通常把它嵌入自己的Job结构。

1.19 GPU Queue是什么

1
2
3
4
5
Context
└─ Queue
├─ Job0
├─ Job1
└─ Job2

Queue至少要区分三个层级:

队列 维护者 作用
Software Queue UMD/KMD 保存尚未送入设备的工作
Firmware Queue/Ring 驱动与固件 主机和固件交换命令
Hardware Queue 设备 硬件真正消费命令的槽位/队列

现代硬件还可能允许User Queue直接写共享Ring,再由固件完成验证和映射。

1.20 GPU Engine、SM和CU是什么

GPU可能包含多类Engine:

1
2
3
4
Graphics Engine
Compute Engine
Copy/DMA Engine
Video Decode/Encode

SM、CU或WGP则是计算Engine内部承载Wave/Lane的计算资源。KMD通常选择Job送往哪个Engine或硬件Ring,不会为每个Warp指定某个SM。

1.21 GPU Memory Model

CPU和GPU都需要地址翻译,但对象可能不同:

1
2
3
CPU VA → CPU页表 → PA → DRAM

GPU VA → GPU页表/MMU → VRAM或System RAM

Linux主线DRM包含GEM/TTM、GPUVM、DRM Buddy、Sync Object等公共基础设施。它们分别解决Buffer对象、放置/迁移、GPU虚拟地址范围和同步等问题。

1.22 GPU VA与CPU VA的区别

同一个Buffer可能同时具有:

1
2
3
4
CPU VA:CPU load/store使用
GPU VA:Command Buffer中的设备指针使用
DMA/IOVA:设备互连或IOMMU侧看到的地址
Physical backing:真实RAM/VRAM页

这些地址不能随意互换。传统模型中CPU和GPU使用独立页表;SVA/SVM、HMM等机制可以增强地址空间协同,但也不意味着所有硬件天然共享完全相同的翻译和一致性语义。

1.23 VRAM与System RAM

离散GPU常见:

1
2
CPU ─ System RAM
GPU ─ VRAM

集成GPU常见:

1
CPU + GPU → Shared DRAM

共享物理DRAM仍要处理:

1
2
3
4
5
6
虚拟地址与页表
访问权限和进程隔离
缓存一致性
Buffer生命周期
设备可见映射
同步和所有权转换

因此“UMA”不等于“没有GPU内存管理”。

1.24 GPU为什么也需要Page Table和MMU

如果用户直接把物理地址写入命令:

1
2
3
4
5
进程隔离困难
Buffer无法安全迁移
地址重定位困难
稀疏映射困难
错误命令可能访问他人内存

GPU MMU和GPUVA提供隔离、重定位、稀疏映射与故障报告。主线DRM GPUVM公共代码抽象gpu_vm、gpu_vma和对象到VM的关联,但页表格式和更新机制仍由驱动实现。

1.25 NPU为什么会出现

神经网络中大量工作由规律的矩阵乘、卷积、激活和张量变换构成。此类工作常受数据搬运和乘加能耗支配。针对访问模式、数值格式和数据流定制硬件,能够获得更好的Performance/Watt。

NPU不是一个严格统一的微架构名称,而是一类面向AI/张量工作负载的加速器。

1.26 NPU和GPU到底有什么不同

典型对比:

1
2
GPU:高度可编程SIMT核心、寄存器密集、Cache/Shared Memory
NPU:矩阵/向量引擎、Dataflow、显式Scratchpad、DMA、空间阵列

GPU也可以有Tensor Core,NPU也可以有VLIW/向量处理器,因此差异是“设计中心”而非绝对边界。源码分析时应以具体设备文档为准。

1.27 NPU的执行模型

1
2
3
4
5
6
7
8
9
10
11
AI Model
↓
Graph Compiler
↓ 融合/量化/Tiling/内存规划/Codegen
NPU Program或Binary
↓
Workload / Command
↓
NPU Context
↓
Partition / Tile / Matrix Engine

NPU通常不暴露“每个神经元一个Linux线程”。KMD管理的是已编译程序、Buffer、Workload和设备资源绑定。

1.28 Graph、Workload、Program和Command

1
2
3
4
Graph:算子及其依赖关系
Program/Binary:编译器为设备生成的指令和配置
Workload:一次可提交执行的工作及资源需求
Command:驱动/固件能够消费的具体控制项

一个Workload可能携带输入输出Buffer、指令Buffer、Scratchpad需求、DMA描述符、Tile数量和依赖Fence。不同驱动命名会不同,必须回到UAPI和具体结构确认边界。

1.29 Tile、Compute Engine和Matrix Engine

NPU常把计算与本地存储组织成二维或分组Tile:

1
2
3
4
5
+--------+--------+--------+
| Tile 0 | Tile 1 | Tile 2 |
+--------+--------+--------+
| Tile 3 | Tile 4 | Tile 5 |
+--------+--------+--------+

Tile可能包含向量/VLIW核心、本地Program/Data Memory、DMA端口和片上互连。Matrix Engine则更偏向执行MAC/矩阵指令。两者不是所有NPU都采用的统一术语。

1.30 Systolic Array的基本思想

Systolic Array让数据在处理单元之间有规律地流动并复用:

1
2
3
Data → PE → PE → PE
↓ ↓ ↓
PE → PE → PE

目标是减少反复访问外部DRAM,让权重、激活或部分和在阵列内部被多次使用。算术峰值只有在数据持续供给且布局匹配时才有意义。

1.31 Scratchpad为什么重要

Cache由硬件自动决定替换,Scratchpad/Local SRAM通常由编译器、Runtime或固件显式规划:

1
DDR → DMA → Scratchpad → Compute → DMA → DDR

神经网络访问模式较可预测,显式管理能换取更确定的延迟、更高复用率和更低能耗;代价是编译器和Runtime必须正确完成Tiling与容量规划。

1.32 NPU为什么大量依赖DMA

在NPU上,数据搬运往往与计算同等重要:

1
2
3
4
5
6
7
Host DDR
↓ DMA-in
Local Memory
↓
Compute
↓ DMA-out
Host DDR

性能瓶颈可能来自DDR带宽、DMA描述符、NoC拥塞、双缓冲失效或Scratchpad复用不足,而不是MAC单元数量。只看TOPS无法解释真实应用性能。

1.33 NPU的Spatial Scheduling

空间调度把不同物理区域同时分配给不同Workload:

1
2
Columns 0~3 → Workload A
Columns 4~7 → Workload B

调度器不仅决定“谁先运行”,还决定“占多少列、哪些Tile、本地存储与DMA资源”。资源分配与调度策略因此紧密耦合。

Linux主线AMD XDNA文档给出了现实例子:二维Compute/Memory Tile Array可在列边界形成隔离Partition,并绑定Workload Context。

1.34 NPU的Temporal Scheduling

时间调度让多个Workload轮流使用同一Partition:

1
2
Partition 0时间轴:
[Workload A][Workload B][Workload A]...

AMD XDNA同时支持空间和时间共享。驱动中的Resource Solver决定阵列重新分区和Workload映射,固件执行Context到Column的绑定。这是具体实现示例,不应推广为所有NPU的强制架构。

1.35 CPU、GPU、NPU调度模型对比

1
2
3
4
5
6
7
8
9
10
11
12
13
CPU:
Task → Runqueue → CPU Scheduler → Core

GPU KMD:
Context → Entity/Queue → Job → Scheduler → HW/FW Queue → Engine

GPU Hardware:
Dispatch → Workgroup → Wave/Warp → SM/CU

NPU:
Context → Workload + Resource Request
→ Scheduler/Resource Solver
→ Queue/Partition → Tile/Engine

CPU主要分配CPU时间;GPU KMD主要在Client间安排Job/Queue到Engine;NPU还可能同时分配空间资源。

1.36 CPU、GPU、NPU内存模型对比

维度 CPU GPU NPU
主要地址 CPU VA GPUVA,可能另有CPU VA Device VA/IOVA
翻译 CPU MMU/页表 GPU MMU/GPU页表 IOMMU和/或设备MMU
外部存储 System RAM VRAM/System RAM DDR/HBM等
本地层次 多级Cache Register、Cache、Shared/Local Memory Scratchpad/Local SRAM
数据移动 Load/Store + Cache Load/Store、Copy Engine 显式DMA通常很关键
管理侧重点 缺页、回收、NUMA Buffer放置、映射、迁移、共享 编译期规划、DMA、Tile本地容量

IOVA是IOMMU面向设备的I/O虚拟地址;GPUVA是GPU程序引用的虚拟地址。某些系统两者可能形成连续翻译链,不能只凭数值相同就认为它们是同一层地址。

1.37 CPU、GPU、NPU同步模型对比

CPU常见:

1
mutex / spinlock / rwsem / completion

异步设备常见:

1
Fence / Timeline / Semaphore / Event / Barrier

CPU提交工作后会继续运行,设备稍后完成,所以需要一个可跨时间、跨驱动表达“工作何时完成”的对象:

1
2
Job A执行 → Fence A signal
Job B依赖Fence A → A完成后才可运行

Linux主线的struct dma_fence包含context、seqno、回调链和signaled状态。它更接近异步活动完成点,不是简单的“GPU版mutex”。

1.38 Linux内核视角下三者如何统一

Linux不会把每个GPU Lane或NPU PE变成task,而是在系统边界管理更粗对象:

1
2
3
4
5
6
7
8
9
10
Linux Process
↓ open()
Device FD / drm_file
↓ ioctl / mmap
Client / Context
├─ Buffer / Address Space
├─ Queue / Job / Workload
└─ Fence / Sync Object
↓
KMD → Firmware → Hardware

CPU task仍负责调用Runtime、提交命令、等待结果和处理异常;设备内部并行由加速器自己的执行机制负责。

1.39 DRM/accel为什么会成为公共基础设施

不同加速器共同面对:

1
2
3
4
5
6
7
8
9
设备文件和UAPI
Client/Context生命周期
Buffer对象和共享
地址空间
Command Submission
Job调度
Fence同步
故障与Reset
多进程隔离

Linux accel子系统明确复用DRM代码:accel设备是一类DRM设备,但使用独立设备节点/主设备号,避免图形用户栈误把纯计算加速器当作显示GPU。驱动代码放在drivers/accel/。

这说明DRM不只等于“显示”:它已经积累了大量适用于异步加速器的内存、调度和同步机制。

1.40 从Process到Hardware的三条完整路径

1.40.1 CPU路径

1
2
3
4
5
6
Application Thread
→ task_struct
→ CPU Scheduler / runqueue
→ CPU Core
→ CPU MMU / Cache
→ DRAM

1.40.2 GPU路径

1
2
3
4
5
6
7
8
9
10
11
12
13
Application
→ Graphics/Compute API
→ Runtime / UMD
→ ioctl/mmap
→ GPU KMD
→ Client / Context / GPUVM
→ Command Buffer / Job / SW Queue
→ DRM或驱动Scheduler
→ Firmware/HW Queue
→ Engine
→ Workgroup → Wave/Warp → Lane

完成:IRQ/Firmware Event → dma_fence signal → Userspace

1.40.3 NPU路径

1
2
3
4
5
6
7
8
9
10
11
12
13
AI Framework
→ Graph Compiler / Runtime
→ UMD
→ ioctl/mmap
→ NPU KMD
→ Context / Buffers
→ Workload / Program
→ Resource Solver / Scheduler
→ Firmware Queue / Partition
→ Tile / Matrix Engine
→ DMA + Scratchpad + Compute

完成:IRQ/Firmware Event → Fence/Event → Userspace

1.41 本章实验

1.41.1 查看主线源码布局

1
2
3
4
5
ls drivers/gpu/drm/
ls drivers/gpu/drm/scheduler/
ls drivers/accel/
ls Documentation/gpu/
ls Documentation/accel/

预测:DRM目录不仅有显示代码,也有scheduler、TTM/GEM、GPUVM和同步相关公共代码;accel目录包含多种计算加速器驱动。

1.41.2 建立对象坐标表

为每个对象回答五个问题:

1
2
3
4
5
谁创建?
谁拥有?
谁调度?
在哪里执行?
何时销毁?

对象至少包括:task_struct、GPU Context、drm_sched_entity、drm_sched_job、GPUVM、dma_fence和NPU Workload。

1.41.3 只观察DRM Scheduler骨架

1
2
rg "struct drm_sched_(entity|job|rq|fence)" include/drm/gpu_scheduler.h
rg "drm_sched_job_queue|drm_sched_job_run" drivers/gpu/drm/scheduler

先画:

1
Job Queue → Entity → Run Queue → drm_gpu_scheduler → Driver run_job()

不要在第一章深入锁和超时恢复。

1.41.4 观察AMD XDNA

1
2
rg "Resource Solver|spatial|temporal|partition" \
Documentation/accel/amdxdna drivers/accel/amdxdna

预测:文档会把二维阵列、Column、Partition、Workload Context、固件和DMA联系起来,验证NPU调度包含空间资源选择。

1.41.5 观察运行中的设备

1
2
3
lspci -nnk | grep -EA3 'VGA|3D|Display|Processing accelerators'
ls -l /dev/dri/ 2>/dev/null
ls -l /dev/accel/ 2>/dev/null

没有/dev/accel不代表内核没有accel框架,可能只是机器没有对应硬件、驱动未启用或尚未绑定。

1.42 性能与工程意义

看到GPU利用率低,问题未必是GPU算力不足:

1
2
3
4
5
6
7
8
CPU生成命令慢
UMD编译/状态处理慢
Submission批次过小
Queue依赖等待
KMD/Firmware调度延迟
GPU缺页或Buffer迁移
内存带宽不足
Wave occupancy不足

同样,NPU标称TOPS高也不保证应用快:

1
2
3
4
5
6
7
Graph切分或Fallback
量化/布局不匹配
DMA与DDR瓶颈
Scratchpad复用不足
Tile分配失败
同步气泡
固件调度开销

嵌入式Camera → ISP → GPU → NPU → Encoder流水线中,dma-buf共享、IOMMU映射、Fence依赖和DDR带宽往往比单个单元峰值更重要。

1.43 常见误区

误区1:GPU就是很多CPU Core

错误。GPU的执行粒度、控制流处理、调度层次和内存隐藏策略都不同。

误区2:GPU Thread等于Linux Thread

错误。GPU Lane没有task_struct,不由Linux CPU调度器逐个调度。

误区3:Linux GPU Scheduler调度Warp

通常错误。KMD更常调度Job、Entity或Queue;Warp/Wave由硬件层管理。

误区4:NPU就是没有图形功能的GPU

错误。典型NPU更强调Tensor/Dataflow、Scratchpad、DMA和空间资源。

误区5:GPU/NPU只有一个Scheduler

错误。Runtime、KMD、Firmware和Hardware都可能各有调度决策。

误区6:CPU和GPU共享DDR就不需要GPU内存管理

错误。仍需GPUVA、权限、页表/映射、缓存一致性、生命周期和同步。

误区7:Fence就是GPU版mutex

不准确。Fence表达异步活动的完成和依赖;mutex主要保护CPU临界区互斥。

误区8:NPU性能只看TOPS

错误。编译、Tiling、DMA、带宽、本地存储复用和资源分区都可能限制性能。

1.44 博客总结

CPU、GPU和NPU的根本差异来自优化目标与硬件执行模型:

1
2
3
CPU:复杂控制流与低单线程延迟
GPU:SIMT大规模并行与总体吞吐
NPU:张量/Dataflow的吞吐和能效

它们进一步塑造Linux软件对象:

1
2
3
CPU:Thread / task_struct / runqueue
GPU:Context / Job / Queue / Engine / GPUVM / Fence
NPU:Context / Workload / Partition / Tile / DMA / Event

本章最重要的判断方法是:

1
2
3
4
先问调度对象是谁
再问逻辑运行在哪一层
再问资源Owner是谁
最后区分Policy和Mechanism

主线Linux 7.3-rc6中的DRM Scheduler、GPUVM、dma_fence、accel Core和AMD XDNA说明:Linux不会把设备内部每个并行单元变成CPU task,而是在KMD边界管理Context、Buffer、Address Space、Job、Queue和完成依赖。

官方源码与文档入口

1.45 学完检查题

  1. 为什么CPU、GPU、NPU不能只按“算力大小”比较?
  2. Linux Thread与GPU Lane的状态、调度者分别是谁?
  3. SIMT与SIMD有什么联系?为什么分支分歧会降低效率?
  4. GPU通过什么方式隐藏内存访问延迟?
  5. Runtime、KMD、Firmware和Hardware Scheduler分别可能调度什么?
  6. GPU Context为什么不等于Linux Process?
  7. Job、Command Buffer、Workgroup和Wave是什么层次关系?
  8. Software Queue、Firmware Queue和Hardware Queue如何区分?
  9. Engine与SM/CU为什么不是同一层对象?
  10. 同一个Buffer为什么可能同时有CPU VA、GPUVA和IOVA?
  11. 集成GPU共享DDR后,哪些内存管理问题仍然存在?
  12. GPU MMU和GPUVM分别解决什么层面的问题?
  13. NPU的Graph、Program、Workload和Command如何区分?
  14. Scratchpad与CPU Cache的主要管理方式有何不同?
  15. 为什么NPU分析必须把DMA和计算放在一起?
  16. Spatial Scheduling与Temporal Scheduling分别分配什么?
  17. AMD XDNA的Resource Solver和Firmware各承担什么角色?
  18. dma_fence为什么适合异步设备工作?
  19. accel为何复用DRM基础设施,却使用独立设备类别?
  20. Camera → GPU → NPU流水线为什么可能受同步和带宽限制,而不是算力限制?

下一章将沿软件栈继续向下:

1
2
3
4
5
6
7
8
Application
→ Framework / API
→ Runtime
→ UMD
→ ioctl / mmap
→ KMD
→ Firmware
→ Hardware

重点回答一次GPU/NPU调用为什么必须跨越这么多层,以及每一层的责任边界。


Linux GPU/NPU加速器总体架构:CPU、GPU、NPU的本质区别
https://cj0510.github.io/2026/10/08/Linux Kernel/GPU/Linux-GPU-NPU加速器总体架构-第1章-CPU-GPU-NPU本质区别/
作者
CJ1018
发布于
2026年10月8日
许可协议
CC BY-NC-SA 4.0