WEBKT

Adreno GPU架构深潜:A6xx与A7xx在Threadgroup Memory上的本质区别与演进

23 0 0 0

在移动端 GPU 架构中,Threadgroup Memory(在 Vulkan 中称为 Shared Memory,在 OpenCL 中称为 Local Memory,在硬件层面通常对应 Local Data Share, LDS)是决定计算着色器(Compute Shader)和现代渲染管线(如 Mesh Shader)性能的关键基础设施。

高通 Adreno 系列 GPU 在经历 A6xx(如 Adreno 630/640/650/660)向 A7xx(如 Adreno 730/740/750)的跨代演进中,其 Threadgroup Memory 硬件架构、数据通路以及与寄存器文件的交互机制发生了本质性的变革。本文将深度剖析这两代 GPU 在 Threadgroup Memory 设计上的核心底层区别。


一、 物理拓扑与 SP 内部布局的重构

要理解 Threadgroup Memory 的变化,首先需要理解 Shader Processor (SP) 物理布局的演进。

1. A6xx 的 “SP-Centric” 绑定设计

在 A6xx 架构中,每个 SP 内部封装了独立的、物理上紧耦合的 LDS 块(通常为 64KB)。

  • 物理位置:LDS 紧邻 SP 的向量寄存器文件(VRF)和算术逻辑单元(ALU)。
  • 调度局限:这种设计属于典型的“静态绑定”。一个 Threadgroup 只能被调度到单个 SP 上执行。如果一个 Compute Kernel 申请了 32KB 的 Threadgroup Memory,即使该 SP 的计算资源未满载,由于物理 LDS 容量的限制,其活动 Wavefront(在 Adreno 中称为 Fiber Group)的数量(Active Warps/Waves)也会受到严格限制,从而导致延迟隐藏能力下降。
[A6xx SP Layout]
+------------------------------------------+
|  SP (Shader Processor)                   |
|  +----------------+  +----------------+  |
|  |  ALU Pipelines |  | Vector Regs    |  |
|  +--------+-------+  +--------+-------+  |
|           |                   |          |
|  +--------+-------------------+--------+  |
|  | Local Data Share (LDS) - 64KB       |  |
|  +-------------------------------------+  |
+------------------------------------------+

2. A7xx 的 “Clustered / Pooled” 弹性设计

A7xx 引入了更为现代的处理器集群(Processor Cluster)概念,对 SP 内部的存储资源进行了“池化”与“解耦”重构。

  • 物理位置:LDS 不再是单片紧耦合在单个 SP 微架构内部,而是作为高速、低延迟、多通道的共享 SRAM 阵列,放置在 SP 簇的中央。
  • 容量提升:A7xx 的旗舰型号(如 Adreno 740/750)将每个计算集群可访问的 Threadgroup Memory 物理容量提升至 128KB,并且支持动态、高粒度的分区。
  • 弹性调度:多个 SP 子单元可以更灵活地共享和映射同一块物理 Threadgroup Memory。这种设计允许编译器和硬件调度器更自由地平衡寄存器压力(Register Pressure)与 Threadgroup Memory 占用,显著提升了 GPU 的占用率(Occupancy)。

二、 Bank 架构与冲突解决机制的升级

Threadgroup Memory 通常被划分为多个物理 Bank,以便并发访问。一旦多个 Fiber 访问同一个 Bank 的不同地址,就会发生 Bank Conflict(冲突),导致访问被串行化,严重拖慢执行效率。

维度 Adreno A6xx Adreno A7xx
Bank 数量 通常为 32 个 Bank 升级为 32 或 64 个高带宽 Bank
Bank 宽度 32-bit (4 Bytes / Dword) 32-bit (优化了 16-bit FP16 动态合并)
交叉开关 (Crossbar) 128-bit 宽度总线,多周期分发 256-bit 或宽总线,单周期多路路由
冲突延迟处罚 高(序列化开销大,缺乏片上快速旁路) 低(引入了更先进的冲突检测与广播合并网络)

1. A6xx 的 Bank 访问特征

在 A6xx 上,当 Fiber Group(通常以 Wave64 或 Wave32 执行)发起 Threadgroup Memory 读写时:

  • 如果 32 个 Fiber 恰好映射到 32 个不同的 Bank,可以达到单周期吞吐。
  • 一旦发生 Bank Conflict,A6xx 的内部纠错和重试机制(Arbitrator)需要多个时钟周期来串行解决。
  • FP16 劣势:在处理半精度(FP16/half)数据时,A6xx 的 Bank 寻址对齐相对生硬,无法高效地将两个 16-bit 的相邻访问合并(Coalesce)为单个 32-bit Bank 端口的并发写入,造成不必要的冲突和带宽浪费。

2. A7xx 的硬件级优化

A7xx 重新设计了 Crossbar(交叉开关)和地址译码器:

  • 动态广播(Broadcast)与多播(Multicast):如果一个 Wave 内的多个 Fiber 同时读取同一个 Bank 的同一个地址(即常量广播),A7xx 可以在硬件级实现单周期多播分发,不占用额外的 Bank 带宽。
  • FP16 紧凑合并:A7xx 能够完美识别连续的 16-bit 线程访问,并将其合并成一个 Dword (32-bit) 的 Bank 访问通道。这使得在移动端广泛使用的端侧 AI、图像处理(Heavy FP16 计算)在访问 Threadgroup Memory 时,带宽利用率直接翻倍。

三、 数据通路(Datapath)与寄存器交互的革命

在 GPU 执行计算任务时,数据通常遵循以下路径:
Global Memory (L2/DDR) -> Register File (VRF) -> Threadgroup Memory (LDS) -> Register File (VRF)

这两代架构在数据通道的连通性和指令阻塞设计上有着本质区别。

[A6xx Datapath]
Global Memory (L2) ---> [VRF (Registers)] <---> [ALU]
                             ^
                             | (Requires ALU instruction for moving)
                             v
                        [LDS Memory]

[A7xx Datapath]
Global Memory (L2) -+-> [VRF (Registers)] <---> [ALU]
                    |        ^
                    |        | (Direct High-Speed Bypass)
                    |        v
                    +-> [LDS Memory] (Supports Direct Async Copy)

1. A6xx:ALU 参与的显式搬运

在 A6xx 架构中,将数据从 Threadgroup Memory 加载到寄存器(或反之)需要占用 SP 的部分寄存器读写端口,并且在编译器层面,这类 ldlg (Load Local Geometry/Group) 和 stlg (Store Local Geometry/Group) 指令容易与普通的 ALU 向量计算指令产生冲突,导致流水线气泡。

  • 同步机制:编译器必须插入显式的等待标记(如 sys_wait 或特定的延迟 Token),以确保数据已经写入 LDS,随后才能被其他 Fiber 安全读取。这种纯软件/编译器管理的依赖性极易因编译器估计不足而造成硬件停顿。

2. A7xx:硬件异步拷贝与旁路(Bypass)

A7xx 引入了类似于现代桌面级 GPU(如 NVIDIA Ampere 之后的 LDGSTS)的异步拷贝机制

  • 直接通路(Direct Routing):支持从 L2 Cache / Global Memory 直接将数据加载到 Threadgroup Memory,而无需中途占用宝贵的向量寄存器(VRF)。这不仅极大释放了寄存器压力,还规避了寄存器读写端口的抢占。
  • 硬化屏障(Hardware Barrier / Sync):A7xx 在硬件层面集成了更高效的屏障控制器(Barrier Controller)。在 Compute Shader 中调用 GroupMemoryBarrier() 时,硬件能够更灵敏、以更低的时钟周期开销挂起和唤醒 Fiber Group,不再完全依赖编译器插入海量的空操作指令(NOPs)来对齐时钟。

四、 原子操作(Atomic Operations)的硬件下放

在并行计算中,对 Threadgroup Memory 进行原子操作(如 atomicAdd)是构建直方图、链表、无锁队列等算法的核心。

  • A6xx 的软实现
    A6xx 的 LDS 内部缺乏强大的逻辑算术单元。当 Fiber 执行 atomicAdd 时,硬件必须将 LDS Bank 内的原始数据读取出来,送回 SP 内部的 ALU 进行加法计算,然后再写回 LDS。这构成了一个长延迟的闭环,并且在多线程高并发冲突时,锁总线时间极长,会导致严重的管线阻塞。

  • A7xx 的硬实现(LDS-Side Atomics)
    A7xx 将原子操作逻辑单元(Atomic ALUs)直接集成到了 Threadgroup Memory 控制器附近。这意味着,当 Fiber 发起原子加、原子最大值等指令时,指令直接发送给 LDS,由 LDS 内部的专用硬件在 Bank 层面就地完成计算并写回。

    • 吞吐量提升:整个操作对 SP ALU 来说是“发射后不管”(Fire-and-Forget)的异步行为。这让 A7xx 的本地原子操作吞吐量相比 A6xx 提升了数倍,极大地优化了粒子系统、物理模拟等需要频繁同步的计算负载。

五、 面向开发者的底层优化启示

针对 A6xx 与 A7xx 在 Threadgroup Memory 架构上的上述本质改变,开发者在进行 Vulkan / OpenCL / Unity HLSL 级底层优化时,应当调整其优化策略:

  1. Threadgroup 尺寸选择

    • 在 A6xx 上:应谨慎使用过大的 Threadgroup 尺寸。如果单个 Threadgroup 的 Shared Memory 占用超过 16KB,应尽量重构算法,否则会导致 Occupancy 急剧下降。
    • 在 A7xx 上:可以更大胆地利用大容量(如 32KB/64KB)的 Threadgroup Memory,并配合 Wave32 模式执行,利用 A7xx 强大的物理池化和高 Occupancy 调度能力掩盖延迟。
  2. 数据类型对齐与合并

    • 在 A7xx 上,强烈建议将 Shared Memory 中的数据结构打包为 16-bit(如 halfuint16_t。A7xx 的硬件 Bank 合并机制能够将相邻 Fiber 的 16-bit 读写无缝拼装,而不会像 A6xx 那样产生严重的 Bank 冲突。
  3. 利用异步屏障

    • 编写 Compute Shader 时,尽量将 Threadgroup 数据的读取(Load)与实际使用(Use)隔开足够长的独立 ALU 指令区间。在 A7xx 上,硬件会自动利用这段区间进行后台异步拷贝,从而实现完美的指令流水线重叠(Pipelining)。

总结

Adreno A6xx 的 Threadgroup Memory 属于一种经典的、紧耦合但相对静态的移动端硬件设计;而 A7xx 则彻底打破了这一温床,转向了池化、宽总线、异步化、具有就地原子计算能力的现代化计算架构。这一演进不仅为移动端光线追踪(Ray Tracing)中的 BVH 遍历加速提供了强力支撑,也让移动端运行复杂的现代 GPU Driven 渲染管线变得更加高效。

ArchDiver Adreno GPUGPU架构计算着色器

评论点评