内容[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
private int performDexOptLI(PackageParser.Package pkg, String[] sharedLibraries,
153 String[] targetInstructionSets, boolean checkProfiles, String targetCompilerFilter) {
在这函数中,可以判断传递下来的pkg是否是我们需要的package,如果是的话,将targetCompilerFilter设置为speed-profile。
speed-profile会在安装的时候采用interperter-only,然后,运行一段时间之后,会将那些常用的方法优化成为speed模式。也就是说是有选择性的优化。
2.修改 L版本:
/art/dex2oat/dex2oat.cc 方法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(若上述方法无效):
1420 if (num_methods <= compiler_options_->GetNumDexMethodsThreshold()) {
1421 compiler_options_->SetCompilerFilter(CompilerOptions::kSpeed);
1422 VLOG(compiler) << "Below method threshold, compiling anyways";
1423 }
1424 }
1425
1426//mtk_add_begin
1427 static constexpr size_t kMinCompileDexSize = 4;
1428 if (!image_ && dex_files_.size() > kMinCompileDexSize) {
1429 compiler_options_->SetCompilerFilter(CompilerOptions::kInterpretOnly);
1430 LOG(INFO) << "Enable Whitelist Rules. Current Dex File Sizes:" << dex_files_.size();
1431 }
1432//mtk_add_end
1433
1434 return true;
1435 }
1436
1437 // Create and invoke the compiler driver. This will compile all the dex files.
1438 void Compile() {
1439 TimingLogger::ScopedTiming t("dex2oat Compile", timings_);
1440 compiler_phases_timings_.reset(new CumulativeLogger("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版本)中进行修改:
47static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
748 const char* output_file_name, int swap_fd, const char *pkgname, const char *instruction_set,
749 bool vm_safe_mode, bool debuggable)
中判断pkg name然后,设置:have_dex2oat_compiler_filter_flag的值为interpreter-only
|