C++函数的执行时间矛盾

Execution time for C++ Functions contradict

本文关键字:矛盾 执行时间 函数 C++      更新时间:2023-10-16

我有一个主函数,它调用两个用户定义的函数。两个函数以不同的方式执行相同的任务(在这种情况下,选择因子为50%的简单选择)(在一个函数中使用if-else,而在另一函数中不使用if-erse)。我测量两个函数的执行时间。

    int main()
    {
     clock_t t;
     period=clock();
     func1();
     period=clock()-period;
     print period
     period=clock();
     func2();
     period=clock()-period;
     print period
   }
   void func1()
   {
    int A[100000],B[100000],in=0;
    for (i=0;i<100000;i++)
    {
      A[i]=i;
    }
    for (i=0;i<100000;i++)
    {
      if(A[i]==3)
      B[in++]=i;
    }
   }

Func2与此类似,只是我用非分支语句替换if。

当我执行程序时,首先调用哪个函数需要更多的时间。在上面的情况下,func1需要更多的时间。如果我先调用func2,然后调用func1,那么func2需要更多的时间。我真的不明白这背后的逻辑。

谁能解释一下吗。

如果Func2除了第二个循环中的分支之外与Func1相同,我的猜测是,对于调用的第一个函数,操作系统必须为堆栈提交页面,而第二个函数只能使用已经提交的页面。

操作系统倾向于只按需提交内存,这样就可以将更多的程序放入物理内存。对于一个新线程,Windows提交(实际上用物理内存页支持虚拟内存地址)可执行文件头中指定的堆栈量。然后,只有当进程接触到页面时,它才会提交堆栈的其他页面。它将继续执行此操作,直到达到指定的保留大小,之后它将生成堆栈溢出异常。Microsoft的link.exe使用的默认值是为每个堆栈保留1MB的虚拟地址空间,并提交一个页面(4kB)。

当进程确实接触到页面时,处理器会尝试在Translation look-aside Buffer中查找虚拟地址。找不到它——TLB"未命中"——因此它将尝试在进程的页表中查找它。页面表将包含一个无效条目,因此它将引发页面错误异常。

操作系统的页面错误处理程序查看页面表条目,并确定它属于线程堆栈,因此它找到一个空的内存页面,修改其页面框架数据库以标记该页面现在属于该进程,修改页面表以指向新页面,然后消除异常。处理器使用出现故障的指令重新启动执行。

处理器异常处理速度较慢。一堆上下文信息被推送到堆栈上,这样处理器就知道返回到哪里,管道停滞,TLB中可能不再有操作系统代码的位置,指令和数据缓存中可能没有操作系统代码或数据。

假设int在编译器上是32位的,那么第一个数组中有400000字节,第二个数组中还有400000字节。第一个循环将生成(可能)98个页面错误以创建第一个阵列,然后第二个循环可能生成另一个错误以将B[0]设置为3。

它还可能取决于编译器、操作系统和编译器选项。对于像这样在堆栈上声明的大数组,一些编译器会在函数的开头生成一个"堆栈探测",以确保堆栈正确提交。Windows要求进程按照正确的顺序逐页提交其堆栈,因此Microsoft的编译器在函数开始时插入对_chkstk函数的调用。这会有意依次从每个堆栈页面读取,以便操作系统提交页面。KB 100775中对此进行了记录。

据报道,Linux只是按需提交堆栈页面,并不要求程序按正确顺序提交页面。