例子
在 WSL2-Ubuntu20.04 上安装 ISPC:
sudo snap install ispc
如下是一个例子:
simple.ispc
// 简单数组相加的 ISPC 程序
// 保存为 simple.ispc
// 通过 export 导出函数供 C/C++ 调用
// uniform 关键字表示标量参数
export void simple_add(uniform float a[],
uniform float b[],
uniform float result[],
uniform int size)
{
// 假设每个程序实例处理一个元素
// 使用 foreach 构造并行循环
foreach (i = 0 ... size)
{
result[i] = a[i] + b[i];
}
}
main.cpp
// 保存为 main.cpp
#include <stdio.h>
#include <stdlib.h>
#include "simple_ispc.h"
int main()
{
const int N = 16;
float a[N], b[N], result[N];
// 初始化数组
for (int i = 0; i < N; i++) {
a[i] = i;
b[i] = i * 2;
}
// 调用 ISPC 函数
ispc::simple_add(a, b, result, N);
// 打印结果
for (int i = 0; i < N; i++) {
printf("result[%d] = %f\n", i, result[i]);
}
return 0;
}
编译运行上述程序的步骤:
# 生成头文件和 .o 文件,这里面使用 SIMD 指令实现 (SPMD编程模型)simple_add 函数
ispc simple.ispc -o simple.ispc.o -h simple_ispc.h
# 和 main.cpp 一起链接为可执行文件
g++ main.cpp simple.ispc.o -o simple_program
# 执行可执行文件
./simple_program
输出结果:
result[0] = 0.000000
result[1] = 3.000000
result[2] = 6.000000
result[3] = 9.000000
result[4] = 12.000000
result[5] = 15.000000
result[6] = 18.000000
result[7] = 21.000000
result[8] = 24.000000
result[9] = 27.000000
result[10] = 30.000000
result[11] = 33.000000
result[12] = 36.000000
result[13] = 39.000000
result[14] = 42.000000
result[15] = 45.000000
这个程序展示了 ISPC 最基本的特性:
- 使用 foreach 构造并行循环
- 通过 export 导出函数供 C/C++ 调用
- uniform 关键字表示标量参数
程序会输出两个数组相加的结果。
ISPC 和 SIMD,SPMD 的关系:
ISPC (Intel SPMD Program Compiler) 的名称直接揭示了它与 SPMD 的关系:
- SPMD (Single Program Multiple Data):
- 一种并行编程模型,多个执行实例运行相同的程序但处理不同的数据
- 每个实例有自己的程序计数器和控制流
- ISPC 实现 SPMD:
- ISPC 编译器将你的程序编译为 SPMD 形式
- 在运行时,多个程序实例(称为"gang")并行执行
- 例如,在 AVX2 上,一个"gang"可能包含 8 个实例(对应 256 位/32 位浮点数)
- 编程模型:
- 你写的 ISPC 代码看起来像单线程代码
- 但编译器会将其转换为多个实例并行执行的形式
ISPC 与 SIMD 的关系
- SIMD (Single Instruction Multiple Data):
- 一种硬件并行机制,一条指令同时操作多个数据元素
- 如 x86 的 SSE/AVX 指令集
- ISPC 生成 SIMD 代码:
- ISPC 编译器将 SPMD 程序转换为高效的 SIMD 指令
- 每个 SPMD 实例对应一个 SIMD 通道(lane)
- 例如,foreach循环会被编译为 SIMD 操作
- 抽象层次:
- SIMD 是硬件层面的并行机制
- SPMD 是编程模型层面的抽象
- ISPC 在 SPMD 编程模型和 SIMD 硬件之间架起桥梁
三者的关系总结
ISPC 底层可以有 SIMD,也可以没有 SIMD。但是 ISPC 编译器通常会让每个 program instance 访问尽可能连续大块的内存以提高效率。而这些连续大块内存上的计算往往会使用 SIMD
[SPMD 编程模型] ← ISPC 语言 → [SIMD 硬件执行]
(程序员视角) (编译器) (实际执行)
ISPC 让你用 SPMD 风格 编写代码
ISPC 编译器将这些代码转换为 SIMD 指令
运行时,SPMD 实例 映射到 SIMD 通道 上执行
关键优势:ISPC 让你不必手动编写 SIMD 内在函数(intrinsics),而是用更高层次的 SPMD 抽象编写代码,同时获得接近手写 SIMD 的性能。