据我所知,相对于rdtsc和rdtscp指令,处理器在运行时顺序上的主要区别在于执行是否要等到所有先前的指令都在本地执行后才能执行。
换句话说,这意味着lfence + rdtsc = rdtscp,因为在rdtsc指令之前的lfence使得在本地所有前一条指令完成后将执行以下rdtsc。
但是,我已经看到一些示例代码,这些示例代码在测量开始时使用rdtsc,在测量结束时使用rdtscp。使用两个rdtsc和rdtsc + rdtscp之间有什么区别吗?
lfence
rdtsc
lfence
...
...
...
lfence
rdtsc
lfence
rdtsc
lfence
...
...
...
rdtscp
我不确定这个答案是正确的。我实际上已经推测了一点,但我并不擅长。带着盐撒它,直到有更多专家来临(嗯,我们知道他们是谁)。
我认为rdtscp
是一条指令,而lfence + rdtsc
是两条指令。由于rdtscp
比lfence + rdtsc
产生更多的微指令,因此仅在前端的最初阶段就节省了资源。但是,如果在rdtscp
之前(或同时)读取TSC(在IA32_TSC_AUX
内),则rdtscp
可以避免配置额外的lfence
。因为它引入了额外的指令(除了用于读取TSC的绝对必要的指令),而且由于无论如何都没有对第一个lfence
进行概要分析之前的rdtsc
,所以似乎不使用rdtscp
作为第一个TSC读取指令似乎是很好的。 >
与Andreas Abel pointed out相同,您仍需要在最后一个lfence
之后加上一个rdtsc(p)
,因为没有按顺序排序。后续说明:
lfence lfence
rdtsc -- VALID --> B
B rdtsc
rdtscp -- VALID --> B
B rdtscp
关于rdtscp
的使用,对我来说,将其视为紧凑的lfence + rdtsc
似乎是正确的。手册对这两个说明使用了不同的术语(例如,“本地完成”与“全局可见”的负载),但所描述的行为似乎是相同的。在此答案的其余部分中,我假设是这样。
但是rdtscp
是一条指令,而lfence + rdtscp
是两条指令,使lfence
成为分析代码的一部分。承认lfence
就后端执行资源而言应该是轻量级的(只是一个标记),它仍然占用前端资源(两个uops?)和ROB中的一个插槽。由于rdtscp
具有读取IA32_TSC_AUX
的能力,因此被解码为更多的微指令,因此,尽管它节省了前端(部分)资源,但它占用了后端更多的资源。如果首先(或同时)使用处理器ID读取TSC,则这些额外的内容仅与后续代码有关。这可能是为什么在基准测试结束时而不是在基准测试开始时使用它的原因(额外的uoop会影响代码)。这足以使一些微体系结构基准偏差/使之复杂化。
您无法避免lfence
之后
rdtsc(p)
,但是您可以使用rdtscp
来避免一个之前。这对于第一个rdtsc
似乎是不必要的,因为无论如何都不会分析前面的lfence
。 最后使用rdtscp
的另一个原因是(根据Intel的意图)是要检测到向另一个CPU的迁移(这就是为什么它也自动加载IA32_TSC_AUX
的原因,因此,在配置文件代码的末尾您可能要检查代码是否尚未调度到另一个CPU。
用户模式软件可以使用RDTSCP来检测在连续读取TSC之间是否发生了CPU迁移。
当然,这需要先读取
IA32_TSC_AUX
(以便进行比较),因此,在性能分析代码之前应先读取rdpid
或rdtscp
。如果负担不起不使用ecx
,则第一个rdtsc
也可以是rdtscp
(但请参见上文),否则(而不是在配置文件代码中存储处理器ID时)可以使用rdpid
首先(因此,在已分析的代码周围有rdtsc + rdtscp
对)。
这对ABA problem开放,因此我认为Intel在这方面没有强项(除非我们限制自己的编码时间短到最多只能重新安排一次)。