C++ 使用Intel Intrinsic快速查找整数数组和
我一直在做一个在线判断的任务:实现C++ 使用Intel Intrinsic快速查找整数数组和,c++,intrinsics,avx,avx2,C++,Intrinsics,Avx,Avx2,我一直在做一个在线判断的任务:实现int-sum(const-int*array,unsigned-int-len),这样它就会返回和的数组len可以是200000,这个函数可以调用200000次;我的程序必须在0.9秒内执行 目前,我的代码如下所示: #include <immintrin.h> #include <stdio.h> int sum(const int* array, unsigned int len) { register int i = 8
int-sum(const-int*array,unsigned-int-len)
,这样它就会返回和的数组len
可以是200000,这个函数可以调用200000次;我的程序必须在0.9秒内执行
目前,我的代码如下所示:
#include <immintrin.h>
#include <stdio.h>
int sum(const int* array, unsigned int len) {
register int i = 8, s = 0;
__m256i sm = _mm256_loadu_si256((void *)(array));
for (; i+8 < len; i += 8) {
const __m256i x = _mm256_loadu_si256((void *)(array+i));
sm = _mm256_add_epi32(sm, x);
}
sm = _mm256_hadd_epi32(sm, sm);
sm = _mm256_hadd_epi32(sm, sm);
s = _mm256_extract_epi32(sm, 0);
s += _mm256_extract_epi32(sm, 4);
for(; i < len; ++i) s += array[i];
return s;
}
#包括
#包括
整数和(常量整数*数组,无符号整数len){
寄存器int i=8,s=0;
__m256i sm=_mm256_loadu_si256((空*)(数组));
对于(;i+8
但是,当法官报告超过了时间限制时,该代码不会通过
有人能指出哪些指令在时间上是昂贵的,以及如何加速我的代码吗?快速检查一下,看起来最新的处理器提供了两个加载端口和两个加法端口,因此至少从理论上讲,通过展开循环的两次迭代,您应该可以获得可观的收益(虽然如果数据非常大,它可能会很快下降到主内存的带宽)
与任何AVX操作一样,您希望确保正在使用的数据正确对齐。如果数据未对齐,较旧的处理器将出现故障。较新的处理器将正常工作,但您将受到相当严重的速度损失。实施@JerryCoffin的建议:
#include <immintrin.h>
#include <stdio.h>
int sum(const int* array, unsigned int len) {
if(len < 60) {
int s = 0;
for(int i = 0; i < len; ++i) s += array[i];
return s;
}
register int i = 0, s = 0;
__m256i sm = _mm256_loadu_si256((void *)(array+i));
__m256i sm2 = _mm256_loadu_si256((void *)(array+i+8));
i += 16;
for (; i+16 < len; i += 16) {
const __m256i x = _mm256_loadu_si256((void *)(array+i));
sm = _mm256_add_epi32(sm, x);
const __m256i y = _mm256_loadu_si256((void *)(array+i+8));
sm2 = _mm256_add_epi32(sm2, y);
}
sm = _mm256_add_epi32(sm, sm2);
sm = _mm256_hadd_epi32(sm, sm);
sm = _mm256_hadd_epi32(sm, sm);
s += _mm256_extract_epi32(sm, 0);
s += _mm256_extract_epi32(sm, 4);
for(; i < len; ++i) s += array[i];
return s;
}
#包括
#包括
整数和(常量整数*数组,无符号整数len){
if(len<60){
int s=0;
对于(int i=0;i
有趣的是,由于函数被调用的次数太多,在数组对齐之前消耗整数实际上比使用loadu
要花费更多的时间,因为函数被调用的次数太多-你的意思是说计数太少,所以启动开销会很高?是的,尤其是如果数据经常正确对齐,则将其保留为HW通常是好的。(虽然对于将相同字节重新处理两次是便宜的,例如复制并添加到非重叠输出中,未对齐且可能重叠的第一个向量可能是好的)。当L1d缓存中的数据不热时,支持AVX2的CPU通常会以足够快的速度吸收未对齐成本,以跟上L3或RAM(只有2%的慢),甚至大部分是L2。如果小的阵列性能很重要,使用一个更好的水平和(),并且考虑用一个不对齐的矢量负载来处理尾部,以避免双重计数。(如果奇数大小正常,也可以使用0..3\uuu m128i
向量,将所需的标量清理量从0..15减少到0..3标量)但是,清理代码的分支预测可能会有问题;如果您可以分析在线法官的工作负载,请单击IDK。如果您的带宽有限,您可能希望签出评论,而不是用于扩展讨论;此对话已结束。