有没有办法获得存储在__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指令替换它.
我有一个过滤器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 告诉我们这个循环在哪里热:
该vaddpd和vfma231pd意义; 没有它们,我们肯定无法执行此操作.但缓慢vpermpd让我感到困惑.它完成了什么?
我尝试过加快玩具 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) 我见过的大多数支持本机标量硬件FP的体系结构都将它们推到了一个与主寄存器组分开的完全独立的寄存器空间中。
我见过的大多数支持本机标量硬件FP的体系结构都将它们推到了一个与主寄存器组分开的完全独立的寄存器空间中。
st(0)通过st(7)索引的每个项目。这可能是最流行的区别。它只能通过加载/存储到内存或将比较结果发送到EFLAGS与其他寄存器进行交互。(286 fnstsw ax和i686 fcomi)。addsd xmm1, m64或subsd xmm1, m64,但你只能加载和存储,通过寄存器movq xmm1, r/m64,movq r/m64, xmm1和朋友。这与ARM64 NEON相似,尽管它与ARM的标准标量指令集略有不同。相反,许多矢量化指令甚至都不会为这种区别而烦恼,只是在标量和矢量之间作了区分。对于x86,ARM和MIPS,全部三个:
但是我想知道:是否有CPU体系结构将相同的寄存器空间重用于整数和浮点运算?
如果不是这样(由于兼容性之外的原因),是什么会阻止硬件设计人员选择走这条路?
我正在尝试使用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) 所以我决定看看如何通过英特尔® 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++ 代码,它们执行相同的计算。与代码 A 相比,代码 B 确实减少了大约 33% 的指令,大约减少了 17% 的内存访问,但运行速度是代码 A 的四倍(而不是两倍)。会是什么原因呢?此外,我们如何才能确认您的回答所提供的主张?
在这两个代码中,
howmany是 20 000 000testees有 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) 我需要一些帮助来了解我尝试的优化是如何工作的。
该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) 嗨我有以下代码:
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++ 编写过这些函数,并在 x86 AVX512 汇编中编写过一次,以将性能与英特尔 VTune Profiler 进行比较。当使用源向量数组作为目标数组时,汇编变体的执行速度比 C++ 对应版本快 3.5 倍到 10x\xc2\xa0,但是当使用不同的源和目标数组时,汇编变体的性能几乎不比 C++ 对应版本更好,实现几乎相同的性能...有时甚至更糟。
\n我无法理解的另一件事是,为什么在使用不同的源和目标数组时,C++ 对应项甚至可以达到与汇编变体接近相同或更好的性能水平,即使汇编代码要短得多并且也根据静态分析工具 uica 和 llvm-mca 速度提高数倍。uica.uops.info
\n我不想让这篇文章变得太长,所以我只发布执行 mat4-vec4 乘法的函数的代码。
\n这是汇编变体的代码,它假设矩阵要转置:
\nalignas(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)