Oprofile callgraph:系统调用的起源

我一直在使用oprofile来试图发现为什么我的程序在内核上花费了太多的时间。 我现在有了来自内核的符号,但是显然我的程序和内核之间没有任何联系,会告诉我我的程序哪些部分需要这么长时间。

samples % image name app name symbol name ------------------------------------------------------------------------------- 201 0.8911 vmlinux-3.0.0-30-generic vmlinux-3.0.0-30-generic _raw_spin_lock_irq 746 3.3073 vmlinux-3.0.0-30-generic vmlinux-3.0.0-30-generic rb_get_reader_page 5000 22.1671 vmlinux-3.0.0-30-generic vmlinux-3.0.0-30-generic default_spin_lock_flags 16575 73.4838 vmlinux-3.0.0-30-generic vmlinux-3.0.0-30-generic _raw_spin_lock 22469 11.1862 vmlinux-3.0.0-30-generic vmlinux-3.0.0-30-generic __ticket_spin_lock 22469 99.6010 vmlinux-3.0.0-30-generic vmlinux-3.0.0-30-generic __ticket_spin_lock [self] 26 0.1153 vmlinux-3.0.0-30-generic vmlinux-3.0.0-30-generic ret_from_intr 

我从哪里出发? 如何在程序中发现导致__ticket_spin_lock的地方?

Oprofile采取堆栈样本。 你需要做的不是看他们的摘要,而是实际检查原始样本。 如果你在内核中花费了30%的时间,那么如果你能看到随机抽取的10个堆栈样本,那么可以预计3个样本会或多或少地显示出你进入核心。

这样你会看到的东西总结或通话图不会显示给你。

因为__ticket_spin_lock是99.6%的时间,所以在你看的每一个堆栈样本中 ,概率是99.6%,你会看到你如何进入这个例程。 那么如果你真的不需要这样做 ,你可能会有250倍的加速。 这就像从四分钟到一秒钟。 拧“正确”或“自动化”的方法 – 获得结果。

补充:关于配置文件的一点是它们很受欢迎,有些用户界面非常好,但可惜的是,恐怕这就是“皇帝的新衣服”。 如果这样一个工具没有找到很多解决办法,那么你会喜欢它,因为它说(可能是错误的)你写的代码是接近最优的。

有很多推荐这个或那个探查器的帖子,但是我不能指出任何使用探查器保存超过百分之一的时间,比如40%。 也许有一些。

从来没有听说过一个profiler被首先用来加速,然后被再次用来获得第二个加速,等等。 这就是你如何得到真正的加速 – 多个优化。 刚刚删除一个较大的性能问题,一开始就是一个小的性能问题。 这幅图显示了如何通过消除六个问题,加速几乎是三个数量级。 你不一定这样做,但这不值得尝试吗?

在这里输入图像描述

APOLOGIES进一步编辑。 我只是想表现出容易欺骗电话图。 红线代表调用堆栈样本。 A1在这里花费所有时间调用C2,反之亦然。 那么假设你保持相同的行为,但是你把一个“调度”程序B,现在调用图失去了A1在C2中消耗的所有信息,反之亦然。 您可以轻松地将此示例扩展到多个级别。 在这里输入图像描述 你可以说一个调用会看到。 那么,这是你怎么可以欺骗呼叫树。 A在C中调用它的所有时间。现在,如果A调用B1,B2,… Bn,而那些调用C,则从A到C的“热路径”被分解成片断,因此A和C是隐藏的。 在这里输入图像描述 还有许多其他完全普通的编程实践会混淆这些工具,特别是当样本深度达到10-30层并且功能都很少时,这种关系不能被程序员仔细检查中等数量的样本所隐藏。

我同意迈克的回答:调查图不是检查问题根源的正确方法。 你真正想要的是看最热门的样本的callchains。

如果您不想“手工”检查oprofile收集的原始样本,则可以使用-g选项的perf命令重新运行您的应用程序以收集堆栈跟踪。 然后,您可以使用perf的report命令显示使用其调用链标注的样本。 由于perf并不是在全局调用图中汇总单个样本的callchains,所以您没有Mike的文章中列出的一些问题。