【发布时间】:2014-01-03 11:38:12
【问题描述】:
我正在尝试编写一些相当快的分量向量加法代码。我正在使用(签名,我相信)64 位整数。
功能是
void addRq (int64_t* a, const int64_t* b, const int32_t dim, const int64_t q) {
for(int i = 0; i < dim; i++) {
a[i] = (a[i]+b[i])%q; // LINE1
}
}
我在 IvyBridge(SSE4.2 和 AVX,但不是 AVX2)上使用 icc -std=gnu99 -O3(icc,以便我以后可以使用 SVML)进行编译。
我的基线是从 LINE1 中删除 %q。 dim=11221184 的 100 个(迭代)函数调用需要 1.6 秒。 ICC 自动矢量化 SSE 的代码;很棒。
不过,我真的很想做模块化添加。使用%q,ICC 不会自动矢量化代码,它会在 11.8 秒内运行(!)。即使忽略上一次尝试的自动矢量化,这似乎仍然过分。
由于我没有 AVX2,使用 SSE 进行矢量化需要 SVML,这可能是 ICC 不自动矢量化的原因。无论如何,这是我对内循环进行矢量化的尝试:
__m128i qs = _mm_set1_epi64x(q);
for(int i = 0; i < dim; i+=2) {
__m128i xs = _mm_load_si128((const __m128i*)(a+i));
__m128i ys = _mm_load_si128((const __m128i*)(b+i));
__m128i zs = _mm_add_epi64(xs,ys);
zs = _mm_rem_epi64(zs,qs);
_mm_store_si128((__m128i*)(a+i),zs);
}
主循环的组装是:
..B3.4: # Preds ..B3.2 ..B3.12
movdqa (%r12,%r15,8), %xmm0 #59.22
movdqa %xmm8, %xmm1 #60.14
paddq (%r14,%r15,8), %xmm0 #59.22
call __svml_i64rem2 #61.9
movdqa %xmm0, (%r12,%r15,8) #61.36
addq $2, %r15 #56.30
cmpq %r13, %r15 #56.24
jl ..B3.4 # Prob 82% #56.24
所以代码按预期进行了矢量化。我知道由于 SVML,我可能无法获得 2 倍的加速,但代码运行时间为 12.5 秒,比完全没有矢量化的情况要慢!这真的是这里能做到的最好的吗?
【问题讨论】:
-
对模数的函数调用正在扼杀性能 - 您对
q的可能值有任何先验知识吗? -
如果您知道输入已完全减少,那么您最好使用比较和条件减法。
-
@PaulR q 在运行时应该(基本上)保持不变,但在编译时不会知道。这怎么可能是有利的?
-
@Mysticial 有趣的是,条件减法只用了 1.9 秒,这可能是合理的,但 ICC 没有矢量化。我不知道它怎么那么快。
-
@Eric 您可以使用 SIMD 进行条件操作。比较指令返回一个全 0 或全 1 的向量,然后您可以将其与另一个值进行 AND 运算并从目标中减去。
标签: c assembly x86-64 sse intrinsics