【发布时间】:2018-05-23 06:54:41
【问题描述】:
所以最近我了解了 linux 中的perf 命令。我决定进行一些实验,所以我创建了一个空的 c 程序并测量了运行需要多少条指令:
echo 'int main(){}'>emptyprogram.c && gcc -O3 emptyprogram.c -o empty
perf stat ./empty
这是输出:
Performance counter stats for './empty':
0.341833 task-clock (msec) # 0.678 CPUs utilized
0 context-switches # 0.000 K/sec
0 cpu-migrations # 0.000 K/sec
112 page-faults # 0.328 M/sec
1,187,561 cycles # 3.474 GHz
1,550,924 instructions # 1.31 insn per cycle
293,281 branches # 857.966 M/sec
4,942 branch-misses # 1.69% of all branches
0.000504121 seconds time elapsed
为什么它使用这么多指令来运行一个实际上什么都不做的程序?我认为这可能是将程序加载到操作系统所需的一些基准指令数量,所以我寻找了一个用汇编编写的最小可执行文件,我发现了一个 142 字节的可执行文件,它在此处输出 "Hi World" (http://timelessname.com/elfbin/ )
在 142 字节的 hello 可执行文件上运行 perf stat,我得到:
Hi World
Performance counter stats for './hello':
0.069185 task-clock (msec) # 0.203 CPUs utilized
0 context-switches # 0.000 K/sec
0 cpu-migrations # 0.000 K/sec
3 page-faults # 0.043 M/sec
126,942 cycles # 1.835 GHz
116,492 instructions # 0.92 insn per cycle
15,585 branches # 225.266 M/sec
1,008 branch-misses # 6.47% of all branches
0.000340627 seconds time elapsed
这似乎仍然比我预期的要高很多,但我们可以接受它作为基准。在那种情况下,为什么运行 empty 需要多 10 倍的指令?这些指示做了什么?如果它们是某种开销,为什么 C 程序和 helloworld 汇编程序之间的开销差异如此之大?
【问题讨论】:
-
您的“空”程序确实会动态加载共享库(至少我猜是 clib - 我猜您有 64b linux,默认情况下二进制文件是 PIE 并使用共享库),然后初始化C-runtime 环境,然后它最终将控制权交给您的空
main(...),它刚刚返回。然后它必须从 C 运行时释放 + 清理所有内容,刷新缓冲区等...... -
可以添加
gcc -O3 -static emptyprogram.c -o empty1; perf stat ./empty1的结果吗? -
所以每次运行程序时使用 C 代替汇编会浪费 0.00016 秒?
-
之前有几个关于
perf指令计数的问题。 This one 建议用户与内核+用户计数可能解释了裸静态可执行文件的高计数。您是否尝试过一个静态可执行文件,它也无需调用sys_write就退出? -
当我查看用 C 编写的空程序时,我发现动态链接器
ldd.so占据了大部分指令,正如 @Ped7g 所暗示的那样。您可以尝试静态链接以查看差异,同时保留 C-rutnime init。