我正在摆弄 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) 我试图矢量化循环,计算大浮点矢量的点积.我正在并行计算它,利用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()的示例和解释,何时使用什么地址和什么命中.你可以帮忙吗?
我看到 Duff 的设备只是在 C 中进行循环展开。
https://en.wikipedia.org/wiki/Duff%27s_device
我不知道为什么它现在仍然有用。编译器不是应该足够聪明来进行循环展开吗?
我正在寻找相关的性能指标来基准测试和优化我的C / C ++代码。例如,虚拟内存使用率是一个简单但有效的指标,但是我知道有些虚拟内存使用情况更为专业,可以帮助优化特定域:高速缓存命中/未命中,上下文切换等。
我相信这里是一个列出性能指标,衡量指标以及如何衡量指标的好地方,以帮助希望开始优化程序的人员知道从何开始。
我需要找到比最后一个滚动最大峰值低 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) 任务是将数组 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 …
我发现了一个有趣的现象:
#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来编译代码 …
我对组装很陌生,这是一个基本问题。
我刚刚听说过使用零字节 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) 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) 我正在使用 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 …
performance ×4
sse ×3
x86 ×3
assembly ×2
c++ ×2
clang ×2
dot-product ×2
avx ×1
avx2 ×1
avx512 ×1
benchmarking ×1
c ×1
caching ×1
cpu ×1
duffs-device ×1
gcc ×1
iaca ×1
intel ×1
optimization ×1
prefetch ×1
profiling ×1
simd ×1
x86-64 ×1