我在某处读到x86指令中的有效地址(如LEA指令中)由"EU"计算.什么是欧盟?计算有效地址究竟涉及什么?
我只学习了MC68k指令集(UC博尔德首先教这个),我找不到一个好的x86网页,通过网络搜索.
首先,我在 IvyBridge 上进行了以下设置,我将在注释位置插入测量有效负载代码。前 8 个字节buf存储buf自身的地址,我用它来创建循环携带依赖:
section .bss
align 64
buf: resb 64
section .text
global _start
_start:
mov rcx, 1000000000
mov qword [buf], buf
mov rax, buf
loop:
; I will insert payload here
; as is described below
dec rcx
jne loop
xor rdi, rdi
mov rax, 60
syscall
Run Code Online (Sandbox Code Playgroud)
我插入到有效载荷位置:
mov qword [rax+8], 8
mov rax, [rax]
Run Code Online (Sandbox Code Playgroud)
perf显示循环为 5.4c/iter。有点理解,因为L1d延迟是4个周期。
我颠倒了这两条指令的顺序:
mov rax, [rax]
mov qword [rax+8], 8
Run Code Online (Sandbox Code Playgroud)
结果突然变成9c/iter。我不明白为什么。因为下一次迭代的第一条指令不依赖于当前迭代的第二条指令,所以这个设置应该和 case 1 没有区别。
我也用IACA工具对这两种情况进行静态分析,但是该工具不可靠,因为两种情况预测的结果都是5.71c/iter,与实验相矛盾。 …
x86 assembly micro-optimization microbenchmark micro-architecture
我已经阅读了很多关于内存排序的文章,并且所有这些文章都只说CPU重新加载和存储.
CPU(我对x86 CPU特别感兴趣)是否仅重新排序加载和存储,并且不重新排序它具有的其余指令?
#include <stdio.h>
#include <iostream>
#include <string>
#include <chrono>
#include <memory>
#include <cstdlib>
#include <cstdint>
#include <cstring>
#include <immintrin.h>
using namespace std;
const int p[9] = {1, 10, 100,
1000, 10000, 100000,
1000000, 10000000, 100000000};
class MyTimer {
private:
std::chrono::time_point<std::chrono::steady_clock> starter;
public:
void startCounter() {
starter = std::chrono::steady_clock::now();
}
int64_t getCounterNs() {
return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now() - starter).count();
}
};
int convert1(const char *a) {
int res = 0;
for (int i=0; i<9; i++) res = res * 10 + a[i] - 48; …Run Code Online (Sandbox Code Playgroud) 在答案中,我已经声明未对齐访问的速度与对齐访问的速度几乎相同(在x86/x86_64上).我没有任何数字来支持这个陈述,所以我已经为它创建了一个基准.
你看到这个基准测试有什么缺陷吗?你可以改进它(我的意思是,增加GB /秒,所以它更好地反映了真相)?
#include <sys/time.h>
#include <stdio.h>
template <int N>
__attribute__((noinline))
void loop32(const char *v) {
for (int i=0; i<N; i+=160) {
__asm__ ("mov (%0), %%eax" : : "r"(v) :"eax");
__asm__ ("mov 0x04(%0), %%eax" : : "r"(v) :"eax");
__asm__ ("mov 0x08(%0), %%eax" : : "r"(v) :"eax");
__asm__ ("mov 0x0c(%0), %%eax" : : "r"(v) :"eax");
__asm__ ("mov 0x10(%0), %%eax" : : "r"(v) :"eax");
__asm__ ("mov 0x14(%0), %%eax" : : "r"(v) :"eax");
__asm__ ("mov 0x18(%0), %%eax" : : "r"(v) :"eax"); …Run Code Online (Sandbox Code Playgroud) 在最近的英特尔ISA文档中,该lfence指令被定义为序列化指令流(防止指令流无序执行).特别是,该指令的描述包括以下行:
具体来说,LFENCE不会执行,直到所有先前的指令在本地完成,并且在LFENCE完成之前没有后续指令开始执行.
请注意,这适用于所有的指令,不只是内存加载指令,使得lfence 更多的不仅仅是一个存储排序防护.
虽然这现在出现在ISA文档中,但不清楚它是否是"架构",即所有x86实现都遵守,或者它是否特定于Intel.特别是AMD处理器是否也将lfence序列化为指令流?
因此还有很多问题,例如https://mirrors.edge.kernel.org/pub/linux/kernel/people/paulmck/perfbook/perfbook.2018.12.08a.pdf和Preshing的文章如https:/ /preshing.com/20120710/memory-barriers-are-like-source-control-operations/及其整个系列文章就不同的障碍类型提供的排序和可见性保证方面抽象地讨论了内存排序。我的问题是,如何在x86和ARM微体系结构上实现这些障碍和内存排序语义?
对于商店-商店壁垒,好像在x86上,商店缓冲区保持商店的程序顺序并将它们提交到L1D(因此使它们以相同的顺序在全局可见)。如果存储缓冲区未排序,即未按程序顺序维护它们,那么如何实现存储障碍?它只是以这样的方式“标记”存储缓冲区,即在屏障提交之前将存储提交到缓存一致性域,然后在屏障之后提交?还是存储屏障实际上刷新了存储缓冲区并暂停了所有指令,直到刷新完成?可以同时实现吗?
对于负载障碍,如何防止负载重新排序?很难相信x86将按顺序执行所有加载!我假设加载可以乱序执行,但是可以按顺序提交/退出。如果是这样,如果一个cpu在2个不同的位置执行2次加载,那么一个加载如何确保它从T100中得到一个值,而下一个加载在T100上或之后得到它?如果第一个负载未命中高速缓存并正在等待数据,而第二个负载命中并获取其值,该怎么办。当负载1获得其值时,如何确保它获得的值不是来自该负载2的值的较新商店?如果负载可以无序执行,如何检测到违反内存排序的情况?
类似地,如何实现负载存储屏障(在x86的所有负载中都是隐含的)以及如何实现存储负载屏障(例如mfence)?即dmb ld / st和dmb指令在ARM上是如何微体系结构的?每个负载和每个存储区以及mfence指令在x86上如何进行微体系结构,以确保内存排序?
x86 x86-64 cpu-architecture memory-barriers micro-architecture
不同的进程可以同时运行RDTSC吗?还是这是只有一个内核可以同时运行的资源?TSC位于每个内核中(至少您可以针对每个内核分别进行调整),因此应该可行。但是超级跑步呢?
我该如何测试?
任务是将数组 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 …
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) x86 ×8
assembly ×3
intel ×3
performance ×3
x86-64 ×3
c++ ×2
amd ×1
avx ×1
avx512 ×1
benchmarking ×1
dot-product ×1
iaca ×1
multicore ×1
optimization ×1
rdtsc ×1
sse ×1