JincResize 代码重构(2)

指令集优化

Generation

(更多内容可查看使用 AVX 系列指令集进行向量化,也可看一下这篇很欢乐的文章 GCC 神坑:-march=native

对于 GCC 编译器,在编译命令中加入-march=native选项,可调用本地的库,使用 AVX 指令集优化。

Functions

(Doc 在这里,直接搜索想查的函数即可)

(另外也可看一下Intel AVX を使用して SIMD 演算を試してみる - その2 -,但函数参数不如上面的 Doc 详细)

_mm_malloc(size_t size, size_t align):对齐的问题

_mm256_load_ps:float 类型输入

_mm256_load_pd:double 类型输入

__m256d _mm256_mul_pd(__m256d, __m256d):256 位双精度乘法

Type

(来自インテル® アドバンスト・ベクトル・エクステンション (インテル® AVX) 組込み関数の詳細

__m256:容纳 8 个 32 位单精度浮点数值

__m256d:容纳 4 个 64 位双精度浮点数值

实际代码

这部分代码来自 luglio,我只是做了一点适配,因为我现在还没有把 JincResize 的中间数据从 double 改为 float。

对齐的问题
1
double* lut = (double *)_mm_malloc(sizeof(double) * d->sample, 64);

_mm_malloc相比一般的malloc,增加了一个用于数据对齐的参数。具体在这里(数据对齐有助于实现向量化)有讲。

虽然我现在还不能完全理解这个概念,但经过测试,对于JincResize现有的代码,把上面的64写成32,和没有 AVX 优化的速度几乎一样。

数据类型
1
2
__mm256_store_ps(lut + j * 8, rl);  // float
__mm256_store_pd(lut + j * 4, rl); // double

看一下两个函数的声明

1
2
void _mm256_store_ps (float * mem_addr, __m256 a)
void _mm256_store_pd (double * mem_addr, __m256d a)

注意到第二个参数类型分别是__m256__m256d,所以有了上述区别。

代码细节的整理

(2020.3.2 完成 2020.3.8 补记)

删去冗余代码

之前没注意,可以直接获取特定平面尺寸的啊(commit 83eb7f)。

把乘方换成乘法

嗯,就是求平方嘛,直接乘多好,用pow()更慢。

说起来虽然是这么一个小改动,但速度提升真是明显(从 r5 到 r6 的 25% 速度提升,AVX优化贡献的可能还不如这里多)。毕竟是在计算量最大的四重循环内,微小的改动就能有大的影响。

经过从 r5 到 r6 的修改,以及对卷积的认识,算是把 JincResize 代码重新认识了一遍,哪里是速度敏感的,怎么样让代码简洁一点,也有了体会。