慎用Android Process setThreadPriority

  • Post author:
  • Post category:其他


最近几个版本,发现公司产品的线上启动时间,突然增加了2s左右,而且线下测试也能够测试在低端机器上,耗时增加明显。

复现问题

因为在低端机器上很容易复现,于是用红米note 1s测试,对比前后两个版本A和B,B版本确实会比A版本平均慢2s左右。在测试过程中会重复的安装与卸载apk,有的时候发现B版本时间跟A版本一样,很是奇怪。多次确认环境后,发现B版本登陆与不登陆应用,启动时间差别很大。

分析问题

既然在登陆与不登陆后,B版本的时间差别很大,那显然可以解释为:

  1. B版本登陆集成了新功能,导致启动时间变长。
  2. B版本登陆影响了启动模块的启动,依赖登陆的模块导致了启动时间的加长。

先看是否是登陆模块引起时间过长。首先确认登陆在A和B版本直接有集成,跟登陆的开发工程师以前review一些代码,耗时操作都在异步线程中,但为了确认对启动时间的影响,还是添加log计算登陆在主线程耗时,跟前一个版本一些,时间上没有变化。为了洗白登陆的嫌疑,那就回退登陆吧!把登陆的版本回退到A版本,B版本的启动时间还是比A版本慢了2s左右,显然不是登陆本身引起的。那应该是原因2导致的。

依赖登陆的模块太大了,拉取启动过程中的trace文件:

启动trace文件

发现模块C非常耗时,Wall Clock Time为500ms左右,Thread Time为200ms左右。询问登陆模块的负责人及查看记录,发现C模块在版本A与B直接有版本更新。然后在找C模块的负责人,回退他们的版本,C模块还依赖其他的模块,一起都回退了以后,线下测试时间果然减少了1s左右。于是找C模块的负责人,把trace一起分享了一下,发现耗时的部分,在A版本上一直就存在,并非这次引入, 新添加的代码,都得业务相关,对启动时间没有影响。

把C模块所有跟启动相关的代码全部注释掉,问题已经还存在。比较明确的是问题由C模块引起,然而却找不到哪块的改动引起。我发邮件说明问题的存在及回退版本后,性能得到了提升,但问题原因还没有定位出来。过了个周末后,C模块的负责人周末分析了一下问题,依旧没有找到原因。周一回来以后,群里开始乱哄哄了,各种手段跟工具出来了,然而却不知所谓,无论怎么变化,都是拉个trace在那里看过来看过去。如果trace能看出来问题话,何至于此?搞的我不会看trace文件一样,我现在最讨厌一有性能问题,别人就说拉个trace看一下,不就知道了吗?也许这就是大部分了对性能问题的理解吧。让他们玩去吧!

我很想见识一下别人的技术是什么样的。刚好周一也用其他的事,就没有继续分析,让别人玩玩去!偶尔看看别人分析的结果,完全在瞎掰,风马牛不相及,根本就不知道干什么。结果到了周二,问题还是没有解决。大老板催了,所以我老板来找我了。模块C的负责人又过来找我了,我认真对比了一下A版本和B版本的trace文件,B版本的trace文件,我发现所有的时间都被拉长了很多。所以我问模块C的负责人,你用没有设置过进程的优先级什么的,他说在他们的service设置过一个线程的优先级。于是我说你设置回去吧!于是他设置回去了,编译apk测试了一下,结果还是没有得到改善。

这下我也没招了,那就一个一个版本回退吧!结果发现从A到B版本,有数百个提交。直接一个一个回退的话,编译一个apk至少需要10分钟,那不知要花多少时间才能回退完。那就git bitsect吧!

当我尝试用git bitsect,我发现代码是build不过的,这下我就没有备注了,实在有点无语了,这让问题怎么查呀!感觉git功能完全没有发挥出来,就是一个存储的地方而已。实在没有招了,那就git bitsect加手动改吧!正吐血,git bitsect 15步左右,从早上搞到下班,才最后定位到两个版本直接的修改。那是定位到那句设置线程优先级的问题。看Process setThreadPriority代码的注释:

    /**
     * Set the priority of the calling thread, based on Linux priorities.  See
     * {@link #setThreadPriority(int, int)} for more information.
     * 
     * @param priority A Linux priority level, from -20 for highest scheduling
     * priority to 19 for lowest scheduling priority.
     * 
     * @throws IllegalArgumentException Throws IllegalArgumentException if
     * <var>tid</var> does not exist.
     * @throws SecurityException Throws SecurityException if your process does
     * not have permission to modify the given thread, or to use the given
     * priority.
     * 
     * @see #setThreadPriority(int, int)
     */
    public static final native void setThreadPriority(int priority)
            throws IllegalArgumentException, SecurityException;

Set the priority of the calling thread, based on Linux priorities.设置的是当前调用的线程,而模块C是在Service Create去设置的,当然是设置主线程的时间,导致部分手机上,主线程优先级低而延迟了启动时间。

问题总结

导致这个问题如此难以定位的原因,应该有:

1、设置的变动,导致直接从trace文件得不到有效的结果,只能看出来所有时间都被拉长了,但依据经验,我猜出来了可能的原因。

2、猜出来原因以后,开发修复设置线程优先级的代码。结果掉进去了maven仲裁的坑里面,修改的代码没有生效。作为一个测试方,没有去怀疑代码是否生效,失败呀!以前我都是自己去修改代码测试的。

3、模块代码回退到中间版本,代码build的不过。这个比较坑,如果是系统出现这样是问题的话,回退根本没法进行,问题会出现没法排查的情况。

感慨

关键问题是,回退出来了问题,还被别人说效率低,倒是给我一个更好的解决方案呀!一堆人瞎折腾也没折腾出来啥。

以前的时候,我看到这种performance problem,会非常有兴趣,很想证明自己技术的高超及能力。然而不知从什么时候开始,我却不太想去碰这种问题了,也许是从我开始慢慢读paper和code后,知道的越多的什么,发现自己智商越来越不够用,自己的无知,所以也就没有必要去证明什么了,更多的是知识和技术的敬畏。很想找个合适适合的地方,一试身手,空怀满腹经纶而无处施展,不得不为生计而活着,真可悲!现在发现,不懂其实还没有那么痛苦,更痛苦的是有理想而不能实现,眼睁睁的开始岁月的流逝!



版权声明:本文为oujunli原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。