【问题标题】:Oprofile callgraph: origin of syscallsOprofile callgraph:系统调用的起源
【发布时间】:2013-04-02 14:24:58
【问题描述】:

我一直在使用 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 的位置?

【问题讨论】:

  • 您使用的是--callgraph 选项吗?
  • --callgraph=10 on opcontrolopreport

标签: linux profiling oprofile


【解决方案1】:

Oprofile 获取堆栈样本。您需要做的不是查看它们的摘要,而是实际检查原始样本。如果你在内核中花费了 30% 的时间,那么如果你可以看到随机选择的 10 个堆栈样本,你可以期望其中 3 个或多或少地向你展示你如何进入内核的全部原因内核。

That way you will see things 不会显示摘要或调用图。

以防万一:由于__ticket_spin_lock 有 99.6% 的时间都在堆栈上,那么在您查看的每个堆栈样本上,您将有 99.6% 的概率看看你是如何进入那个常规的。 那么如果你真的不需要这样做,你可能会有 250 倍的加速。 这就像从四分钟到一秒。使用“正确”或“自动化”的方法 - 获得结果。

添加:关于分析器的事情是它们很受欢迎,并且有些具有非常漂亮的 UI, 但遗憾的是,这恐怕是“皇帝的新衣”一案。 如果这样的工具找不到太多需要修复的地方,你会喜欢它,因为它说(可能是错误的)你写的代码接近最优。

有很多帖子推荐这个或那个分析器,但是 我无法指出使用分析器可以节省超过百分之几的时间,例如 40%。 也许有一些。

从未听说过首先使用分析器来获得加速,然后再次使用来获得第二次加速,依此类推。 这就是您获得真正加速的方式 - 多重优化。 一开始只是一个小性能问题的东西在你删除了一个更大的问题之后不再是小问题。 这张图显示了通过消除六个问题,加速是如何接近三个数量级的。 你不一定能做到,但不值得一试吗?

为进一步的编辑道歉。我只是想表明很容易欺骗调用图。 红线代表调用堆栈样本。在这里,A1 将所有时间都花在调用 C2 上,反之亦然。然后假设您保持相同的行为,但是您放入了“调度”例程 B。 现在调用图丢失了 A1 在 C2 中花费的所有时间的信息,反之亦然。 您可以轻松地将此示例扩展到多个级别。 你可以说调用 tree 会看到这一点。 好吧,这就是你如何欺骗调用树的方法。 A 将所有时间都花在调用 C 上。 现在,如果 A 调用 B1、B2、... Bn,而那些调用 C,则从 A 到 C 的“热路径”被分解成碎片,因此 A 和 C 之间的关系被隐藏了。 还有许多其他完全普通的编程实践会混淆这些工具,特别是当样本深度为 10-30 层且功能很少时,但程序员仔细检查适量样本时无法隐藏关系。

【讨论】:

  • 有趣的帖子,谢谢。有没有办法使用我已经通过 oprofile 收集的数据?这似乎有点过于手动,无法成为“正确”的方式。
  • 对吗?太手动了? this post 的 >500 票不存在,因为它不正确。如果您追溯性能分析背后的想法来自哪里,它们是没有根据的。它们基于整体的测量概念。 OTOH,如果你有一个无限循环,你不会通过测量找到它,是吗?不。您将其视为要手动发现的错误,并在调试器中将其停止。好吧,每当一个程序花费的时间比它可能的多时,最好的技术是相同的。您抓取随机时间样本并仔细检查它们。
  • @MikeDunlavey:是的。首先,oprofile 使用统计抽样,这相当于您建议的方法(尽管它需要较少的人工干预,并且在无法停止程序的情况下工作)。在这种特定情况下,建议筛选大量样本是不可行的。我可能建议在这里检查调用图设置,因为它们似乎被截断了,或者使用 opreport --accumulated 选项,或者将结果限制为正在分析的图像,使用这些来识别有问题的调用链。
  • @Hasturkun: 1) 采样没问题,但对它们做了什么却不行。 2) 问题很容易隐藏在调用图中,例如它取决于数据或发生调用的代码行。 3)Here are the statistics为什么需要大量样本是没有根据的。 4) this post 的第 3 点显示了调用图的问题。 5)您听说过哪些加速因素,使用任何分析器?我不是说没有。我是说它们很小。
  • @MikeDunlavey:回复:2,在大多数情况下,这仍然会给你一个代码区域来关注(另外,IIRC,调度例程案例不应该丢失信息。虽然我可以' t 现在验证这一点,我认为 oprofile 将为您提供有关呼叫的指令级详细信息)。在任何情况下,都应检查配置文件输出,甚至在需要时查看单个样本。我的观点可能因处理线程异步代码而受到污染,因此我将删除我的反对意见,尽管我仍然觉得这并不能真正回答问题。
【解决方案2】:

我同意 Mike 的回答:调用图不是检查问题根源的正确方法。您真正想要的是查看最热门样本的调用链。

如果您不想“手动”检查 oprofile 收集的原始样本,您可以使用 -g 选项使用 perfrecord 命令重新运行您的应用程序,以收集堆栈跟踪。然后,您可以使用 perf 的 report 命令显示带有 callchains 注释的示例。由于 perf 没有在全局调用图中聚合单个样本的调用链,因此您不会遇到 Mike 的帖子中概述的一些问题。

【讨论】:

    猜你喜欢
    • 2014-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-09
    • 1970-01-01
    • 1970-01-01
    • 2011-09-24
    相关资源
    最近更新 更多