Perf启动开销:为什么执行MOV + SYS_exit的简单静态可执行文件有如此多的停顿周期(和指令)?

时间:2018-02-15 14:14:58

标签: linux performance assembly x86-64 perf

我正在努力了解如何衡量效果并决定编写非常简单的程序:

section .text
    global _start

_start:
    mov rax, 60
    syscall

我用perf stat ./bin运行程序我感到惊讶的是stalled-cycles-frontend太高了。

      0.038132      task-clock (msec)         #    0.148 CPUs utilized          
             0      context-switches          #    0.000 K/sec                  
             0      cpu-migrations            #    0.000 K/sec                  
             2      page-faults               #    0.052 M/sec                  
       107,386      cycles                    #    2.816 GHz                    
        81,229      stalled-cycles-frontend   #   75.64% frontend cycles idle   
        47,654      instructions              #    0.44  insn per cycle         
                                              #    1.70  stalled cycles per insn
         8,601      branches                  #  225.559 M/sec                  
           929      branch-misses             #   10.80% of all branches        

   0.000256994 seconds time elapsed

据我了解stalled-cycles-frontend,这意味着CPU前端必须等待某些操作(例如总线事务)的结果才能完成。

那么是什么原因导致CPU前端在最简单的情况下等待大部分时间?

2页错误?为什么?我没有阅读任何记忆页面。

1 个答案:

答案 0 :(得分:2)

页面错误包括代码页。

perf stat包括启动开销。

IDK perf如何开始计算的详细信息,但可能是它必须在内核模式下对性能计数器进行编程,因此当 CPU切换回用户时,它们会计算模式(停止多个周期,特别是在具有使TLB无效的Meltdown防御的内核上)。

我想大多数录制的47,654指令都是内核代码。也许包括页面错误处理程序!

我猜您的流程永远不会用户 - > kernel->用户,整个流程是kernel-> user-> kernel(启动,syscall调用sys_exit,然后永远不会返回用户空间),所以从来都不会出现TLB本来很热的情况,除非在sys_exit系统调用之后在内核中运行。无论如何,TLB错过了不是页面错误,但这可以解释许多停滞的循环。

用户 - >内核转换本身解释了大约150个停滞的周期,BTW。 syscall比缓存未命中更快(除非它没有流水线,实际上刷新了整个流水线;即没有重命名权限级别。)