如何将uftrace打造成业务时延检测的终极利器?
摘要:本文来自博客园,作者:T-BARBARIANS,博文严禁转载,转载必究! 篇幅较长,阅读耗时告警! 一、前言 作为后台程序的开发人员,应用程序的性能一直是我们的核心关注点。 大到业务程序的架构设计、支撑业务的组件选型,小到具体某些功能相似方
本文来自博客园,作者:T-BARBARIANS,博文严禁转载,转载必究!
篇幅较长,阅读耗时告警!
一、前言
作为后台程序的开发人员,应用程序的性能一直是我们的核心关注点。
大到业务程序的架构设计、支撑业务的组件选型,小到具体某些功能相似方法的性能横向对比、编译优化、甚至抠某一行代码,目的都是为了给我们的程序插上翅膀。
有了这些就够了么?显然不是的,因为做到了这些,实际的综合表现还是未知的。就像生产一款新型汽车,组装好了你得拉出来溜一溜,对照众多测试用例,核验各项设计指标。
本文要介绍的就是借助uftrace工具,核查C/C++/Rust程序中每一个函数的执行耗时,在此基础上,优化耗时大的函数,真正为我们的程序起飞打下坚实基础。
二、抛砖引玉
介绍uftrace之前,先简单聊一聊perf。
perf是c/c++领域性能分析的一大利器。perf可以统计过去一段时间里,所有被执行函数和指令的CPU使用总时间,通过统计报表的形式,直观展示热点函数和指令的CPU占比。例如下图一所示,开发者可以通过对热点的针对性分析,达到程序性能优化的目的。
图 1
perf完美了么,就没有它不能覆盖的性能分析场景了么?显然不是,perf是基于过去一段时间的所有累计之和,是从宏观的角度去分析。那从微观角度,比如我有一个需求:有没有这样的一种工具,它可以记录某个用户态函数在过去一段时间里,每一次执行的单独耗时,以及它的完整调用链?从而挖掘出宏观角度发现不了的深坑!
例如一个“hello world”函数,大部分时间该函数的执行时长都比较一致,但是会偶发执行时长大幅增加的情况,那这背后的原因就值得我们去深入分析。
图 2
perf tools的ftrace具备“记录函数每一次的执行耗时”能力,但是ftrace是基于内核的,只能跟踪分析linux内核中各种函数的执行耗时。这里我使用trace-cmd工具(ftrace的一个命令行工具,大大简化ftrace的使用)来记录“do_page_fault”缺页中断函数在一段时间范围的执行耗时。
1、只查看函数的每一次执行耗时。
图 3
由图3可知,do_page_fault在内核的每一次执行,耗时都集中在1us左右,短时间内未见异常。
2、查看do_page_fault每次耗时,以及函数内部各子函数的执行耗时。
图 4
图 5
图5直接展示了do_page_fault函数内部各子函数的执行耗时。假设当某一次do_page_fault耗时异常,那就可以通过日志准确定位到某个异常的子函数,这样对我们定位问题是非常有用的。
那用户态呢,有分析和记录用户态函数执行耗时的工具么?答案是当然有,优秀的工具凤毛麟角,uftrace百里挑一!
三、uftrace简介
uftrace是一个分析C/C++/Rust用户态程序性能,且支持多线程性能分析的开源工具。
(1)安装简介
1、获取最新Release安装包,https://github.com/namhyung/uftrace
2、解压安装包,执行相关配置,编译,安装命令
最后,在指定的安装目录:/usr/local/uftrace下,有如下目录,uftrace的可执行程序就位于bin目录下。
(2)uftrace初露锋芒
如何使用uftrace呢?通过一个demo,我们先来实践一下uftrace的基本使用方法,以及初步介绍uftrace的时延分析方法。
有如下malloc多线程程序,每一个线程执行10S,且在每一个线程里会不断的多次重复执行malloc()和free()。
另外:
1、编译选项里要添加参数 -pg(使编译器在函数入口插入对mcount()桩函数的调用,从而实现每个函数的耗时记录);
2、去掉所有优化选项-O,否则对于庞大的程序,uftrace只能展示优化后代码的串行执行顺序,非常不利于我们对照代码进行问题排查。
