相关疑难解决方法(0)

使用SSE/AVX获取存储在__m256d中的值的总和

有没有办法获得存储在__m256d变量中的值的总和?我有这个代码.

acc = _mm256_add_pd(acc, _mm256_mul_pd(row, vec));
//acc in this point contains {2.0, 8.0, 18.0, 32.0}
acc = _mm256_hadd_pd(acc, acc);
result[i] = ((double*)&acc)[0] + ((double*)&acc)[2];
Run Code Online (Sandbox Code Playgroud)

此代码有效,但我想用SSE/AVX指令替换它.

c++ optimization sse avx avx2

6
推荐指数
2
解决办法
1690
查看次数

生成慢vpermpd指令; 为什么?

我有一个过滤器m_f作用于输入向量v通过

Real d2v = m_f[0]*v[i];
for (size_t j = 1; j < m_f.size(); ++j)
{
   d2v += m_f[j] * (v[i + j] + v[i - j]);
}
Run Code Online (Sandbox Code Playgroud)

perf 告诉我们这个循环在哪里热:

在此输入图像描述

vaddpdvfma231pd意义; 没有它们,我们肯定无法执行此操作.但缓慢vpermpd让我感到困惑.它完成了什么?

c++ assembly signal-processing avx auto-vectorization

6
推荐指数
2
解决办法
119
查看次数

在 Zen 2 CPU 上使用 AVX2 实现的 GEMM 内核比 AVX2/FMA 更快

我尝试过加快玩具 GEMM 的实施速度。我处理 32x32 双精度块,为此我需要优化的 MM 内核。我可以访问 AVX2 和 FMA。

我在下面定义了两个代码(在 ASM 中,我为格式的粗糙性表示歉意),一个使用 AVX2 功能,另一个使用 FMA。

在不进行微观基准测试的情况下,我想尝试(理论上)理解为什么 AVX2 实现比 FMA 版本快 1.11 倍。以及可能如何改进这两个版本。

下面的代码适用于 3000x3000 双打 MM,并且内核是使用经典的朴素 MM 和可互换的最深循环来实现的。我使用 Ryzen 3700x/Zen 2 作为开发 CPU。

我没有尝试过积极展开,担心 CPU 可能会耗尽物理寄存器。

AVX2 32x32 MM 内核:

Block 82:
    imul r12, r15, 0xbb8
    mov rax, r11
    mov r13d, 0x0
    vmovupd ymm0, ymmword ptr [rdi+r12*8]
    vmovupd ymm1, ymmword ptr [rdi+r12*8+0x20]
    vmovupd ymm2, ymmword ptr [rdi+r12*8+0x40]
    vmovupd ymm3, ymmword ptr [rdi+r12*8+0x60]
    vmovupd ymm4, ymmword ptr [rdi+r12*8+0x80]
    vmovupd ymm5, …
Run Code Online (Sandbox Code Playgroud)

assembly simd avx micro-optimization matrix-multiplication

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

是否有任何架构将相同的寄存器空间用于标量整数和浮点运算?

我见过的大多数支持本机标量硬件FP的体系结构都将它们推到了一个与主寄存器组分开的完全独立的寄存器空间中。

我见过的大多数支持本机标量硬件FP的体系结构都将它们推到了一个与主寄存器组分开的完全独立的寄存器空间中。

  • X86的遗产的x87 FPU使用部分地分离浮点“堆机”(读:基本上是固定大小的8项环形缓冲器)与寄存器st(0)通过st(7)索引的每个项目。这可能是最流行的区别。它只能通过加载/存储到内存或将比较结果发送到EFLAGS与其他寄存器进行交互。(286 fnstsw ax和i686 fcomi)。
  • 启用FPU的ARM具有一个单独的FP寄存器空间,其工作空间与其整数空间相似。主要区别是专用于浮点的单独指令集,但即使是惯用语也大多对齐。
  • MIPS介于两者之间,因为浮点在技​​术上是通过协处理器完成的(至少是可见的),并且在使用方面有一些略有不同的规则(例如使用两个浮点寄存器而不是单个扩展寄存器的双精度),但是它们在其他方面却相当有效与ARM类似。
  • X86的更新的SSE标量指令使用相似的助记符和惯用法与矢量指令相似地工作。它可以自由加载和存储标准的寄存器和存储器,并且可以使用64位内存引用作为操作数为许多标量运算喜欢addsd xmm1, m64subsd xmm1, m64,但你只能加载和存储,通过寄存器movq xmm1, r/m64movq r/m64, xmm1和朋友。这与ARM64 NEON相似,尽管它与ARM的标准标量指令集略有不同。

相反,许多矢量化指令甚至都不会为这种区别而烦恼,只是在标量和矢量之间作了区分。对于x86,ARM和MIPS,全部三个:

  • 它们将标量和向量寄存器空间分开。
  • 它们将相同的寄存器空间重新用于矢量化的整数和浮点运算。
  • 他们仍然可以访问整数堆栈(如果适用)。
  • 标量运算只是从相关的寄存器空间(或在x86 FP常量的情况下为内存)中提取其标量。

但是我想知道:是否有CPU体系结构将相同的寄存器空间重用于整数和浮点运算?

如果不是这样(由于兼容性之外的原因),是什么会阻止硬件设计人员选择走这条路?

cpu-architecture cpu-registers

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

Simd Matmul程序给出不同的数值结果

我正在尝试使用simd内部函数在C中编程矩阵乘法。我非常确定自己的实现,但是执行时,我会从所得矩阵系数的第5位开始出现一些数字错误。

REAL_T只是具有typedef的浮点数

/* This is my matmul Version with simd, using floating simple precision*/
void matmul(int n, REAL_T *A, REAL_T *B, REAL_T *C){
  int i,j,k;
  __m256 vA, vB, vC, vRes;
  for (i=0; i<n; i++){
    for (j=0; j<n; j++){  
      for (k=0; k<n; k= k+8){
        vA = _mm256_load_ps(&A[i*n+k]);
        vB = _mm256_loadu_ps(&B[k*n+j]);
        vC = _mm256_mul_ps(vA, vB);
        vC = _mm256_hadd_ps(vC, vC);
        vC = _mm256_hadd_ps(vC, vC);
        /*To get the resulting coefficient, after doing 2 hadds,
        I have to get the first and the last element …
Run Code Online (Sandbox Code Playgroud)

c floating-point simd vectorization avx

5
推荐指数
1
解决办法
84
查看次数

使用 AVX 矢量内在函数手动矢量化的运行速度与 Ryzen 上添加的 4 个标量 FP 的速度大致相同?

所以我决定看看如何通过英特尔® Intrinsics 在 C 中使用 SSE、AVX 等。不是因为有任何实际兴趣将它用于某事,而是出于纯粹的好奇心。试图检查使用 AVX 的代码是否实际上比非 AVX 代码快,结果让我有点惊讶。这是我的 C 代码:

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

#include <emmintrin.h>
#include <immintrin.h>


/*** Sum up two vectors using AVX ***/
#define __vec_sum_4d_d64(src_vec1, src_vec2, dst_vec) \
  _mm256_store_pd(dst_vec, _mm256_add_pd(_mm256_load_pd(src_vec1), _mm256_load_pd(src_vec2)));

/*** Sum up two vectors without AVX ***/
#define __vec_sum_4d(src_vec1, src_vec2, dst_vec) \
  dst_vec[0] = src_vec1[0] + src_vec2[0];\
  dst_vec[1] = src_vec1[1] + src_vec2[1];\
  dst_vec[2] = src_vec1[2] + src_vec2[2];\
  dst_vec[3] = src_vec1[3] + src_vec2[3];


int main (int argc, char *argv[]) {
  unsigned long i; …
Run Code Online (Sandbox Code Playgroud)

c x86 assembly cpu-architecture avx

5
推荐指数
1
解决办法
147
查看次数

指令减少 33%,内存访问减少 17%,但速度提高 4 倍?

概括

我有两段 C++ 代码,它们执行相同的计算。与代码 A 相比,代码 B 确实减少了大约 33% 的指令,大约减少了 17% 的内存访问,但运行速度是代码 A 的四倍(而不是两倍)。会是什么原因呢?此外,我们如何才能确认您的回答所提供的主张?

在这两个代码中,

  • howmany是 20 000 000
  • testees有 20 000 000 个元素,mt19937在启动时(在这些片段之前)为代码 A 和代码 B 随机生成 ( )。
  • 乘法是通过对内存的一次访问来处理的(如稍后在汇编代码中看到的)
  • 两个代码都是用优化标志编译的-O1

一些代码

代码 A - 运行时间约为。95 至 110 毫秒

    GF2 sum {GF2(1)};
    auto a = system_clock::now();
    for(size_t i=0;i<howmany;i++){
        sum *= testees[i]; 
    }
    auto b = system_clock::now();
Run Code Online (Sandbox Code Playgroud)

代码 B - 运行时间约为。25 至 30 毫秒

    GF2 sum1 {GF2(1)};
    GF2 sum2 {GF2(1)};
    GF2 sum3 …
Run Code Online (Sandbox Code Playgroud)

c++ performance assembly g++

5
推荐指数
0
解决办法
260
查看次数

优化累积总和

我需要一些帮助来了解我尝试的优化是如何工作的。

cumsum函数获取一个向量,并用累加和写入一个向量。

我尝试了以下方法来优化它:我没有在整个向量上执行一次循环,而是编写了一个循环,该循环在每四分之一的向量上同时运行。然后调整每个部分以考虑前面部分的总和。结果略有不同,但这不是问题。

这是程序:

module cumsum_mod
    implicit none
    integer, parameter, private :: dp = kind(1d0)
contains
    ! cumsum in one straight loop
    subroutine cumsum1(n, a, b)
        integer :: n, i
        real(dp) :: a(n), b(n)
        
        b(1) = a(1)
        do i = 2, n
            b(i) = a(i) + b(i-1)
        end do
    end subroutine
    
    subroutine cumsum2(n, a, b)
        integer :: n, i, m
        real(dp) :: a(n), b(n)
        
        m = n/4
        
        ! Loop over the four parts
        b(1) = a(1)
        b(1+m) = …
Run Code Online (Sandbox Code Playgroud)

optimization x86 assembly fortran x86-64

5
推荐指数
0
解决办法
81
查看次数

乘法和求和/相加两个数组(点积)的最快方法 - 未对齐比 FMA 快得惊人

嗨我有以下代码:

public unsafe class MultiplyAndAdd : IDisposable
{
    float[] rawFirstData = new float[1024];
    float[] rawSecondData = new float[1024];

    static int alignment = 32;
    float[] alignedFirstData = new float[1024 + alignment / sizeof(float)];
    int alignedFirstDataOffset;
    GCHandle alignedFirstDataHandle;
    float* alignedFirstDataPointer;
    float[] alignedSecondData = new float[1024 + alignment / sizeof(float)];
    int alignedSecondDataOffset;
    GCHandle alignedSecondDataHandle;
    float* alignedSecondDataPointer;

    public IEnumerable<object[]> Data { get; set; }

    public void Dispose()
    {
        this.alignedFirstDataHandle.Free();
        this.alignedSecondDataHandle.Free();
    }

    //Calculate the offset that needs to be applied to ensure that the array …
Run Code Online (Sandbox Code Playgroud)

c# intrinsics avx2 fma .net-6.0

5
推荐指数
1
解决办法
1159
查看次数

当源 = 目标、就地时,AVX512 自动向量化 C++ 矩阵向量函数要慢得多

我尝试编写一些函数来使用单个矩阵和源向量数组来执行矩阵向量乘法。我曾经用 C++ 编写过这些函数,并在 x86 AVX512 汇编中编写过一次,以将性能与英特尔 VTune Profiler 进行比较。当使用源向量数组作为目标数组时,汇编变体的执行速度比 C++ 对应版本快 3.5 倍到 10x\xc2\xa0,但是当使用不同的源和目标数组时,汇编变体的性能几乎不比 C++ 对应版本更好,实现几乎相同的性能...有时甚至更糟。

\n

我无法理解的另一件事是,为什么在使用不同的源和目标数组时,C++ 对应项甚至可以达到与汇编变体接近相同或更好的性能水平,即使汇编代码要短得多并且也根据静态分析工具 uica 和 llvm-mca 速度提高数倍。uica.uops.info

\n

我不想让这篇文章变得太长,所以我只发布执行 mat4-vec4 乘法的函数的代码。

\n

这是汇编变体的代码,它假设矩阵要转置:

\n
alignas(64) uint32_t mat4_mul_vec4_avx512_vpermps_index[64]{    0, 0, 0, 0, 4, 4, 4, 4, 8, 8, 8, 8, 12, 12, 12, 12,\n                                                            1, 1, 1, 1, 5, 5, 5, 5, 9, 9, 9, 9, 13, 13, 13, 13,\n                                                            2, 2, 2, 2, 6, 6, 6, 6, 10, 10, 10, 10, 14, 14, …
Run Code Online (Sandbox Code Playgroud)

c++ assembly x86-64 auto-vectorization avx512

5
推荐指数
1
解决办法
206
查看次数