Skip to content

CPU和GPU加速计算

简单讲述一下 SIMD 和 SIMT

SIMD

Single Instruction Multiple Data,一个指令可以对应操作多个数据。

因为我们发现,很多计算可以通过并行运算来提升速度 —— 比如计算两个向量相加,一方面可以按位来逐个相加,这很慢。另一种实现方式就是把若干个位打包一起并行运算,速度会快很多。这样,一个简单的加法指令,就可以对应操作 “ 多个数据 ”。

宽寄存器 + 单指令

从底层上说,其实有向量寄存器用于处理批数据,然后在执行指令的时候就可以直接进行快速的操作。

C
__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

C++
struct Vec3
{
	float x, y, z;
};

Vec3 positions[N];

这是AoS的一种存储方法(Array of Structures),逻辑上不错,只是假设我们只需要其中的某个字段的时候,一整个结构体对象都会被读取到缓存中去,其他字段没有利用到,并且占用了空间,非常的低效。

此时另一种优化方式 ——

C
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]]

总结

Released under the MIT License.