执行两个语句之间的时差不一致

时间:2014-12-26 11:25:45

标签: c++ latency

您能否告诉我为什么以下程序打印的timediff的值通常为4微秒(不同运行的范围为90到1000倍),但有些情况下有时为70或更多微秒(对于不同的运行,在2到10倍的范围内):

#include <iostream>
using namespace std;
#include<sys/time.h>
#define MAXQ 1000000
#define THRDS 3
double GetMicroSecond()
{
    timeval tv;
    gettimeofday (&tv, NULL);
    return (double) (((double)tv.tv_sec * 1000000) + (double)tv.tv_usec);
}

int main()
{
        double timew, timer, timediff;
        bool flagarray[MAXQ];
        int x=0, y=0;
        for(int i=0; i<MAXQ; ++i)
            flagarray[i] = false;
        while(y <MAXQ)
       {
            x++;
            if(x%1000 == 0)
            {
                    timew = GetMicroSecond();
                    flagarray[y++]=true;
                    timer = GetMicroSecond();
                    timediff = timer - timew;
                    if(timediff > THRDS) cout << timer-timew << endl;
            }
       }
}

使用编译:g ++ testlatency.cpp -o testlatency

注意:在我的系统中有12个核心。仅使用系统中运行的此程序检查性能。

4 个答案:

答案 0 :(得分:0)

通常,有许多线程共享少量核心。除非您采取措施确保您的线程不间断地使用核心,否则您无法保证操作系统不会决定在两次呼叫GetMicroSecond()呼叫之间抢占您的线程,并让一些其他线程使用核心。

即使您的代码不间断运行,您尝试计时的行也是:

flagarray[y++]=true;

执行的时间可能比测量代码本身少得多。

答案 1 :(得分:0)

在您的程序执行的同时,现代操作系统内部发生了许多事情。他们中的一些人可能会从你的程序中“窃取”CPU,正如NPE的答案所述。还有一些可以影响时间安排的例子:

  • 设备中断(计时器,硬盘,网络接口等);
  • 访问RAM(缓存)

这些都不容易预测。

如果您在某些微控制器上运行代码,或者使用real time OS,则可以保持一致性。

答案 2 :(得分:0)

  

timew = GetMicroSecond();
      flagarray [Y ++] = TRUE;
      timer = GetMicroSecond();

语句flagarray[y++]=true;在现代计算机上执行将花费不到一微秒如果 flagarray[y++恰好位于1级缓存中。如果该位置在第2级高速缓存中但不在第1级高速缓存中,则该语句将花费更长的时间,如果它在3级高速缓存中但不在1级或2级高速缓存中则更长,并且如果不是1和2级则更长#39; t在任何缓存中。

使timer-timew超过3毫秒的另一件事是当你的程序产生OS时。缓存未命中可导致产量。系统调用也是如此。函数gettimeofday是系统调用。作为一般规则,您应该期望任何系统调用都能产生。


  

注意:在我的系统中有12个核心。仅使用系统中运行的此程序检查性能。

事实并非如此。总有许多其他程序,以及12核计算机上运行的许多其他线程。这些包括操作系统本身(其中包含许多线程),以及许多小守护进程。每当你的程序产生时,操作系统就可以决定暂时暂停你的程序,以便其中一个临时暂停但却要求使用CPU的其他线程。

其中一个守护进程是网络时间协议守护进程(ntpd)。这为你的系统时钟做了各种时髦的小事,使它与原子钟保持接近。在flagarray[y++]=true的连续调用之间只有gettimeofday之类的微小指令,您甚至可能偶尔会看到时间倒退。


在测试时序时,最好在粗略的时间进行时序测量。不要计算不涉及任何函数调用的单个语句。定时循环比定时更好,而不是单独执行循环体的时间。即便如此,由于缓存未命中以及操作系统暂时中止程序的执行,您应该期望时序存在一些差异。

现代基于Unix的系统有更好的计时器(例如,clock_gettime)而不是gettimeofday,它们不受网络时间协议守护程序所做的更改。您应该使用其中一个而不是gettimeofday

答案 3 :(得分:0)

有很多变量可以解释看到的不同时间值。我会更专注于

  • 缓存未命中/填充
  • 计划程序事件
  • 中断

    bool flagarray [MAXQ];

由于您将MAXQ定义为1000000,因此我们假设flagarray占用1MB空间。

您可以根据L1 / L2 D-cache大小计算可能发生的缓存未命中数。然后,您可以关联填充所有L1并开始丢失所需的迭代次数以及与L2相同的迭代次数。操作系统可能会计划您的流程并重新安排它 - 但是,我希望由于您拥有的核心数量不太可能。中断的情况也是如此。空闲系统永远不会完全空闲。您可以选择将您的流程与核心编号相关联,例如通过执行

来表示

taskset 0x<MASK> ./exe并控制其执行。

如果你真的很好奇,我建议你使用&#34; perf&#34;大多数Linux发行版都提供了工具。

你可以做

perf stat -e L1-dcache-loadmisses

perf stat -e LLC-load-misses

一旦你有了这些数字和迭代次数,你就会开始构建一个引起注意滞后的活动的图片。您还可以使用&#34; perf stat&#34;。

监控OS调度程序事件