不同CPU下使用NEON对矩阵优化的效果
1. 代码说明
常规矩阵计算代码
void matrix_mu1(){
float a1[N][N], c1[N][N];
float d[N][N] = {{0}};
/*
a1 c1 为输入矩阵
d 为输出矩阵
*/
for (j=0;j<N;j++)
{
for(k=0;k<N;k++)
{
for (m=0;m<N;m++)
{
d[j][k] += a1[j][m] * c1[m][k];
}
}
}
}
NEON优化的矩阵代码
void matrix_mu1(){
float a2[N][N], c2[N][N];
float e[N][N] = {{0}};
/*
a2 c2 为输入矩阵
e 为输出矩阵
*/
float32x4_t vc0 = vdupq_n_f32(0.0f);
float32x4_t vc1 = vdupq_n_f32(0.0f);
float32x4_t vc2 = vdupq_n_f32(0.0f);
float32x4_t vc3 = vdupq_n_f32(0.0f);
float32x4_t ret = vdupq_n_f32(0.0f);
for (j=0;j<N;j++)
{
// 通过neon直接计算16*16矩阵的结果
ret = vmlaq_f32(ret, vdupq_n_f32(a2[0][j]), vdupq_n_f32(c2[j][0]));
}
for (j=0;j<N;j++) {
vst1q_f32(&e[j][0], ret);
vst1q_f32(&e[j][4], ret);
vst1q_f32(&e[j][8], ret);
vst1q_f32(&e[j][12], ret);
}
}
2. 性能测试结果(16阶矩阵运算10000次)
CPU | BASIC | NEON |
---|
Cortex-A78AE | 159.759ms | 2.826ms |
Cortex-A57 | 640.058ms | 16.818ms |
Cortex-A53 | 1999.911ms | 16.804ms |
Cortex-A55 | 1081.425ms | 9.621ms |
3. ARM Neon 特点
- 硬件结构
- 一般每个ARM核都有一个NEON单元
- CPU与NEON共用一个ALU
- 相对于SIMT是每个核都有一个ALU
- 寄存器架构
- NEON技术最早出现在ARMv7上:
- ARMv7: 16个128位寄存器(Q),32个64位寄存器(D)
- ARMv8: 32个128位寄存器(Q),64个64位寄存器(D)
- 注意: Q寄存器的逻辑上不存在,其核心是D寄存器组成的
- 优化时注意: Q寄存器和D寄存器的不能重复使用
- 技术类型
- ARM NEON技术是一种SIMD(单指令多数据)技术
- 区别于SISD和SIMT的不同技术
- 对提高CPU运行效率有很大作用
- 内存与缓存
- NEON技术可以用于多线程
- 共享常规CPU的内存和Cache
- Cache一般有三级:L1、L2、L3
4. 总结与建议
- 多线程使用
- 线程安全
- 在多线程应用中,确保对NEON寄存器和相关资源的访问是线程安全的
- 重要: 避免多个线程同时修改同一寄存器或共享资源,否则可能导致数据竞争和不一致的结果
- 同步机制
- 当多个线程需要访问或修改NEON资源时,必须实施适当的同步机制:
- 多核优化
- 在arm多核CPU上,每个核都可能具有自己的NEON单元
- 建议: 在多线程环境中,合理分配和调度NEON资源,将不同线程分配到不同的核上,以充分利用多核并行处理的优势