相关疑难解决方法(0)

AVX2:计算 512 个浮点数组的点积

我先说我是 SIMD 内在函数的完全初学者。

本质上,我有一个支持 AVX2 内在 ( Intel(R) Core(TM) i5-7500T CPU @ 2.70GHz)的 CPU 。我想知道计算两个std::vector<float>size的点积的最快方法512

我在网上做了一些挖掘,发现了这个这个这个堆栈溢出问题建议使用以下函数__m256 _mm256_dp_ps(__m256 m1, __m256 m2, const int mask);,但是,这些都表明了执行点积的不同方法我不确定什么是正确的(和最快的)方法它。

特别是,我正在寻找对大小为 512 的向量执行点积的最快方法(因为我知道向量大小会影响实现)。

感谢您的帮助

编辑 1:我也对-mavx2gcc 标志有点困惑。如果我使用这些 AVX2 函数,我编译时是否需要添加标志?另外,-OFast如果我编写了一个天真的点积实现,gcc 是否能够为我做这些优化(比如我使用gcc 标志)?

编辑 2 如果有人有时间和精力,如果您能编写完整的实现,我将不胜感激。我相信其他初学者也会重视这些信息。

c++ simd dot-product avx2 fma

15
推荐指数
1
解决办法
3210
查看次数

向量加载/存储和收集/分散的每元素原子性?

考虑像一个数组atomic<int32_t> shared_array[].如果你想SIMD矢量化for(...) sum += shared_array[i].load(memory_order_relaxed)怎么办?或者在数组中搜索第一个非零元素,或者将其范围归零?这可能很少见,但考虑一下不允许在元素内撕裂的任何用例,但在元素之间重新排序很好. (也许是寻找CAS候选人的搜索).

认为 x86对齐的向量加载/存储在实践中可以安全地用于带有mo_relaxed操作的SIMD ,因为任何撕裂只会发生在当前硬件上最坏的8B边界(因为这是自然对齐的8B访问原子1的原因).不幸的是,英特尔的手册只说:

"可以使用多个存储器访问来实现访问大于四字的数据的x87指令或SSE指令."

无法保证这些组件访问是自然对齐,不重叠或其他任何内容.(有趣的事实:根据Agner Fog,大概是qword + word,fld m80在Haswell上用2个加载uops和2个ALU uops完成x87 10字节加载.)

如果你想在面向未来的方式,当前的x86手册上说,未来所有的x86 CPU将努力向量化,你可以在8B块与加载/存储movq/ movhps.

或者你可以使用vpmaskmovd带有全真掩码的256b,因为手册的操作部分用多个独立的32位负载来定义它,比如Load_32(mem + 4).这是否意味着每个元素都作为一个单独的32位访问,保证该元素内的原子性?

(在实际硬件上,它是Haswell上的1个负载和2个端口5 uops,或者Ryzen上只有1或2个负载+ ALU uops(128/256).我认为这是针对不需要从元素中抑制异常的情况进入一个未映射的页面,因为它可能会更慢(但IDK如果它需要微代码辅助).无论如何,这告诉我们它至少与vmovdqaHaswell上的正常负载一样原子,但这告诉我们没有关于x86 Deathstation 9000 16B的信息/ 32B向量访问被分解为单字节访问,因此每个元素内可能会有撕裂.

我认为实际上可以安全地假设你不会在16,32或64位元素中撕裂任何真正的x86 CPU上的对齐矢量加载/存储,因为这对于已经有效的实现是没有意义的必须保持自然对齐的64位标量存储原子,但知道手册中的保证到底有多远是有趣的.)


收集(AVX2,AVX512)/ Scatter(AVX512)

类似vpgatherdd的指令显然由多个独立的32b或64b访问组成.AVX2表格被记录为多次执行,FETCH_32BITS(DATA_ADDR);因此可能会被通常的原子性保证所覆盖,并且如果它不跨越边界,则每个元素将以原子方式收集.

AVX512褶裥都记录在英特尔公司的PDF的insn参考手册作为
DEST[i+31:i] <- MEM[BASE_ADDR + SignExtend(VINDEX[i+31:i]) * …

x86 sse atomic avx avx512

13
推荐指数
0
解决办法
557
查看次数

使 std::vector 分配对齐内存的现代方法

以下问题是相关的,但答案是旧的,并且从用户评论马克Glisse表明有因为C ++ 17的新方法这个问题可能没有得到充分讨论。

我试图让对齐的内存为 SIMD 正常工作,同时仍然可以访问所有数据。

在 Intel 上,如果我创建一个类型为 的浮点向量__m256,并将我的大小减小 8 倍,它会给我对齐的内存。

例如 std::vector<__m256> mvec_a((N*M)/8);

以一种稍微有点麻烦的方式,我可以将指向向量元素的指针转换为浮点,这允许我访问单个浮点值。

相反,我更喜欢std::vector<float>正确对齐的 ,因此可以加载到__m256其他 SIMD 类型中而不会出现段错误。

我一直在研究aligned_alloc

这可以给我一个正确对齐的 C 样式数组:

auto align_sz = static_cast<std::size_t> (32);
float* marr_a = (float*)aligned_alloc(align_sz, N*M*sizeof(float));
Run Code Online (Sandbox Code Playgroud)

但是我不确定如何为std::vector<float>. 授予std::vector<float>所有权marr_a 似乎是不可能的

我已经看到一些建议我应该编写自定义分配器,但这似乎需要做很多工作,也许现代 C++ 有更好的方法?

c++ simd memory-alignment stdvector c++17

13
推荐指数
2
解决办法
729
查看次数

使用带有gcc的SSE指令而不使用内联汇编

我有兴趣使用x86-64与gcc的SSE向量指令,并且不想为此使用任何内联汇编.有没有办法在C中做到这一点?如果是这样,有人可以举个例子吗?

c gcc sse x86-64 simd

12
推荐指数
3
解决办法
8834
查看次数

如何解决AVX加载/存储操作的32字节对齐问题?

我在使用时遇到对齐问题 ymm寄存器,一些代码片段对我来说似乎很好.这是一个最小的工作示例:

#include <iostream> 
#include <immintrin.h>

inline void ones(float *a)
{
     __m256 out_aligned = _mm256_set1_ps(1.0f);
     _mm256_store_ps(a,out_aligned);
}

int main()
{
     size_t ss = 8;
     float *a = new float[ss];
     ones(a);

     delete [] a;

     std::cout << "All Good!" << std::endl;
     return 0;
}
Run Code Online (Sandbox Code Playgroud)

当然,sizeof(float)4在我的架构(英特尔(R)至强(R)CPU E5-2650 V2 @ 2.60GHz),我与编译gcc使用-O3 -march=native标志.当然,错误会随着未对齐的内存访问而消失,即指定_mm256_storeu_ps.我在xmm寄存器上也没有这个问题,即

inline void ones_sse(float *a)
{
     __m128 out_aligned = _mm_set1_ps(1.0f);
     _mm_store_ps(a,out_aligned);
}
Run Code Online (Sandbox Code Playgroud)

我做了什么愚蠢的事吗?解决这个问题的方法是什么?

c++ sse memory-alignment avx c++11

11
推荐指数
2
解决办法
4468
查看次数

与 GCC 5 相比,使用 GCC 9 编译的 STLpriority_queue 性能较慢

对于我的项目,我从 GCC 5 切换到 GCC 9,发现性能变得更差。我做了一些调查并提出了一个简单的源代码来重现该行为。

我在同一台机器上使用不同的 GCC 版本(g++-5 和 g++-9)编译代码

#include <queue>

int main()
{
        std::priority_queue<int> q;
        for (int j = 0; j < 2000; j ++) {
                for (int i = 0; i < 20000; i ++) {
                        q.emplace(i);
                }
                for (int i = 0; i < 20000; i ++) {
                        q.pop();
                }
        }
        return 0;
}
Run Code Online (Sandbox Code Playgroud)

当我使用 GCC 5 编译它时,我得到以下计时:

# g++-5 -std=c++14 -O3 main.cpp
# time ./a.out

real    0m1.580s
user    0m1.578s
sys     0m0.001s
Run Code Online (Sandbox Code Playgroud)

对 GCC 9 …

c++ performance gcc priority-queue compiler-optimization

11
推荐指数
1
解决办法
312
查看次数

C循环优化有助于最终分配

因此,对于我在计算机系统课程中的最终作业,我们需要优化这些forloops,使其比原始版本更快.使用我们的linux服务器,基本等级不到7秒,完整等级不到5秒.我在这里的代码大约需要5.6秒.我想我可能需要以某种方式使用指针来使它更快,但我不是很确定.任何人都可以提供我的任何提示或选项吗?非常感谢!

QUICKEDIT:文件必须保持50行或更少,我忽略了教师所包含的那些注释行.

#include <stdio.h>
#include <stdlib.h>

// You are only allowed to make changes to this code as specified by the comments in it.

// The code you submit must have these two values.
#define N_TIMES     600000
#define ARRAY_SIZE   10000

int main(void)
{
    double  *array = calloc(ARRAY_SIZE, sizeof(double));
    double  sum = 0;
    int     i;

    // You can add variables between this comment ...
    register double sum1 = 0, sum2 = 0, sum3 = 0, sum4 = 0, sum5 = 0, …
Run Code Online (Sandbox Code Playgroud)

c optimization loops compiler-optimization debug-mode

8
推荐指数
2
解决办法
5650
查看次数

调用always_inline'_mm_mullo_epi32'时内联失败:目标特定选项不匹配

我正在尝试使用使用SIMD内在函数的cmake编译C程序.当我尝试编译它时,我得到两个错误

/ usr/lib/gcc/x86_64-linux-gnu/5/include/smmintrin.h:326:1:错误:内联调用always_inline'_mm_mullo_epi32'失败:目标特定选项不匹配_mm_mullo_epi32(__ m128i __X,__ m128i __Y)

/ usr/lib/gcc/x86_64-linux-gnu/5/include/tmmintrin.h:136:1:错误:内联调用always_inline'_mm_shuffle_epi8'失败:目标特定选项不匹配_mm_shuffle_epi8(__ m128i __X,__ m128i __Y)

这个问题已经在这里通过设置 解决了StackOverflow

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse4.1")
Run Code Online (Sandbox Code Playgroud)

我尝试了相同的和许多其他选项.但我的项目仍然无法编译.

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse4.1")  
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -sse4_1")  
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=nehalem")  
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse4.1 -msse4.2")  
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")  
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ssse3")  
Run Code Online (Sandbox Code Playgroud)

c x86 sse simd cmake

8
推荐指数
2
解决办法
5861
查看次数

强制AVX内在函数使用SSE指令

不幸的是我有一个AMD打桩机cpu,它似乎与AVX指令有问题:

使用256位AVX寄存器进行的内存写入非常慢.测量的吞吐量比之前的型号(Bulldozer)慢5到6倍,比两个128位写入慢8到9倍.

根据我自己的经验,我发现mm256内在函数比mm128要慢得多,而且我假设它是因为上述原因.

我真的想编写最新的指令集AVX,同时仍然能够以合理的速度在我的机器上测试构建.有没有办法迫使mm256内在函数使用SSE指令?我正在使用VS 2015.

如果没有简单的方法,那么艰难的方式呢.替换<immintrin.h>为包含我自己的内在函数定义的自定义标题,可以编码为使用SSE?不确定这是多么合理,在我完成这项工作之前,如果可能的话,更喜欢更简单的方法.

c++ sse avx visual-studio visual-c++

6
推荐指数
1
解决办法
768
查看次数

std :: bitset和SSE指令

是否可以在std :: bitset的基础数据上使用SSE指令?我正在使用的位集大于无符号长整数,因此to_ulong()方法是不够的.例如,我可以使用这样的指令:

__m128i* ptr= (__m128i*)(&my_bitset[0]);
Run Code Online (Sandbox Code Playgroud)

然后按正常情况执行SSE操作?

对于使用带有SSE的std :: bitset的人来说,我试图搜索互联网,但它似乎并不是一个常见的用例.

c++ sse bitset

5
推荐指数
2
解决办法
525
查看次数