以前作为app开发者,能够经过Android Studio自带的app profiler来检查单一使用的performance状况。比方内存占用,网络请求等等
可是成为framework开发之后,就不能只局限于单一的使用的profiler了。因为一个app的performance其实也取决于当时体系的运转状况。比方敞开某一个线程运转耗时操作,这个线程到底在某一个短时刻内分配了多少CPU cycle,决议了它多快能运转完成。当体系反常繁忙的时分,单一线程所能分配到的cycle自然变少。
所以今日我就简略的介绍一下一个能够profile整个体系的运转状况的东西Perfetto, 来看看怎样监控整个体系的performance。这期文章会以监控线程运转状况,Binder call为重点。
Perfetto初探
Perfetto 是谷歌推出的新一代体系级别performance的监控东西(能够监控Linux和Android),
详细的用处和用法能够参考官网 : perfetto.dev/
简略的说,开发者能够经过一个比较傻瓜式的网站UI tool来提取 trace文件,也能够用一个script自行装备。可是原理都是一样的,经过修改data source 来提供想监控的状况。
经过UI东西监控
经过script监控
值得注意的是Perfetto默认不监控binder和一切app的trace,在这儿咱们需求改动一下装备敞开监控binder和一切app的trace。然后咱们也能够自定义duration_ms
字段来操控profile的时刻长短。我作业的时分需求监控接听电话的performance,所以我一般设置成30秒。
敞开监控之后,立刻进行想监控的操作(无论是app的行为,仍是体系的行为),然后Perfetto东西会自动翻开一个可视化的网站剖析得到的监控trace文件。Trace文件可视化之后长这个姿态:
左边一列列出了在当时监控session之内敞开的一切进程。咱们能够借此检查咱们想检查的app/进程的运转状况。
点击某一个进程,左边会列出在监控session中发动的一切线程和线程中记载的trace(下面会详细讲一下trace)
怎样加Trace
Trace代表了一段你想监控的代码段。在Perfetto 可视化东西里边长这样。
以上是一个大Trace里边包括了许多小Trace, 原因也很简略,一个有Trace的办法A能够包括若干个也带有Trace的办法B,C,D,E。。。
在代码里边加Trace也很简略,
new Thread(() -> {
Trace.beginSection("test2");
try{
//模仿耗时作业
Thread.sleep(4000);
}
catch (Exception e) {
}
Trace.endSection();
}, "richard").start();
加了这个代码之后,在Perfetto 可视化东西就能够看到该Trace
同理假如你在一个办法里边写多个Trace
new Thread(() -> {
Trace.beginSection("test2");
try{
//模仿耗时作业
Thread.sleep(2000);
Trace.beginSection("test3");
//模仿调用另一个带trace的办法
Thread.sleep(2000);
Trace.endSection();
}
catch (Exception e) {
}
Trace.endSection();
}, "richard").start();
所以,合理的编写trace代码能够轻松的在监控东西中检查办法调用的耗时和联系。
安卓在体系层许多的当地都加入了默认的trace,不过不少都需求体系开发者在代码中手动敞开,需求自己重新编译体系的ROM。比方Telecom component:
所以也侧面说明了,要想能合理的调试体系performance,其实要先有对要监控的部位的根底认知。。。。否则在哪打log,或许trace都不知道的话,光看现有的trace可能并不会特别有用。
最后安卓也支撑异步的trace。比方开始trace和结束trace在不同线程 (可是这种trace貌似出来检查耗时之外并不是特别有用,因为这种线程不同的状况下,trace会单独列出来不好线程绑定)
Trace.beginAsyncSection("test1", 1);
new Thread(new Runnable() {
@Override
public void run() {
try{
Thread.sleep(4000);
}
catch (Exception e) {
}
Trace.endAsyncSection("test1", 1);
}
}, "richard").start();
线程运转状况
假如你仔细观察,会发现同一个线程会有两行。
其实这两行的意图是不一样的,榜首行一般记载线程的运转状况,第二行记载线程的trace。
咱们把榜首行放大看看
能够发现榜首行记载了线程在这个session中什么时分是running的状况(被分配了CPU cycle,在CPU中运转),什么时分是runnable的状况(没分配到CPU,在等候中)。
经过鼠标的拖拽,能够把某一段trace包起来,检查这个trace总体被分配的CPU状况
能够看到这一段trace里边,正在在CPU中运转的时刻只要10微秒左右,等候的时刻是运转的十倍左右。
假如这段代码不是故意的在代码中等候线程或许进行IO的话,说明当时线程被分配的CPU cycle不是很够。这便是值得注意需求优化的当地了。
Binder call的追寻
和以前的App profiler相比,Perfetto最大的提高之一便是在可视化东西中提供了Binder call的追寻。开发者能够检查任何一个IPC的caller 和 consumer。
比方咱们在App中调用体系API,去检查对某个体系API从哪里call,到哪个进程。
new Thread(new Runnable() {
@Override
public void run() {
Trace.beginSection("test1");
TelephonyManager manager = MainActivity.this.getSystemService(TelephonyManager.class);
try{
manager.getEmergencyNumberList();
Thread.sleep(4000);
}
catch (Exception e) {
}
Trace.endSection();
}
}, "richard").start();
以上代码中咱们调用了体系API TelephonyManager#getEmergencyNumberList
, 敞开监控之后运转该代码,检查可视化东西
能够看到在trace test1 下面果然有一个binder call的trace,点击该trace的binder reply,可视化东西会自动跳转到binder的reply进程
能够看到该binder的reply是在com.android.phone(也便是Telephony)进程。
检查源代码的package name和 服务端完成
果然!!!
经过监控binder call的trace,咱们作为体系开发者能够了解某个app在调用IPC的时分,为何会耗时,耗时的进程在哪,服务端的进程的运转状况等等,从而做出优化选择。
总结
这篇文章简略的介绍了一下Perfetto的使用办法,其实Perfetto除了以上三个用处还有许多强大的功用,这儿只做简略的介绍,下篇文章会用一个实际的比如来讲述怎样经过Perfetto 监控东西来发现能够优化的体系代码的 (呵呵又水了一篇文章!!!!!)
最近作业实在太忙了,更新速度肉眼可见变慢。。。。。。求宽恕