此循环在英特尔Conroe/Merom上每3个周期运行一次,imul
按预期方式在吞吐量方面存在瓶颈.但是在Haswell/Skylake上,它每11个循环运行一次,显然是因为setnz al
它依赖于最后一个循环imul
.
; synthetic micro-benchmark to test partial-register renaming
mov ecx, 1000000000
.loop: ; do{
imul eax, eax ; a dep chain with high latency but also high throughput
imul eax, eax
imul eax, eax
dec ecx ; set ZF, independent of old ZF. (Use sub ecx,1 on Silvermont/KNL or P4)
setnz al ; ****** Does this depend on RAX as well as ZF?
movzx eax, al
jnz .loop ; }while(ecx);
Run Code Online (Sandbox Code Playgroud)
如果setnz al …
我目前正在尝试了解 x86_64(特别是我的 Intel(R) Core(TM) i3-8145U CPU @ 2.10GHz 处理器)上某些循环的性能属性。具体来说,在循环体内部添加一个额外的读取内存指令几乎可以使性能翻倍,而细节并不是特别重要。
我一直在使用一个测试程序,它由两个主要部分组成:一个测试循环和一个被测函数。测试循环运行被测函数 2 32次,一次将每个有符号的 32 位整数作为参数(按从INT_MIN
到 的顺序INT_MAX
)。被测函数(名为body
)是一个小函数,用于检查是否使用预期参数调用它,否则将错误记录在全局变量中。测试程序涉及的内存量足够小,所有东西都可能适合 L1 缓存。
为了消除可能由编译器行为引起的任何速度差异,我用汇编语言编写了两个有问题的函数(我clang
用作汇编程序),并被迫从固定地址(这种测试循环的性能通常受与对齐或缓存相关的影响所支配,因此使用固定地址将消除任何与更改无关的对齐效果或缓存效果)。
这是反汇编的测试循环(它需要函数的地址在 中循环%rdi
):
401300: 53 push %rbx
401301: 55 push %rbp
401302: 51 push %rcx
401303: 48 89 fd mov %rdi,%rbp
401306: bb 00 00 00 80 mov $0x80000000,%ebx
loop:
40130b: 89 df mov %ebx,%edi
40130d: ff d5 callq *%rbp
40130f: 83 c3 01 add $0x1,%ebx
401312: 71 f7 jno 40130b <loop> …
Run Code Online (Sandbox Code Playgroud) 使用以下代码是否存在任何执行速度差异:
cmp al, 0
je done
Run Code Online (Sandbox Code Playgroud)
以下内容:
or al, al
jz done
Run Code Online (Sandbox Code Playgroud)
我知道JE和JZ指令是相同的,并且使用OR可以提供一个字节的大小改进.但是,我也关心代码速度.逻辑运算符似乎比SUB或CMP更快,但我只是想确定.这可能是规模和速度之间的权衡,或双赢(当然代码将更加不透明).
我正在阅读http://www.realworldtech.com/sandy-bridge/,我在理解一些问题时面临一些问题:
专用堆栈指针跟踪器也存在于Sandy Bridge中并重命名堆栈指针,消除了串行依赖性并删除了多个uop.
什么是dedicated stack pointer tracker
实际?
对于Sandy Bridge(和P4),英特尔仍然使用术语ROB.但重要的是要理解,在这种情况下,它只引用了飞行中uops的状态数组
事实上它意味着什么?请说清楚.
我编写了可以编译的汇编代码:
as power.s -o power.o
Run Code Online (Sandbox Code Playgroud)
当我链接power.o目标文件时出现问题:
ld power.o -o power
Run Code Online (Sandbox Code Playgroud)
为了在64位操作系统(Ubuntu 14.04)上运行,我.code32
在power.s
文件的开头添加了,但是我仍然得到错误:
分段故障(核心转储)
power.s
:
.code32
.section .data
.section .text
.global _start
_start:
pushl $3
pushl $2
call power
addl $8, %esp
pushl %eax
pushl $2
pushl $5
call power
addl $8, %esp
popl %ebx
addl %eax, %ebx
movl $1, %eax
int $0x80
.type power, @function
power:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl 8(%ebp), %ebx
movl 12(%ebp), %ecx
movl %ebx, -4(%ebp)
power_loop_start:
cmpl …
Run Code Online (Sandbox Code Playgroud) 如果负载与两个早期存储重叠(并且负载未完全包含在最早的存储中),现代Intel或AMD x86实现是否可以从两个存储转发以满足负载?
例如,请考虑以下顺序:
mov [rdx + 0], eax
mov [rdx + 2], eax
mov ax, [rdx + 1]
Run Code Online (Sandbox Code Playgroud)
最后的2字节加载从前一个存储区获取其第二个字节,但是它之前的存储区的第一个字节.这个负载可以存储转发,还是需要等到两个先前的存储都提交给L1?
请注意,通过存储转发,我包括任何可以满足仍然存储在缓冲区中的存储的读取的机制,而不是等待它们提交到L1,即使它是一个比最好的情况"转发"更慢的路径.单店"案例.
显然,现代处理器可以判断您是否做了一些愚蠢的事情,例如将寄存器移动到自身 ( mov %eax, %eax
) 并对其进行优化。为了验证该声明,我运行了以下程序:
#include <stdio.h>
#include <time.h>
static inline void f1() {
for (int i = 0; i < 100000000; i++)
__asm__(
"mov %eax, %eax;"
"nop;"
);
}
static inline void f2() {
for (int i = 0; i < 100000000; i++)
__asm__(
"nop;"
);
}
static inline void f3() {
for (int i = 0; i < 100000000; i++)
__asm__(
"mov %ebx, %eax;"
"nop;"
);
}
int main() {
int NRUNS = 10;
clock_t …
Run Code Online (Sandbox Code Playgroud) 我有一个带有4个HT内核(8个逻辑CPU)的Intel CPU,并构建了两个简单的进程。
第一个:
int main()
{
for(int i=0;i<1000000;++i)
for(int j=0;j<100000;++j);
}
Run Code Online (Sandbox Code Playgroud)
第二个:
int main()
{
while(1);
}
Run Code Online (Sandbox Code Playgroud)
两者都编译时gcc
没有特殊选项。(即默认值为-O0
:无优化调试模式,将变量保留在内存中而不是寄存器中。)
当我在第一个逻辑CPU(CPU0)上运行第一个时,并且当其他逻辑CPU的负载费用接近0%时,此第一个进程的执行时间为:
real 2m42,625s
user 2m42,485s
sys 0m0,070s
Run Code Online (Sandbox Code Playgroud)
但是,当我在CPU4上运行第二个进程(无限循环)时(CPU0和CPU4在同一内核上,但不在同一硬件线程上),第一个进程的执行时间为
real 2m25,412s
user 2m25,291s
sys 0m0,047s
Run Code Online (Sandbox Code Playgroud)
我期望更长的时间,因为在同一核心上有两个进程,而不是只有一个。但这实际上更快。为什么会这样?
编辑:P状态驱动程序是intel_pstate。使用来固定C状态processor.max_cstate=1 intel_idle.max_cstate=0
。将调速器设置为性能(cpupower frequency-set -g performance
),禁用涡轮增压(cat /sys/devices/system/cpu/intel_pstate/no_turbo
给出1)
我正在努力尝试使用枚举和大量的宏观魔法来实现vtable的替代品,这种魔法真的开始让我的大脑混乱.我开始认为我没有走正确的道路,因为代码变得更加丑陋和丑陋,并且无论如何都不适合生产.
如何使用最少量的重定向/操作实现以下代码的模式?
它必须在标准的c ++中完成,最多17个.
class A{
virtual void Update() = 0; // A is so pure *¬*
};
class B: public A
{
override void Update() final
{
// DO B STUFF
}
}
class C: public A
{
override void Update() final
{
// DO C STUFF
}
}
// class...
int main()
{
std::vector<A*> vecA{};
// Insert instances of B, C, ..., into vecA
for(auto a: vecA) // This for will be inside a main loop
a->Update(); // …
Run Code Online (Sandbox Code Playgroud) 我发现了一个有趣的现象:
#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来编译代码 …