【问题标题】:Profiling a (possibly I/O-bound) process to reduce latency分析(可能是 I/O 绑定的)进程以减少延迟
【发布时间】:2012-08-01 15:19:49
【问题描述】:

我想提高大型应用程序中特定方法的性能。

目标是改善延迟(特定功能所花费的挂钟时间),而不是(必然)系统负载。

要求:

  1. 我预计很多延迟都是由 I/O 引起的,因此请考虑等待/阻塞所花费的时间(换句话说:查看挂钟时间而不是 CPU 时间)
  2. 因为程序比我试图优化的片段做得更多。需要有一种方法可以以编程方式启动/停止分析,或者过滤输出以仅显示进入和退出我正在优化的函数之间的时间。
  3. 方法级别的分析是可以接受的(如果可以在指令级别完成,那就更好了。如果只分析系统调用,那可能还不够)
  4. 这是一个爱好项目,所以昂贵的工具不是真正的选择
  5. 仪器(-finstrument-functions)是可以接受的
  6. 我感兴趣的关键代码段很难手动中断(因为它已经相对较快并且很难在循环中实际调用),因此需要某种自动化。

目前丢弃的工具:

  • gprof、oprofile、callgrind(要求 1)
  • 使用 getrusage 构建自定义内容(要求 1)
  • poormansprofiler.org(要求 2)
  • strace -T,dtrace,http://perf.wiki.kernel.org(要求 2 和 3)
  • VTune、缩放(要求 4)
  • 手动调用堆栈采样(要求 6)
  • google-perftools(应该能够测量挂墙时间,但这在我的情况下似乎不起作用,大概是因为 SIGALRM 干扰。
  • systemtap(我的内核未修补以包含 utrace)

我尚未进一步评估的其他选项:

  • cprof(这里不是开箱即用的,似乎仅限 i386)
  • 手动插入跟踪点(例如使用 lttng)

我很想听听:

  • 其他选项
  • 也许我太早放弃了一些工具?
  • 我尚未评估的选项是否有机会发挥作用,如果有,如何做到最好。

我终于安顿下来了:

这个粗糙的工具产生的痕迹很难解释,我可以很容易地想象一些工具可以进一步处理它的输出,让它变得无限有用。但是,这对我来说已经完成了工作,所以我将这个项目推迟到以后;)。

【问题讨论】:

    标签: linux performance profiling trace sampling


    【解决方案1】:

    使用this method

    无论是在 CPU 还是 IO 绑定代码中,它都能非常简单有效地确定优化机会。

    如果您认为最大的机会在于特定功能或模块是正确的,那么它会找到它们。如果它们在别处,它会找到它们。

    在你提到和丢弃的工具中,它与穷人的分析器最相似,但仍然不是很相似。

    编辑:既然你说它是由用户交互触发并阻止进一步的输入直到它完成,我会这样做。

    首先,我假设它不会阻止到调试器的手动中断信号,否则您将无法停止无限循环。 其次,我会在有问题的例程周围循环 10、100 或 1000 次,因此它执行的时间足够长,可以手动中断。

    现在,假设它在 I/O 上花费了一小部分时间,比如 50%。然后当你中断它时,你有 50% 的机会在 I/O 中捕获它。 因此,如果您在 I/O 中捕获它(调用堆栈会告诉您),您还可以非常详细地查看从哪里请求 I/O 以及请求的原因。

    它将向您展示正在发生的事情,这几乎可以肯定是令人惊讶的。 如果您看到它在少至两 (2) 个样本上做一些事情,您可以找到一种消除方法,那么您将获得相当大的加速。 事实上,如果您消除该活动,您不会提前知道会节省多少时间,但平均而言,您可以期望节省分数 F = (s+1)/(n+2) em>,其中 n 是您采集的样本总数,s 是显示活动的样本数。 (Rule of Succession) 例如,如果您采集了 4 个堆栈样本并在其中 2 个上看到了活动,平均而言,它会为您节省 F = 3/6 = 1/2,对应于加速因子 1 /(1-F) 或 2.

    完成此操作后,您可以再次执行此操作并找到其他要修复的问题。 加速因素像复利一样相乘。

    当然,你移除外部循环并“兑现”你获得的所有加速。

    如果您想知道这与分析有何不同,那就是通过仔细检查每个堆栈样本以及可能的相关数据,您可以识别出您可以删除的活动,如果您只有测量值,那么您就剩下了试图直觉发生了什么。 无论任何测量结果如何,您节省的实际时间都是如此。 重要的是发现问题。 无论分析器如何精确地测量它,如果您无法找到它,那么您就不会获胜。 这些页面上到处都是人们说他们要么不明白他们的分析器告诉他们什么,要么似乎在说没有什么可以解决的,他们只是太愿意接受了。 那是一副玫瑰色眼镜。

    More on all that.

    【讨论】:

    • 确实,我在搜索时遇到了该页面。您描述了调用堆栈采样。这将是我的问题的一个很好的解决方案。但是,我感兴趣的关键代码很难手动中断。你知道可以帮助我自动完成的工具/技术吗?
    • 至于需求2,这并没有让我感到困惑,我真的很想专门优化这个方法。方法调用由用户交互触发,并且进一步的 UI 交互被阻止,直到它完成。程序的其他部分可能“更重”/“更慢”,但用户并没有那么积极地等待那些,所以这不是什么大问题。
    • @ArnoutEngelen:在这种情况下,我所做的是通过在它周围环绕一个循环来放大它,比如执行它 10 或 100 次,而通常它会执行一次。然后我进行优化,最后删除循环。
    • 正如我所指定的,在我的情况下,在要优化的段周围环绕一个循环并不容易。尽管我觉得你的回答并没有真正回答我原来的问题(因为它忽略了“无循环”的要求),但对于其他可行的情况来说,这仍然是很好的信息,所以我接受你的回答。
    【解决方案2】:

    对于 I/O 绑定应用程序,您可以使用 callgrind 的 --collect-systime=yes 选项。

    这会收集系统调用所花费的时间(以毫秒为单位)。 因此,如果您认为自己存在 I/O 瓶颈,您可以使用这些统计数据来识别它。

    【讨论】:

    • 很高兴知道!将不得不深入研究:)
    • 如果您使用 kcachegrind,请不要忘记将成本类型更改为 sysCountsysTime
    【解决方案3】:

    Todo:检查“perf”(再次)

    【讨论】:

    【解决方案4】:
    • fork()
    • execxxx(被测进程)
    • 在父级中:
      • (在循环中)定期调用:
      • getrusage(RUSAGE_CHILDREN, ...)

    getrusage() 不仅会为您提供 cpu 使用率,还会为您提供主要/次要页面错误、上下文切换次数等。其余时间可能都花在等待 I/O 上。这不会为您提供详细的分析信息,但可以很好地了解程序行为的整体足迹,可与基于每个进程运行 vmstat 相媲美。

    【讨论】:

    • 看起来这不会将我指向执行大量(可能是可避免的)I/O 的地方,我对此特别感兴趣,对吧?
    • 整个想法是提供另一种看待事物的方式。如果简单的分析没有产生明显的热点,那就没有什么可做的了。 (除了算法更改、缓存对齐、引用位置等)
    • 好吧,例如,我还没有找到一个工具可以将我指向pastebin.com/W7ZS31yB 的“slow()”方法——据我所知,getrusage 也不会。显然有办法抓住这一点(目前我看到的最有前途的是仪器和堆栈采样),但我还没有找到可以做到这一点的免费工具..
    • 顺便说一句:我错了,RUSAGE_CHILDREN 只报告已退出的孩子。如果您想要中间值,则必须使用进程本身的 getrusage(可能使用计时器驱动的信号)并将它们发送到外部收集器进程(使用管道或 UDP 套接字)。仪器仪表。而且在采样时您仍然缺少当前的堆栈跟踪。 (IIRC 有一个技巧)顺便说一句:当程序在系统调用中被阻塞时,信号传递更有可能,所以这将是一个胜利。
    猜你喜欢
    • 2011-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-21
    • 1970-01-01
    • 2018-04-10
    • 2011-01-16
    • 1970-01-01
    相关资源
    最近更新 更多