【发布时间】:2016-03-11 16:28:11
【问题描述】:
我不知道如何实现:
__m256d min(__m256d A, __m256d B, __m256d C, __m256d D)
{
__m256d result;
// result should contain 4 minimal values out of 16 : A[0], A[1], A[2], A[3], B[0], ... , D[3]
// moreover it should be result[0] <= result[1] <= result[2] <= result[2]
return result;
}
对如何以智能方式使用_mm256_min_pd、_mm256_max_pd 和随机/置换有任何想法吗?
================================================ ===
这是我到目前为止的地方,之后:
__m256d T = _mm256_min_pd(A, B);
__m256d Q = _mm256_max_pd(A, B);
A = T; B = Q;
T = _mm256_min_pd(C, D);
Q = _mm256_max_pd(C, D);
C = T; D = Q;
T = _mm256_min_pd(B, C);
Q = _mm256_max_pd(B, C);
B = T; C = Q;
T = _mm256_min_pd(A, B);
Q = _mm256_max_pd(A, B);
A = T; D = Q;
T = _mm256_min_pd(C, D);
Q = _mm256_max_pd(C, D);
C = T; D = Q;
T = _mm256_min_pd(B, C);
Q = _mm256_max_pd(B, C);
B = T; C = Q;
我们有: A[0]
所以最小值在 A 之间,第二个最小值在 A 或 B 之间,... 不知道从那里去哪里......
================================================ =========
第二个想法是问题可以简化为自身,但有 2 个输入 __m256 元素。如果可以做到,那么只需执行 min4(A,B) --> P, min4(C,D) --> Q, min4(P,Q) --> 返回值。
不知道如何处理两个向量:)
================================================ =========================
更新 2:问题几乎解决了——以下函数计算 4 个最小值。
__m256d min4(__m256d A, __m256d B, __m256d C, __m256d D)
{
__m256d T;
T = _mm256_min_pd(A, B);
B = _mm256_max_pd(A, B);
B = _mm256_permute_pd(B, 0x5);
A = _mm256_min_pd(T, B);
B = _mm256_max_pd(T, B);
B = _mm256_permute2f128_pd(B, B, 0x1);
T = _mm256_min_pd(A, B);
B = _mm256_max_pd(A, B);
B = _mm256_permute_pd(B, 0x5);
A = _mm256_min_pd(A, B);
T = _mm256_min_pd(C, D);
D = _mm256_max_pd(C, D);
D = _mm256_permute_pd(D, 0x5);
C = _mm256_min_pd(T, D);
D = _mm256_max_pd(T, D);
D = _mm256_permute2f128_pd(D, D, 0x1);
T = _mm256_min_pd(C, D);
D = _mm256_max_pd(C, D);
D = _mm256_permute_pd(D, 0x5);
C = _mm256_min_pd(C, D);
T = _mm256_min_pd(A, C);
C = _mm256_max_pd(A, C);
C = _mm256_permute_pd(C, 0x5);
A = _mm256_min_pd(T, C);
C = _mm256_max_pd(T, C);
C = _mm256_permute2f128_pd(C, C, 0x1);
T = _mm256_min_pd(A, C);
C = _mm256_max_pd(A, C);
C = _mm256_permute_pd(C, 0x5);
A = _mm256_min_pd(A, C);
return A;
};
剩下的就是在返回之前对 A 内部的值进行升序排序。
【问题讨论】:
-
您遇到的具体问题是什么?这是一个相当广泛的问题。
-
您正在寻找一个将所有 16 个双精度数中最低的 4 个双精度数按顺序排列到一个向量中,对吗?谷歌 SIMD 排序网络之类的东西。您可能会发现解包到两个
__m128d向量对于某些步骤很有用,但可能不是。如果您只关心最小的 4 个元素,而不是完整的排序,那么使用 SIMD 排序网络可能更难击败标量代码。 -
正确——所有 16 个双精度数中最低的 4 个双精度数成为一个向量。这 4 个向量包含 16 个值,这些值是 SIMD 计算的结果,效果非常好。最后必须选择最低的 4 个。目标不是击败标量代码,而只是避免它。将值卸载到内存,然后进行排序,然后再次加载,对我来说似乎不合逻辑。
-
这里最重要的性能标准是什么?延迟、吞吐量或总融合域微指令(即对周围代码吞吐量的影响)?乱序执行是否可能同时进行多个排序,或者与其他工作重叠,或者这是循环携带依赖的一部分?
-
顺便说一句,从 n 中找出最小的 k 个元素的正式名称是 Selection algorithm。 (从技术上讲,选择算法只找到第 k 阶统计量,而不是所有 k..n 或 0..k(部分排序)。我们想要一个不做额外工作的部分排序来确保数组的其余部分(或寄存器)仍然有有意义的数据。)无论如何,我没有找到很多关于 very small
k的讨论,其中 n 在谷歌搜索 simd selection algorithm 时也很小。 ://
标签: c++ simd intrinsics avx avx2