相关疑难解决方法(0)

这种使用 SSE 处理数组尾部的方法是否过度?

我正在摆弄 SSE,试图编写一个函数来将单精度浮点数组的所有值相加。我希望它适用于数组的所有长度,而不仅仅是 4 的倍数的数组,就像网络上几乎所有示例中所假设的那样。我想出了这样的事情:

float sse_sum(const float *x, const size_t n)
{
    const size_t
        steps = n / 4,
        rem = n % 4,
        limit = steps * 4;

    __m128 
        v, // vector of current values of x
        sum = _mm_setzero_ps(0.0f); // sum accumulator

    // perform the main part of the addition
    size_t i;
    for (i = 0; i < limit; i+=4)
    {
        v = _mm_load_ps(&x[i]);
        sum = _mm_add_ps(sum, v);
    }

    // add the last 1 - 3 odd items …
Run Code Online (Sandbox Code Playgroud)

c++ floating-point sse

4
推荐指数
1
解决办法
742
查看次数

如何正确使用预取指令?

我试图矢量化循环,计算大浮点矢量的点积.我正在并行计算它,利用CPU拥有大量XMM寄存器的事实,如下所示:

__m128* A, B;
__m128 dot0, dot1, dot2, dot3 = _mm_set_ps1(0);
for(size_t i=0; i<1048576;i+=4) {
    dot0 = _mm_add_ps( dot0, _mm_mul_ps( A[i+0], B[i+0]);
    dot1 = _mm_add_ps( dot1, _mm_mul_ps( A[i+1], B[i+1]);
    dot2 = _mm_add_ps( dot2, _mm_mul_ps( A[i+2], B[i+2]);
    dot3 = _mm_add_ps( dot3, _mm_mul_ps( A[i+3], B[i+3]);
}
... // add dots, then shuffle/hadd result.
Run Code Online (Sandbox Code Playgroud)

我听说使用预取指令可以帮助加速,因为它可以"在后台"获取更多数据,同时执行muls并添加缓存中的数据.但是我没有找到关于如何使用_mm_prefetch()的示例和解释,何时使用什么地址和什么命中.你可以帮忙吗?

x86 caching sse prefetch dot-product

4
推荐指数
1
解决办法
1612
查看次数

达夫的设备还有用吗?

我看到 Duff 的设备只是在 C 中进行循环展开。

https://en.wikipedia.org/wiki/Duff%27s_device

我不知道为什么它现在仍然有用。编译器不是应该足够聪明来进行循环展开吗?

gcc clang compiler-optimization duffs-device loop-unrolling

4
推荐指数
1
解决办法
917
查看次数

与C / C ++最相关的性能指标

我正在寻找相关的性能指标来基准测试和优化我的C / C ++代码。例如,虚拟内存使用率是一个简单但有效的指标,但是我知道有些虚拟内存使用情况更为专业,可以帮助优化特定域:高速缓存命中/未命中,上下文切换等。

我相信这里是一个列出性能指标,衡量指标以及如何衡量指标的好地方,以帮助希望开始优化程序的人员知道从何开始。

cpu optimization performance benchmarking profiling

4
推荐指数
1
解决办法
87
查看次数

SIMD 搜索最后一个峰值后的低谷

我需要找到比最后一个滚动最大峰值低 X 或更多 % 的值的索引。

峰值是一个数组 ( highs) 中元素的滚动最大值,而值位于另一个数组 ( lows) 中。数组具有相等的长度,并且值保证 <= peaks 数组中的对应项,没有 0、NAN 或无穷大元素。since保证小于till

迭代实现很简单:

inline
size_t trail_max_intern(double *highs,
        double *lows,
        double max,
        double trail,
        size_t since,
        size_t till)
{
    for (; since < till; ++since) {
        if (max < highs[since]) {
            max = highs[since];
        }

        if (lows[since] / max <= trail) {
            break;
        }
    }

    return since;
}

size_t trail_max_iter(double *highs, double *lows, double trail, size_t since, size_t till)
{ …
Run Code Online (Sandbox Code Playgroud)

c simd vectorization avx2

4
推荐指数
1
解决办法
112
查看次数

简单的 AVX512 点积循环仅快 10.6 倍,预期快 16 倍

任务是将数组 A 中的每个浮点数与数组 B 中的相应元素相乘的乘积求和。数组可能有数万个元素,并且必须运行 100,000 倍秒才能处理实时数据流,因此性能是关键。

我使用常规数学对其进行了编码,并再次使用 AVX512 对其进行了编码。它大约快了 10.6 倍,这令人惊讶,因为我预计每条指令执行 16 倍的操作,所以速度会快 16 倍左右。此外,虽然循环有各种开销(例如,循环变量、增量、如果继续循环则分支等),但与原始版本相比,它只执行了 1/16。

我正在 Visual Studio 2022 Community 中以发布模式进行编译,并在 i7-11700F 上运行。

这是代码行。我基本上一次遍历两个数组 16 个元素,将各个元素相乘,并保留 16 个运行和。在计算的最后,我_mm512_reduce_add_ps()对这 16 个和进行求和。

vector<__m512>      a512In;
vector<__m512>      a512IRCurr;
__m512 fOut = _mm512_set1_ps( 0.0 );

for ( iSample = 0; iSample < iIterations; iSample++ ) 
    fOut = _mm512_add_ps( fOut, _mm512_mul_ps( a512In[ iPos++ ],
                                               a512IRCurr[ iSample ] ) );
Run Code Online (Sandbox Code Playgroud)

我发现vmobups并没有假设目标是一致的,并且想知道这是否是问题所在。不过,我还发现,许多代未对齐版本的速度与对齐版本相同,但令人不安的是延迟可能仍然不同:https ://community.intel.com/t5/Intel-ISA-Extensions/what -are-the-performance-implications-of-using-vmovups-and/mp/1143448 虽然我对 6502 品种的机器语言很满意,但我不了解现代英特尔。

我还想知道这是否_mm512_add_ps是正确的a …

c++ performance avx dot-product avx512

4
推荐指数
1
解决办法
904
查看次数

添加冗余分配可在编译时加速代码而无需优化

我发现了一个有趣的现象:

#include<stdio.h>
#include<time.h>

int main() {
    int p, q;
    clock_t s,e;
    s=clock();
    for(int i = 1; i < 1000; i++){
        for(int j = 1; j < 1000; j++){
            for(int k = 1; k < 1000; k++){
                p = i + j * k;
                q = p;  //Removing this line can increase running time.
            }
        }
    }
    e = clock();
    double t = (double)(e - s) / CLOCKS_PER_SEC;
    printf("%lf\n", t);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我在i5-5257U Mac OS上使用GCC 7.3.0来编译代码 …

performance x86 assembly

3
推荐指数
1
解决办法
627
查看次数

如何知道汇编代码正在使用 RAM?

我对组装很陌生,这是一个基本问题。

我刚刚听说过使用零字节 RAM的概念。

我已经编译了一个 C++ 代码

g++ -O3 main.cpp -S -o main3.s
Run Code Online (Sandbox Code Playgroud)

main.cpp (源代码)

#include <iostream>
using namespace std;

int main()
{
    int low=10, high=100, i, flag;

    cout << "Prime numbers between " << low << " and " << high << " are: ";

    while (low < high)
    {
        flag = 0;

        for(i = 2; i <= low/2; ++i)
        {
            if(low % i == 0)
            {
                flag = 1;
                break;
            }
        }

        if (flag == 0)
            cout …
Run Code Online (Sandbox Code Playgroud)

assembly

3
推荐指数
1
解决办法
708
查看次数

两个看似相同的汇编代码之间的性能差异

tl; dr:我有两个功能相同的C代码,我用Clang编译(事实上它的C代码并不重要;只有汇编很有意思),IACA告诉我一个应该更快,但我不明白为什么,我的基准测试显示两个代码的性能相同.

我有以下的C代码(忽略#include "iacaMarks.h",IACA_START,IACA_END现在):

ref.c:

#include "iacaMarks.h"
#include <x86intrin.h>

#define AND(a,b)  _mm_and_si128(a,b)
#define OR(a,b)   _mm_or_si128(a,b)
#define XOR(a,b)  _mm_xor_si128(a,b)
#define NOT(a)    _mm_andnot_si128(a,_mm_set1_epi32(-1))

void sbox_ref (__m128i r0,__m128i r1,__m128i r2,__m128i r3,
               __m128i* r5,__m128i* r6,__m128i* r7,__m128i* r8) {
  __m128i r4;

  IACA_START
  r3 = XOR(r3,r0);
  r4 = r1;
  r1 = AND(r1,r3);
  r4 = XOR(r4,r2);
  r1 = XOR(r1,r0);
  r0 = OR(r0,r3);
  r0 = XOR(r0,r4);
  r4 = XOR(r4,r3);
  r3 = XOR(r3,r2);
  r2 = OR(r2,r1);
  r2 = XOR(r2,r4);
  r4 = NOT(r4); …
Run Code Online (Sandbox Code Playgroud)

performance x86 intel micro-optimization iaca

3
推荐指数
1
解决办法
196
查看次数

为什么添加 xorps 指令使这个函数使用 cvtsi2ss 并添加 ~5x 快?

我正在使用 Google Benchmark 优化一个函数,并遇到了我的代码在某些情况下意外变慢的情况。我开始试验它,查看编译后的程序集,并最终想出了一个最小的测试用例来展示这个问题。这是我想出的展示这种放缓的程序集:

    .text
test:
    #xorps  %xmm0, %xmm0
    cvtsi2ss    %edi, %xmm0
    addss   %xmm0, %xmm0
    addss   %xmm0, %xmm0
    addss   %xmm0, %xmm0
    addss   %xmm0, %xmm0
    addss   %xmm0, %xmm0
    addss   %xmm0, %xmm0
    addss   %xmm0, %xmm0
    addss   %xmm0, %xmm0
    retq
    .global test
Run Code Online (Sandbox Code Playgroud)

此函数遵循 GCC/Clang 的 x86-64 函数声明调用约定extern "C" float test(int);注意注释掉的xorps指令。取消注释此指令可显着提高函数的性能。用我的机器有i7-8700K,谷歌基准测试显示的功能测试它,而不xorps指令需要8.54ns(CPU),而功能xorps指令需要1.48ns。我已经在具有不同操作系统、处理器、处理器世代和不同处理器制造商(英特尔和 AMD)的多台计算机上对此进行了测试,它们都表现出类似的性能差异。重复addss指令使减速更加明显(在某种程度上),并且这种减速仍然使用此处的其他指令(例如mulss)或什至混合指令发生,只要它们都%xmm0以某种方式依赖于值。值得指出的是,只调用xorps 每个函数调用会导致性能提升。使用循环对性能进行采样(如 Google Benchmark 所做的那样)和xorps循环外的调用仍然显示出较慢的性能。

由于这是一种专门添加指令可以提高性能的情况,因此这似乎是由 CPU 中的一些非常低级的东西引起的。由于它发生在各种 CPU …

sse x86-64 cpu-architecture clang microbenchmark

3
推荐指数
1
解决办法
167
查看次数