我正在努力了解如何衡量效果并决定编写非常简单的程序:
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页错误?为什么?我没有阅读任何记忆页面。
答案 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
比缓存未命中更快(除非它没有流水线,实际上刷新了整个流水线;即没有重命名权限级别。)