[DESCRIPTION]
自L版本之后,所有的APP要经过dex2oat处理过之后,才能运行。而dex2oat的任务是将原来的dex文件做预先的翻译,从而可以加快APP运行的时间。但是由于某些APP比较复杂,所以优化的时间就比较长。优化是以dex文件中的method为单位。dex2oat在优化时,会根据需要优化一定量的method。也就是说并不是优化的method都会被翻译成oat模式。根据优化的method的量的多少,可以分为如下的几种模式:
对APP的优化是通过dex2oat去执行的,而优化模式则是由于外界调用dex2oat通过参数的方式传递进去的,如果调用命令的时间没有传递参数那么,默认采用speed模式。
而调用dex2oat的路径一般有两种:安装APP的时候,由packagemanagerservice将参数传递给installd,由于installd调用dex2oat,也就是说优化模式由PMS决定。另外一种是APP自身优化插件,这时候,往往会指定为speed或者不指定。
前一种方式将APK的路径,优化之后的oat存放路径传递给dex2oat,但是由于内容可能发生改变,我们有可能无法在dex2oat对APP加以识别,所以,这时候,可以在installd或者pms中加以判断是否是我们认为为安装比较慢的APP,如果是的话,则想改变其优化的模式。
如果是后一种方式,往往会在优化之后的保存路径中携带APP的包名。
目前有些apk像facebook、微信等apk,本身应用较大且code复杂度高,往往会出现安装失败,安装慢等问题。
安装失败是由于dex2oat进程编译时间过久打到了timeout,安装慢当然就是dex2oat做的compiler久的原因。
还有像微信 这种在启动应用的时候是会优化插件的(而不是在安装的时候优化),这样就会导致应用lunch时间过久,给用户的感觉就是很晚才入。
说明:app 安装/ lunch时间的长短取决于CPU核心数,8核心的肯定是必4核心的优化要快,还取决于EMMC的性能 ,memory等系统因素。
目前解决安装慢或者启动慢主要从如下几个方面着手:
首先:保证系统方面已经没有可以优化的空间,例如,各种对应的patch已经合入,art是最新版本。如果已经没有优化空间,这时候,就需要考虑更改优化的模式以加快安装的时间,但是会降低app运行的性能。
1. 请先确保以下patch合入
L版本:
patch: ALPS02522543(L1.MP9不需要合入)
ALPS02861966(dependency 了所以重要的patch)
M版本:
ALPS02894769
2. 发现:6735平台上dex2oat慢:demo 机 k35m 就比 k35 慢, 原因是CPU 频率影响,PS有说明, 参考以下FAQ尝试修改freq:
[FAQ17683]如何调整CPU corenum, freq, policy
[FAQ09538][CPU DVFS/Hotplug]运行时,把CPU固定在特定频率/特定核数的办法
更改dex2oat的模式:
如上面讨论那样,dex2oat发生的时机有两种情况:一是APP安装 ,二是APP自身优化插件。
更改优化模式的难点在于:如何识别进行优化的APP就是我们希望优化成指定模式的APP或得jar包。
目前在android中可以在三个地方进行判断 :
PackageManagerService当中,这个地方是安装APP必经之路
installd的commands.cpp当中,这也是安装APP的必经之路
dex2oat当中,dex2oat是所有APP或者jar包的必经之路,但是由于传递给dex2oat的参数有限,所以可能无法识别。
所以对于安装APP可以在pms当中修改,而对于jar包可以在dex2oat当中修改。
因为pms中我们可以知道APP的pkg信息,这个是每一个APP唯一的。
而对jar包来说,由于每一个APP在优化的时候,喜欢把优化之后的jar包放在自己安装的APP路径下面。所以,可以利用这个特性进行判断 。
[SOLUTION M版本]
在PMS中修改
在L和M版本不适用。
N版本中经过层层调用,会调用到如下的函数,因此需要修改如下的文件:
/frameworks/base/services/core/java/com/android/server/pm/PackageDexOptimizer.java
privateintperformDexOptLI(PackageParser.Packagepkg,String[]sharedLibraries,153String[]targetInstructionSets,booleancheckProfiles,StringtargetCompilerFilter) {
在这函数中,可以判断传递下来的pkg是否是我们需要的package,如果是的话,将targetCompilerFilter设置为speed-profile。
speed-profile会在安装的时候采用interperter-only,然后,运行一段时间之后,会将那些常用的方法优化成为speed模式。也就是说是有选择性的优化。
2.修改
L版本:
方法1:
// mtk add begin
if ((!oat_filename_.empty() && (oat_filename_.find("facebook") != std::string::npos))||(!zip_location_.empty() && (zip_location_.find("facebook") !=std::string::npos))||((!oat_location_.empty()) && oat_location_.find("facebook") != std::string::npos)){ // mtk modify 2016-06-06
compiler_filter_string = "interpret-only";
LOG(INFO) <<" This apk is in whitelist from property so set interpret-only ";
}
// mtk add end
if (compiler_filter_string = nullptr){
compiler_filter_string = "speed";
}
注意:CTS测项用的包不能使用interpret-only模式,因为一些CTS测项是性能相关的,如果改为interpret模式,会导致CTS不过。之前有客户为了追求更快的安装速度,将所有的包都改为interpret-only的,结果CTS就不过了,针对这种情况,可以把CTS的包再放到speed模式的白名单当中。cts的关键字为test.
方法2(若上述方法无效):
1420if(num_methods<=compiler_options_->GetNumDexMethodsThreshold()) {
1421compiler_options_->SetCompilerFilter(CompilerOptions::kSpeed);
1422VLOG(compiler) <<"Below method threshold, compiling anyways";
1423}
1424}
1426//mtk_add_begin
1427staticconstexprsize_tkMinCompileDexSize=4;
1428if(!image_&&dex_files_.size() >kMinCompileDexSize) {
1429compiler_options_->SetCompilerFilter(CompilerOptions::kInterpretOnly);
1430LOG(INFO) <<"Enable Whitelist Rules. Current Dex File Sizes:"<<dex_files_.size();
1431}
1432//mtk_add_end
1434returntrue;
1435}
1437// Create and invoke the compiler driver. This will compile all the dex files.
1439TimingLogger::ScopedTimingt("dex2oat Compile",timings_);
1440compiler_phases_timings_.reset(newCumulativeLogger("compilation times"))
[SOLUTION L版本]
在device.mk中加入PRODUCT_PROPERTY_OVERRIDES += ro.mtk.dex2oat_white_list=com.tencent.mm: (注意 包名后又冒号“:”
[添加source code](抱歉不能排版)
/art/dex2oat/dex2oat.cc添加红色部分:
#ifdef HAVE_ANDROID_OS
extern "C"{
static int shouldUseInterpretonly(const char* filename){
char prop_buf[92];
memset(prop_buf,0,92);
bool have_whitelist = property_get("ro.mtk.dex2oat_white_list", prop_buf, NULL) > 0;
if(!have_whitelist)
return false;
char *str = prop_buf;
char appname[128],*ptrname = appname;
memset(appname,0,128);
while(*str)
{
if(*str != ':'){
*ptrname = *str;
ptrname ++;
str++;
} else{
str++;
if(*appname != 0){
if(strstr(filename,appname)) //found
{
return 1;
} else{
memset(appname,0,sizeof(appname));
ptrname = appname;
}
}
}
}
return 0;
}
}
#endif
static int dex2oat(int argc, char** argv) {
std::string dex_filename; //mtk_add
......
if (option.starts_with("--dex-file=")) {
dex_filenames.push_back(option.substr(strlen("--dex-file=")).data());
dex_filename = option.substr(strlen("--dex-file=")).data(); //mtk_add
} else if......
if (compiler_filter_string == nullptr) {
if (instruction_set == kMips64) {
// TODO: fix compiler for Mips64.
compiler_filter_string = "interpret-only";
} else if (image) {
compiler_filter_string = "speed";
} else {
#if ART_SMALL_MODE
compiler_filter_string = "interpret-only";
#else
#ifdef HAVE_ANDROID_OS
if(shouldUseInterpretonly(zip_location.c_str())){
compiler_filter_string = "interpret-only";
LOG(INFO) <<" This apk is in whitelist from property so set interpret-only";
}else if(shouldUseInterpretonly(dex_filename.c_str())){
compiler_filter_string = "interpret-only";
LOG(INFO) <<" This jar is in whitelist from property so set interpret-only";
}else{
#endif
compiler_filter_string = "speed";
#ifdef HAVE_ANDROID_OS
}
#endif
#endif
}
}
CHECK(compiler_filter_string != nullptr);
.......
}
----------------------------------------------------------------------------------------------------------------------------------------------------
PS:新发现6735平台上dex2oat慢:demo 机 k35m 就比 k35 慢, 原因是CPU 频率影响, 与ART 优化影响不大
k35m M版本测试版本:
\\10.15.11.230\public1\ALPS_load\alps-mp-m0.mp1\alps-mp-m0.mp1-V2.23\k35mv1_64_op01_alps-mp-m0.mp1-V2.23_user
tencent.mm 版本V6.3.8.56_re6b2553
当时的CPU主频221000/ 988000KHz:
01-01 04:28:43.565 <7>[16560.006725] (0)[56:cfinteractive][name:mt_cpufreq&][Power/cpufreq] @_mt_cpufreq_set_locked(): Vproc = 950mv, freq = 221000 KHz
01-01 04:28:44.366 <7>[16560.806949] (0)[56:cfinteractive][name:mt_cpufreq&][Power/cpufreq] @_mt_cpufreq_set_locked(): Vproc = 1250mv, freq = 988000 KHz
M版本测试数据耗时install(34.077s)+launch(61.369ms+19.889s)=54s:
01-01 04:28:03.349302 1617 1661 I PackageManager.DexOptimizer: Running dexopt (dex2oat) on: /data/app/vmdl1857097406.tmp/base.apk pkg=com.tencent.mm isa=arm vmSafeMode=false debuggable=false oatDir = /data/app/vmdl1857097406.tmp/oat
01-01 04:28:03.471265 5654 5654 I dex2oat : Starting dex2oat.
01-01 04:28:37.548439 5654 5654 I dex2oat : dex2oat took 34.077s (threads: 4) arena alloc=23MB java alloc=14MB native alloc=88MB free=5MB 01-01 04:28:54.538837 5725 5725 I dex2oat : /system/bin/dex2oat --dex-file=/data/user/0/com.tencent.mm/app_dex/secondary-1.dex.jar --oat-file=/data/user/0/com.tencent.mm/app_cache/secondary-1.dex.dex
01-01 04:28:54.538837 5725 5725 I dex2oat : /system/bin/dex2oat --dex-file=/data/user/0/com.tencent.mm/app_dex/secondary-1.dex.jar --oat-file=/data/user/0/com.tencent.mm/app_cache/secondary-1.dex.dex
01-01 04:28:54.599338 5725 5725 I dex2oat : dex2oat took 61.369ms (threads: 4) arena alloc=3KB java alloc=20KB native alloc=921KB free=870KB
01-01 04:28:54.675067 5730 5730 I dex2oat : /system/bin/dex2oat --dex-file=/data/user/0/com.tencent.mm/app_dex/secondary-2.dex.jar --oat-file=/data/user/0/com.tencent.mm/app_cache/secondary-2.dex.dex
01-01 04:29:14.563627 5730 5730 I dex2oat : dex2oat took 19.889s (threads: 4) arena alloc=5MB java alloc=8MB native alloc=45MB free=4MB
k35 M版本测试版本:
\\10.15.11.230\public1\ALPS_load\alps-mp-m0.mp1\alps-mp-m0.mp1-V2.27\k35v1_64_op02_alps-mp-m0.mp1-V2.27_user
tencent.mm 版本V6.3.8.56_re6b2553
当时的CPU主频299000/1300000 KHz:
01-01 01:29:08.957 <7>[ 5573.215146] (1)[57:cfinteractive][name:mt_cpufreq&][Power/cpufreq] @_mt_cpufreq_set_locked(): Vproc = 950mv, freq = 299000 KHz
01-01 01:29:08.967 <7>[ 5573.225164] (1)[57:cfinteractive][name:mt_cpufreq&][Power/cpufreq] @_mt_cpufreq_set_locked(): Vproc = 1118mv, freq = 1300000 KHz
M版本测试数据耗时install(24.303s)+launch(45.461ms+13.574s)=38s, 可以看到K35比K35m快16s:
01-01 01:28:46.130507 2948 3018 I PackageManager.DexOptimizer: Running dexopt (dex2oat) on: /data/app/vmdl1834204165.tmp/base.apk pkg=com.tencent.mm isa=arm vmSafeMode=false debuggable=false oatDir = /data/app/vmdl1834204165.tmp/oat
01-01 01:28:46.215408 5590 5590 I dex2oat : Starting dex2oat.
0-01 01:29:10.519144 5590 5590 I dex2oat : dex2oat took 24.303s (threads: 4) arena alloc=22MB java alloc=14MB native alloc=88MB free=5MB
01-01 01:29:23.273697 5677 5677 I dex2oat : /system/bin/dex2oat --dex-file=/data/user/0/com.tencent.mm/app_dex/secondary-1.dex.jar --oat-file=/data/user/0/com.tencent.mm/app_cache/secondary-1.dex.dex
01-01 01:29:23.318485 5677 5677 I dex2oat : dex2oat took 45.461ms (threads: 4) arena alloc=3KB java alloc=20KB native alloc=921KB free=870KB
01-01 01:29:23.379928 5682 5682 I dex2oat : /system/bin/dex2oat --dex-file=/data/user/0/com.tencent.mm/app_dex/secondary-2.dex.jar --oat-file=/data/user/0/com.tencent.mm/app_cache/secondary-2.dex.dex
01:29:36.954313 5682 5682 I dex2oat : dex2oat took 13.574s (threads: 4) arena alloc=4MB java alloc=8MB native alloc=45MB free=4MB
因此碰到6735平台dex2oat慢,先判断是35m还是35, 再尝试修改CPU 频率测试
[FAQ17683]如何调整CPU corenum, freq, policy
[FAQ09538][CPU DVFS/Hotplug]运行时,把CPU固定在特定频率/特定核数的办法
M版本:
由于APK安装时传递下来的APK路径不包含PKG信息无法生效,但是对于一些jar包,可以判断oat保存的路径,因为往往会在路径中透露pkg的信息。可以利用此判断是否是我们关注的jar包在优化插件。
如下的Log所示:
01-01 08:34:27.063 I/dex2oat ( 7714): /system/bin/dex2oat --runtime-arg -classpath --runtime-arg --instruction-set=arm --instruction-set-features=default --runtime-arg -Xrelocate --boot-image=/system/framework/boot.art --dex-file=/data/data/com.tencent.mm/app_dex/secondary-2.dex.jar --oat-fd=62 --oat-location=/data/data/com.tencent.mm/app_cache/secondary-2.dex.dex --runtime-arg -Xms64m --runtime-arg -Xmx512m
--dex-file,--oat-location都透露了pkg的信息。
因此,可以判断这两个参数是否包含了我们的要求的pkg信息,如果有的话,可以设置
compiler_filter_string为interpreter-only
N版本上面,也是判断上面的参数,这后,满足条件之后,可以想办法调用
compiler_options_->SetCompilerFilter(kSpaceProfile);
对于L和M版本中如果是安装APP可以在commands.cpp或者commands.c(L版本)中进行修改:
47staticvoidrun_dex2oat(intzip_fd,intoat_fd,constchar*input_file_name,748constchar*output_file_name,intswap_fd,constchar*pkgname,constchar*instruction_set,749boolvm_safe_mode,booldebuggable)
中判断pkg name然后,设置:have_dex2oat_compiler_filter_flag的值为interpreter-only