- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我在NASM中使用RDTSC和RDTSCP测量各种汇编语言指令的机器周期,以帮助优化。
我读了Intel的Gabriele Paoloni撰写的“如何在Intel IA-32和IA-64指令集体系结构上对代码执行时间进行基准测试”(2010年9月)和其他Web资源(其中大多数是C语言中的示例)。
使用下面的代码(从C转换而来),我测试了各种指令,但是RDTSCP在RDX中始终返回零,在RAX中始终返回7。我首先认为7是周期数,但显然并非所有指令都需要7个周期。
rdtsc
cpuid
addsd xmm14,xmm1 ; Instruction to time
rdtscp
cpuid
rdtsc
cpuid
add rcx,rdx ; Instruction to time
rdtscp
cpuid
cpuid
rdtsc
mov [start_time],rax
addsd xmm14,xmm1 ; INSTRUCTION
rdtscp
mov [end_time],rax
cpuid
mov rax,[end_time]
mov rdx,[start_time]
sub rax,rdx
最佳答案
您的第一个代码(导致标题问题)有问题,因为它用EAX,EBX,ECX和EDX中的rdtsc
结果覆盖rdtscp
和cpuid
结果。
使用lfence
代替cpuid
;自从永久性地在Intel上启用了Spectre缓解功能的AMD以来,lfence
将序列化指令流,从而通过rdtsc
完成您想要的操作。
请记住,RDTSC会计算参考周期,而不是内核时钟周期。 Get CPU cycle count?以及有关RDTSC的更多信息。
您的测量间隔内没有cpuid
或lfence
。但是您在测量间隔中确实有rdtscp
。背靠背rdtscp
的速度不是很快,如果您不预热CPU而运行,则64个参考周期听起来是完全合理的。空闲时钟速度通常比参考周期慢很多。 1个参考周期等于或接近“贴纸”频率,例如英特尔CPU上的最大非涡轮持续频率。例如在“ 4GHz” Skylake CPU上为4008 MHz。
这不是您安排单个指令的时间
重要的是在另一条指令可以使用结果之前的等待时间,而不是等待它从无序后端完全退出之前的等待时间。 RDTSC可用于计时一条加载或一条存储指令花费的时间的相对变化,但是开销意味着您不会获得良好的绝对时间。
不过,您可以尝试减少测量开销。例如clflush to invalidate cache line via C function。另请参阅后续文章:Using time stamp counter and clock_gettime for cache miss和Memory latency measurement with time stamp counter。
这就是我通常用来描述短块指令的延迟或吞吐量(以及uops融合和非融合域)的方法。调整使用它的方式来限制延迟(如此处所示),如果您只想测试吞吐量,则不要调整。例如使用%rep
块具有足够的不同寄存器来隐藏等待时间,或在较短的块之后用pxor xmm3, xmm3
打破依赖关系链,让无序的exec发挥其魔力。 (只要您不在前端遇到瓶颈。)
您可能要使用NASM的smartalign软件包或使用YASM,以免将ALIGN指令用于单字节NOP指令。即使在始终支持long-NOP的64位模式下,NASM默认还是真正愚蠢的NOP。
global _start
_start:
mov ecx, 1000000000
; linux static executables start with XMM0..15 already zeroed
align 32 ; just for good measure to avoid uop-cache effects
.loop:
;; LOOP BODY, put whatever you want to time in here
times 4 addsd xmm4, xmm3
dec ecx
jnz .loop
mov eax, 231
xor edi, edi
syscall ; x86-64 Linux sys_exit_group(0)
perf stat
对其进行概要分析,您可以在每次更改源代码时向上箭头键并重新运行:
asm-link
的shell脚本中,以在不进行性能分析时保存键入内容。反汇编功能可确保循环中的内容与配置文件的含义相同,尤其是当您有配置文件时代码中的
%if
内容。如果要在脑海中测试理论时回滚,它也位于配置文件之前的终端上。)
t=testloop; nasm -felf64 -g "$t.asm" && ld "$t.o" -o "$t" && objdump -drwC -Mintel "$t" &&
taskset -c 3 perf stat -etask-clock,context-switches,cpu-migrations,page-faults,cycles,branches,instructions,uops_issued.any,uops_executed.thread -r4 ./"$t"
perf
在辅助列中具有单位缩放的显示错误。已在上游修复,但Arch Linux尚未更新。):
Performance counter stats for './testloop' (4 runs):
4,106.09 msec task-clock # 1.000 CPUs utilized ( +- 0.01% )
17 context-switches # 4.080 M/sec ( +- 5.65% )
0 cpu-migrations # 0.000 K/sec
2 page-faults # 0.487 M/sec
16,012,778,144 cycles # 3900323.504 GHz ( +- 0.01% )
1,001,537,894 branches # 243950284.862 M/sec ( +- 0.00% )
6,008,071,198 instructions # 0.38 insn per cycle ( +- 0.00% )
5,013,366,769 uops_issued.any # 1221134275.667 M/sec ( +- 0.01% )
5,013,217,655 uops_executed.thread # 1221097955.182 M/sec ( +- 0.01% )
4.106283 +- 0.000536 seconds time elapsed ( +- 0.01% )
addsd
具有4个周期的延迟,吞吐量为0.5c。 (即,如果延迟不是瓶颈,则每个时钟2个)。请参见
https://agner.org/optimize/,
https://uops.info/和
http://instlatx64.atw.hu/。
addsd
= 4个周期的
addsd
延迟,即使对于这个包含一点点启动开销的测试,Agner Fog的4个周期的测量结果也要好于100分之一。并中断开销。
:u
(例如
instructions:u
)添加到性能中,甚至只会计算用户空间指令,不包括在中断处理程序中运行的指令。我通常不这样做,因此我可以将其作为挂钟时间说明的一部分。但是,如果这样做,
cycles:u
可以与
instructions:u
非常匹配。
-r4
将其运行4次并取平均值,这对于查看是否存在大量运行差异很有用,而不是仅从ECX中的较高值中获得一个平均值。
关于optimization - NASM中的RDTSCP始终返回相同的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54621381/
我很困惑 rdtscp在多核环境中单调递增。根据文档:__rdtscp , rdtscp似乎是基于处理器的指令,可以防止围绕调用重新排序指令。 The processor monotonically
这个问题在这里已经有了答案: Which inline assembly code is correct for rdtscp? (2 个答案) 关闭 5 年前。 我正在使用 rdtscp 指令读取
一些新的 Intel 处理器同时具有 RDTSC 和 RDTSCP 指令,而大多数旧处理器只有 RDTSC 指令。 在使用 C/C++ 编写代码时,如何在编译时检测正在使用的体系结构是否具有 RDTS
免责声明:言语无法描述我对 AT&T 风格语法的厌恶程度 我遇到了一个问题,希望是由寄存器破坏引起的。如果没有,我就有一个更大的问题。 我使用的第一个版本是 static unsigned long
我正在尝试编写一个程序来测量上下文切换。我经历过这个 Intel's manual关于 rdtsc + rdtscp 指令。 现在,我想在上下文切换中使用这些时间戳指令。我的总体框架如下: // in
我有这个代码 #include #include unsigned long long rdtscp(unsigned int* aux) { // For IA32 unsign
我正在做一些 Linux 内核计时,特别是在中断处理路径中。我一直在使用 RDTSC 进行计时,但我最近了解到它不一定准确,因为指令可能会乱序发生。 然后我尝试了: RDTSC + CPUID(此处为
我正在尝试使用 rdtscp 为子程序计时。这是我的程序: ; Setting up time rdtscp ; Getting time push rax
我使用 RDTSCP 来替换 LFENCE;RDTSC 序列,并获取处理器 ID,以便我知道在线程重新调度到另一个 CPU 后何时比较 TSC 值。 为了确保我不会在太旧的计算机上运行 RDTSCP,
我有一段代码在 MSVC 2012 上运行: #include #include UINT64 gettime() { try { unsigned int ui; retu
假设我们正在尝试使用 tsc 进行性能监控,并且我们希望防止指令重新排序。 这些是我们的选择: 1: rdtscp 是一个序列化调用。它可以防止围绕对 rdtscp 的调用进行重新排序。 __asm_
据我所知,相对于rdtsc和rdtscp指令,处理器中的运行时排序的主要区别在于执行是否要等到所有先前的指令都在本地执行后才能执行。 换句话说,这意味着lfence + rdtsc = rdtscp,
我是一名优秀的程序员,十分优秀!