CPU和GPU加速计算
简单讲述一下 SIMD 和 SIMT
SIMD
Single Instruction Multiple Data,一个指令可以对应操作多个数据。
因为我们发现,很多计算可以通过并行运算来提升速度 —— 比如计算两个向量相加,一方面可以按位来逐个相加,这很慢。另一种实现方式就是把若干个位打包一起并行运算,速度会快很多。这样,一个简单的加法指令,就可以对应操作 “ 多个数据 ”。
宽寄存器 + 单指令
从底层上说,其实有向量寄存器用于处理批数据,然后在执行指令的时候就可以直接进行快速的操作。
__m128 a = _mm_load_ps(ptr); // 加载 4 个 float
__m128 b = _mm_add_ps(a, a); // 4 个 float 同时做加法
_mm_store_ps(ptr, b);所以如果数据是比较整齐的排布,就会减少 Cache miss 的情况,从而更好的提升速度,运用SIMD
当然,底层上对于数据理解上的变化也有助于优化 ——
按照普通的思路来说,假设我们需要存储若干三维向量(比如在游戏中代表model position
struct Vec3
{
float x, y, z;
};
Vec3 positions[N];这是AoS的一种存储方法(Array of Structures),逻辑上不错,只是假设我们只需要其中的某个字段的时候,一整个结构体对象都会被读取到缓存中去,其他字段没有利用到,并且占用了空间,非常的低效。
此时另一种优化方式 ——
struct Positions
{
float x[N];
float y[N];
float z[N];
};这就是另外一种存储方式 —— SoA,即Structure of Array,这样在上述情况的时候就会大幅提高效率。
不过上述显然依旧很大程度上依赖数据整齐,所以如果遇到分支等结构就难以优化——可以通过掩码来实现遮罩掉不需要的结果,但是效率依旧会大打折扣。
SIMT
Single Instruction Multi Thread,一个指令通过多个线程并行运算
宽线程组 + 单指令
Nvidia 家的 Warp 或者 AMD 家的 Wavefront,其中的运行单位就是线程,通过线程组的并行运算来提升计算速度。
比如 x += 1 可能就会展开成 32 个线程组同时开始计算
此处如果遇到复杂分支,也是十分棘手的问题 —— 一般来说会让if分支运行,else分支线程休眠;等执行完之后再反过来运行。
提供斯坦福课程的图片
![[Assets/Pasted image 20260311235732.png]]