C++ Valgrind输出和rdtsc不一致…为什么会这样?
我正在测试库中几个函数的延迟。为了做到这一点,我在进入和退出时使用rdtsc(),跟踪结果rdtsc值、运行的最小值、最大值和调用次数(以获得平均值)。当我查看输出图时,我看到平均约100个周期,但峰值约20000个周期或类似的干扰(这似乎比函数中3或4个分支的简单分支预测失误严重得多)。我运行cachegrind,得到如下输出:C++ Valgrind输出和rdtsc不一致…为什么会这样?,c++,optimization,valgrind,C++,Optimization,Valgrind,我正在测试库中几个函数的延迟。为了做到这一点,我在进入和退出时使用rdtsc(),跟踪结果rdtsc值、运行的最小值、最大值和调用次数(以获得平均值)。当我查看输出图时,我看到平均约100个周期,但峰值约20000个周期或类似的干扰(这似乎比函数中3或4个分支的简单分支预测失误严重得多)。我运行cachegrind,得到如下输出: ==14038== ==14038== I refs: 2,260,149,383 ==14038== I1 misses: 10
==14038==
==14038== I refs: 2,260,149,383
==14038== I1 misses: 10,408
==14038== LLi misses: 3,978
==14038== I1 miss rate: 0.00%
==14038== LLi miss rate: 0.00%
==14038==
==14038== D refs: 1,100,962,403 (773,471,444 rd + 327,490,959 wr)
==14038== D1 misses: 26,419 ( 13,447 rd + 12,972 wr)
==14038== LLd misses: 15,446 ( 5,701 rd + 9,745 wr)
==14038== D1 miss rate: 0.0% ( 0.0% + 0.0% )
==14038== LLd miss rate: 0.0% ( 0.0% + 0.0% )
==14038==
==14038== LL refs: 36,827 ( 23,855 rd + 12,972 wr)
==14038== LL misses: 19,424 ( 9,679 rd + 9,745 wr)
==14038== LL miss rate: 0.0% ( 0.0% + 0.0% )
==14038==
==14038== Branches: 327,248,773 (297,539,058 cond + 29,709,715 ind)
==14038== Mispredicts: 980,262 ( 978,639 cond + 1,623 ind)
==14038== Mispred rate: 0.2% ( 0.3% + 0.0% )
if(memberVarBool_)
{
memberVarPtr->smallFuncWithThreeIntAssignsAndstdmax;
}
哪里的预测失误率和分支未命中率如此之低,这让我想知道到底发生了什么。我怎么可能经常看到20K周期的高延迟测量?我还可以做些什么来解开这个谜?可能是什么
事实上,令人难以置信的是,其中一个rdtsc测量值仅包含以下内容:
==14038==
==14038== I refs: 2,260,149,383
==14038== I1 misses: 10,408
==14038== LLi misses: 3,978
==14038== I1 miss rate: 0.00%
==14038== LLi miss rate: 0.00%
==14038==
==14038== D refs: 1,100,962,403 (773,471,444 rd + 327,490,959 wr)
==14038== D1 misses: 26,419 ( 13,447 rd + 12,972 wr)
==14038== LLd misses: 15,446 ( 5,701 rd + 9,745 wr)
==14038== D1 miss rate: 0.0% ( 0.0% + 0.0% )
==14038== LLd miss rate: 0.0% ( 0.0% + 0.0% )
==14038==
==14038== LL refs: 36,827 ( 23,855 rd + 12,972 wr)
==14038== LL misses: 19,424 ( 9,679 rd + 9,745 wr)
==14038== LL miss rate: 0.0% ( 0.0% + 0.0% )
==14038==
==14038== Branches: 327,248,773 (297,539,058 cond + 29,709,715 ind)
==14038== Mispredicts: 980,262 ( 978,639 cond + 1,623 ind)
==14038== Mispred rate: 0.2% ( 0.3% + 0.0% )
if(memberVarBool_)
{
memberVarPtr->smallFuncWithThreeIntAssignsAndstdmax;
}
这家伙向我展示了很多“25”个周期的东西,这很有意义,但也有很多关于2000个周期的例子
更新:我刚刚改用gettimeofday以纳秒为单位测量延迟,希望避免rdtsc特有的问题,但仍然看到相同的东西……有没有办法在我的测量中避免抢占和外部或进程影响?如何确保操作系统不会在两个任务/进程之间安排另一个任务/进程调用rdtsc()?如何防止在对rdtsc()的两次调用之间发生硬件中断
这两种情况都会导致两个读数之间的差异出现峰值。如何确保操作系统不会在两次调用rdtsc()之间安排另一个任务/进程?如何防止在对rdtsc()的两次调用之间发生硬件中断
这两种情况都会导致两个读数之间的差异出现峰值。如果保留原始样本,可以绘制它们的图表,忽略异常值,或者取中值而不是平均值。顺便说一句,还有抢占——rdtsc可能误报时间间隔的另一个原因是线程移动内核:每个内核都有自己的TSC寄存器,在许多框中,它们在任何时间点都没有同步到相同的值。将流程固定到特定的核心可以有所帮助。您可能需要成为root用户才能禁用硬件中断,我不确定在用户进程上下文中是如何实现的
另外,名义上返回纳秒并不意味着实际返回纳秒:许多这样的函数会随着较慢的滴答声驱动程序跳跃数亿纳秒;对函数的重复调用将返回相同的值,直到它再次跳转。如果保留原始样本,则可以绘制它们的图形并忽略异常值,或者取中值而不是平均值/平均值。顺便说一句,还有抢占——rdtsc可能误报时间间隔的另一个原因是线程移动内核:每个内核都有自己的TSC寄存器,在许多框中,它们在任何时间点都没有同步到相同的值。将流程固定到特定的核心可以有所帮助。您可能需要成为root用户才能禁用硬件中断,我不确定在用户进程上下文中是如何实现的
另外,名义上返回纳秒并不意味着实际返回纳秒:许多这样的函数会随着较慢的滴答声驱动程序跳跃数亿纳秒;重复调用该函数将返回相同的值,直到它再次跳转。您是否在实时操作系统上运行?有很多事情可能会中断您的进程。您的进程是否曾被抢占或进行过系统调用?@Chad,我将尝试使用ulimit-r99运行。但我想排除代码本身的实际低效或问题。@Plasmah我运行的代码段没有系统调用…不确定程序的抢占,但这是否是罪魁祸首?@PalaceChan:如果您的程序被抢占并且没有安排100000个周期,然后你的计时将显示那100000个周期。你是在实时操作系统上运行的吗?有很多事情可能会中断您的进程。您的进程是否曾被抢占或进行过系统调用?@Chad,我将尝试使用ulimit-r99运行。但我想排除代码本身的实际低效或问题。@Plasmah我运行的代码段没有系统调用…不确定程序的抢占,但这是否是罪魁祸首?@PalaceChan:如果您的程序被抢占并且没有安排100000个周期,然后你的计时将显示那100000个循环..使用ulimit-R99运行会有助于防止这种情况吗?或者我该如何归因于此或避免此问题?使用ulimit-r99运行是否有助于防止此问题?或者我怎样才能归因于这个或者避免这个?有趣的是,在它再次跳转之前,这是关于同一个值的什么?我在纳秒的时候观察到了相当多的重复值!非常具体的数量,比如1000。我之所以关注最大值,是因为我担心它们看起来如此频繁(根据我开始质疑的“计时数据…”…ulimit-R99是否保证没有先发制人?有没有一种方法可以在非常低的延迟下测量“用户时间”,我可以研究吗?@PalaceChan:这正是问题所在——如果你在一个紧循环中调用一个操作系统计时函数,你会多次得到完全相同的值,然后它会以实际更新周期的倍数跳跃(通常乘数为1,但如果出现线程抢占、硬件中断等情况,则乘数可能会更大)。如果您确实需要了解分支预测失误、缓存线暂停等的成本,则最大值非常重要。人们通常认为,当这对他们的总体程序吞吐量无关紧要时,他们会这样做,但您可能会这样做;-)(
ulimit-r
本身不会有帮助。。。您需要将操作系统设置为实时支持,并使应用程序请求具有更高的优先级。“用户”