Tag: avx

在_mm256_rsqrt_ps()中处理零

鉴于_mm256_sqrt_ps()相对较慢,并且我生成的值会立即被_mm256_floor_ps()截断,看看它似乎在做: _mm256_mul_ps(_mm256_rsqrt_ps(eightFloats), eightFloats); 是获得额外性能和避免管道停滞的方法。 不幸的是,零值,我当然得到崩溃计算1/sqrt(0) 。 围绕这个的最佳方法是什么? 我试过这个(有效并且更快),但是有更好的方法,还是我会在某些条件下遇到问题? _mm256_mul_ps(_mm256_rsqrt_ps(_mm256_max_ps(eightFloats, _mm256_set1_ps(0.1))), eightFloats); 我的代码用于垂直应用程序,因此我可以假设它将在Haswell CPU(i7-4810MQ)上运行,因此可以使用FMA / AVX2。 原始代码大约是: float vals[MAX]; int sum = 0; for (int i = 0; i < MAX; i++) { int thisSqrt = (int) floor(sqrt(vals[i])); sum += min(thisSqrt, 0x3F); } vals所有值都应该是整数值。 (为什么一切都不仅仅是int是一个不同的问题…)

L1内存带宽:使用相差4096 + 64字节的地址,效率下降50%

我想用英特尔处理器实现以下操作的最大带宽。 for(int i=0; i<n; i++) z[i] = x[i] + y[i]; //n=2048 其中x,y和z是浮点数组。 我在Haswell,Ivy Bridge和Westmere系统上这样做。 我最初分配了这样的内存 char *a = (char*)_mm_malloc(sizeof(float)*n, 64); char *b = (char*)_mm_malloc(sizeof(float)*n, 64); char *c = (char*)_mm_malloc(sizeof(float)*n, 64); float *x = (float*)a; float *y = (float*)b; float *z = (float*)c; 当我这样做时,我获得了每个系统预期的峰值带宽的大约50%。 峰值计算为frequency * average bytes/clock_cycle 。 每个系统的平均字节/时钟周期为: Core2: two 16 byte reads one […]

使用SSE / AVX进行OpenMP减少

我想使用OpenMP和SIMD对arrays进行减少。 我读到OpenMP的减少相当于: inline float sum_scalar_openmp2(const float a[], const size_t N) { float sum = 0.0f; #pragma omp parallel { float sum_private = 0.0f; #pragma omp parallel for nowait for(int i=0; i<N; i++) { sum_private += a[i]; } #pragma omp atomic sum += sum_private; } return sum; } 我从以下链接得到了这个想法: http : //bisqwit.iki.fi/story/howto/openmp/#ReductionClause但是atomic也不支持复杂的运算符。 我所做的是用关键替换primefaces并用OpenMP和SSE实现这种减少: #define ROUND_DOWN(x, s) […]

一个目标文件中的代码对齐正在影响另一个目标文件中的函数的性能

我熟悉数据对齐和性能,但我很擅长对齐代码。 我最近开始使用NASM在x86-64汇编中进行编程,并且一直在使用代码对齐来比较性能。 据我所知,NASM插入nop指令来实现代码对齐。 这是我在Ivy Bridge系统上尝试过的function void triad(float *x, float *y, float *z, int n, int repeat) { float k = 3.14159f; int(int r=0; r<repeat; r++) { for(int i=0; i<n; i++) { z[i] = x[i] + k*y[i]; } } } 我正在使用的组件如下。 如果我没有指定对齐,我的性能与峰值相比只有大约90%。 但是,当我将循环前的代码以及两个内部循环对齐到16个字节时,性能会跳跃到96%。 很明显,这种情况下的代码对齐有所不同。 但这是最奇怪的部分。 如果我将最里面的循环对齐到32个字节,那么这个函数的性能没有任何区别,但是,在这个函数的另一个版本中,在单独的目标文件中使用内在函数,我将其性能从90%链接到95%! 我做了一个对象转储(使用objdump -d -M intel )的版本对齐到16个字节(我将结果发布到这个问题的结尾)和32个字节,它们是相同的! 事实certificate,在两个目标文件中,最内层循环无论如何都对齐到32个字节。 但必须有一些区别。 我对每个目标文件进行了hex转储,目标文件中有一个字节不同。 对齐到16个字节的目标文件具有0x10的字节,并且对应于32个字节的目标文件具有0x20的字节。 到底是怎么回事! […]

乘以int64_t数组的最快方法?

我想矢量化两个内存对齐数组的乘法。 我没有找到任何方法在AVX / AVX2中乘以64 * 64位,所以我只是循环展开和AVX2加载/存储。 有更快的方法吗? 注意:我不想保存每次乘法的高半结果。 void multiply_vex(long *Gi_vec, long q, long *Gj_vec){ int i; __m256i data_j, data_i; __uint64_t *ptr_J = (__uint64_t*)&data_j; __uint64_t *ptr_I = (__uint64_t*)&data_i; for (i=0; i<BASE_VEX_STOP; i+=4) { data_i = _mm256_load_si256((__m256i*)&Gi_vec[i]); data_j = _mm256_load_si256((__m256i*)&Gj_vec[i]); ptr_I[0] -= ptr_J[0] * q; ptr_I[1] -= ptr_J[1] * q; ptr_I[2] -= ptr_J[2] * q; ptr_I[3] […]

AVX标量操作要快得多

我测试了以下简单的function void mul(double *a, double *b) { for (int i = 0; i<N; i++) a[i] *= b[i]; } 具有非常大的数组,因此它是内存带宽限制。 我使用的测试代码如下。 当我用-O2编译时需要1.7秒。 当我用-O2 -mavx编译时,它只需要1.0秒。 非vex编码的标量操作慢了70%! 为什么是这样? 这是-O2和-O2 -mavx的程序集。 <img src="http://sofzh.miximages.com/c/otliN.png" alt=" -O2 和 -O2 -mavx 的vimddif”> https://godbolt.org/g/w4p60f 系统:i7-6700HQ@2.60GHz(Skylake)32 GB内存,Ubuntu 16.10,GCC 6.3 测试代码 //gcc -O2 -fopenmp test.c //or //gcc -O2 -mavx -fopenmp test.c #include #include #include #include […]

这个memcpy实现中缺少什么/次优?

我对编写memcpy()作为一种教育练习感兴趣。 我不会写一篇关于我做了什么和没想过的论文,但这里有一些人的实现 : __forceinline //因为通常Size已知,内联后编译器可以优化掉大部分无用代码void* myMemcpy(char* Dst, const char* Src, size_t Size) { void* start = Dst; for ( ; Size >= sizeof(__m256i); Size -= sizeof(__m256i) ) { __m256i ymm = _mm256_loadu_si256(((const __m256i* &)Src)++); _mm256_storeu_si256(((__m256i* &)Dst)++, ymm); } #define CPY_1B *((uint8_t * &)Dst)++ = *((const uint8_t * &)Src)++ #define CPY_2B *((uint16_t* &)Dst)++ = *((const uint16_t* […]

如何执行_mm256_movemask_epi8(VPMOVMSKB)的反转?

内在的: int mask = _mm256_movemask_epi8(__m256i s1) 创建一个掩码,其32位对应于s1的每个字节的最高位。 在使用位操作(例如BMI2 )操作掩码之后,我想执行_mm256_movemask_epi8的反转,即创建__m256i向量,其中每个字节的最高有效位包含uint32_t mask的相应位。 做这个的最好方式是什么? 编辑:我需要执行逆操作,因为内部_mm256_blendv_epi8只接受__m256i类型的掩码而不是uint32_t 。 因此,在生成的__m256i掩码中,我可以忽略每个字节的MSB以外的位。