【问题标题】:Is there any difference in between (rdtsc + lfence + rdtsc) and (rdtsc + rdtscp) in measuring execution time?(rdtsc + lfence + rdtsc) 和 (rdtsc + rdtscp) 在测量执行时间方面有什么区别吗?
【发布时间】:2020-05-02 16:52:27
【问题描述】:

据我所知,处理器中运行时排序与 rdtsc 和 rdtscp 指令的主要区别在于执行是否等待直到所有先前的指令都在本地执行。

换句话说,就是lfence + rdtsc = rdtscp,因为rdtsc指令前面的lfence使得后面的rdtsc在所有前一条指令在本地完成后执行。

但是,我看到一些示例代码在测量开始时使用 rdtsc,最后使用 rdtscp。使用两个 rdtsc 和 rdtsc + rdtscp 有什么区别吗?

    lfence
    rdtsc
    lfence
    ...
    ...
    ...
    lfence
    rdtsc
    lfence
    lfence
    rdtsc
    lfence
    ...
    ...
    ...
    rdtscp
    lfence

【问题讨论】:

  • 为了得到有意义的结果,最后一个 rdtsc(p) 之后还应该有一个 lfence。
  • 是的,您可以阻止最后一个 rdtsc(p) 指令按照以下说明重新排序。

标签: assembly x86 cpu-architecture microbenchmark rdtsc


【解决方案1】:

TL;DR

rdtscplfence/rdtsc 在 Intel 处理器上具有完全相同的上游序列化属性。在具有调度序列化lfence 的 AMD 处理器上,两个序列也具有相同的上游序列化属性。对于后面的指令,lfence/rdtsc 序列中的rdtsc 可以与后面的指令同时被调度执行。如果您还想精确地为这些后面的指令计时,那么这种行为可能是不可取的。这通常不是问题,因为只要不存在结构性危害,保留站调度程序就会优先考虑较旧的微指令进行调度。在lfence 退休后,rdtsc 微指令将是 RS 中最古老的,可能没有结构性危害,因此它们将立即被派出(可能与一些后来的微指令一起)。您也可以在rdtsc 之后添加lfence

英特尔手册 V2 对rdtscp (强调我的)有以下说明:

RDTSCP 指令不是序列化指令,但它确实 等到所有先前的指令都已执行并且所有先前的指令 负载是全局可见的。但它不等待以前的商店 为了全局可见,后续指令可能会在执行读取操作之前开始执行

这里的“读取操作”部分是指读取时间戳计数器。这表明rdtscp 在内部像lfence 一样工作,然后是rdtsc + 阅读IA32_TSC_AUX。也就是说,首先执行lfence,然后执行从寄存器中读取的两次(可能同时执行)。

在大多数支持这些指令的 Intel 和 AMD 处理器上,lfence/rdtsc 的微指令数量比rdtscp 略多。 Agner's tables 中提到的lfence uops 的数量是针对lfence 指令背靠背执行的情况,这使得lfence 看起来被解码为较少数量的 uops(1 或 2 ) 而不是单个lfence 实际解码为(5 或 6 微秒)。通常,lfence 不使用其他背靠背lfences。这就是lfence/rdtscrdtscp 包含更多微指令的原因。 Agner 的表格还显示,在某些处理器上,rdtscrdtscp 具有相同数量的微指令,我不确定这是否正确。 rdtscprdtsc 拥有一个或多个微指令更有意义。也就是说,延迟可能比微指令数量的差异更重要,因为这会直接影响测量开销。

在可移植性方面,rdtscrdtscp 更老; rdtsc 最初在 Pentium 处理器上得到支持,而支持 rdtscp 的第一批处理器于 2005-2006 年发布(参见:What is the gcc cpu-type that includes support for RDTSCP?)。但目前使用的大多数 Intel 和 AMD 处理器都支持rdtscp。比较两个序列的另一个维度是,rdtscprdtsc 多污染一个寄存器(即ECX)。

总而言之,如果您不关心阅读IA32_TSC_AUX MSR,那么您应该选择其中一个并没有什么特别大的理由。我会在不支持它的处理器上使用rdtscp 并回退到lfence/rdtsc(或lfence/rdtsc/lfence)。如果您想要最大的计时精度,请使用Memory latency measurement with time stamp counter 中讨论的方法。


作为Andreas Abel pointed out,您仍然需要在最后一个rdtsc(p) 之后添加lfence,因为它不是按w.r.t 排序的。后续说明:

lfence                    lfence
rdtsc      -- ALLOWED --> B
B                         rdtsc

rdtscp     -- ALLOWED --> B
B                         rdtscp

这也是addressed in the manuals


关于rdtscp的使用,我认为它是一个紧凑的lfence + rdtsc似乎是正确的。
手册对两条指令使用不同的术语(例如,“在本地完成”与“全局可见”的负载),但描述的行为似乎是相同的。
我在这个答案的其余部分假设是这样。

但是rdtscp 是一条指令,而lfence + rdtscp 是两条,这使得lfence 成为配置代码的一部分。
尽管lfence 在后端执行资源方面应该是轻量级的(它只是一个标记),但它仍然占用前端资源(两个微指令?)和 ROB 中的一个插槽。
rdtscp 被解码为由于它能够读取IA32_TSC_AUX,所以它的uop数量更多,因此在节省前端(部分)资源的同时,它占用了更多的后端。
如果 TSC 的读取首先(或同时)使用处理器 ID 完成,则此额外的微指令仅与后续代码相关。
这可能是为什么它在最后而不是在基准测试开始时使用的原因(额外的微指令会影响代码)。 这足以使一些微架构基准产生偏差/复杂化。

您无法避免 lfence afterrdtsc(p),但您可以通过 rdtscp 避免 before
这对于第一个rdtsc 来说似乎是不必要的,因为前面的lfence 无论如何都没有被分析。


最后使用rdtscp 的另一个原因是它(根据英特尔)旨在检测到不同 CPU 的迁移(这就是为什么它也以原子方式加载IA32_TSC_AUX),所以在配置文件的末尾您可能需要检查代码是否未安排到另一个 CPU。

用户模式软件可以使用 RDTSCP 来检测在连续读取 TSC 之间是否发生了 CPU 迁移。

当然,这需要在之前阅读过IA32_TSC_AUX(以便进行比较),因此在分析代码之前应该有一个rdpidrdtscp
如果可以不使用ecx,则第一个rdtsc 也可以是rdtscp(但见上文),否则(而不是在分析代码中存储处理器ID),可以使用rdpid首先(因此,在分析代码周围有一个 rdtsc + rdtscp 对)。

这对ABA problem 开放,所以我认为英特尔在这方面没有优势(除非我们限制自己的代码足够短,最多可以重新安排一次)。

编辑 正如 PeterCordes 指出的那样,从 经过时间 度量的角度来看,迁移 A->B->A 不是问题,因为参考时钟是相同的。


有关rdtsc(p) 未完全序列化原因的更多信息:Why isn't RDTSC a serializing instruction?

【讨论】:

  • 我认为在定时区域的底部,您确实需要lfence;rdtsc;lfence,或rdtscp;lfence。我不确定为什么在最终的 TSC 读取发生时停止运行以后的指令很重要,但它确实给出了更一致的结果。 (例如Hadi recommended it for measuring cache miss latency)。哦,我想我刚刚理解了您的“有效”箭头图:您正在显示您不想要的 CPU 重新排序 allowed 。不过,CPU 通常会先执行最旧的准备就绪
  • 如果您确实设法在一个定时区域内进行了 ABA 迁移(例如,在第一次迁移后进入用户空间后又中断了一些指令),您仍然可以准确地测量经过的时间,因为您重新查看开始和结束时间的相同时钟。 RDTSCP 可让您检测到明显合理的时间间隔,而实际上您是从两个非同步时钟中减去时间。 (通常 TSC 会在内核之间同步,因为它们都同时上电,并且 CPU 有 constant_tsc / nonstop_tsc。但是软件可以修改 TSC MSR 并使它们不同步。)
  • @BeeOnRope 我认为这意味着“所有早期的序列化,按程序顺序,指令”。
  • @BeeOnRope 也许对“上游”和“下游”序列化的更正确解释可能分别是“不使用较早/较旧的指令重新排序”和“不使用较晚/较年轻的指令重新排序”(都 wrt 程序命令)。 lfence 之后的指令的“下游”序列化最多可以防止并发执行(仍然是一种重新排序的形式,IMO),因为调度程序按程序顺序扫描,因此以后的独立微指令。我不会使用“上游”和“下游”,但它们对我来说仍然有意义。您可能应该 ping HadiBrais 以获得更多亮点。
  • @JaehyukLee 是的,这不准确。我已经更新了那个答案。感谢您指出这一点。
猜你喜欢
  • 1970-01-01
  • 2017-09-16
  • 2015-05-25
  • 2019-10-05
  • 2019-07-08
  • 2012-01-26
  • 1970-01-01
  • 2017-06-30
  • 2016-04-21
相关资源
最近更新 更多