sheldon_blogs

Android TV : 平台性能调试方法

硬件相关CPU/GPU/DRAM/EMMC

1.指令调试(MTK):

============CPU============
cat /proc/cpuinfo //查看CPU核数,arm版本等信息
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies //cpu支持的频率档位
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq //当前cpu运行频率
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors //CPU支持的运行模式
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor //CPU当前的运行模式

cat /proc/1486/task/1503/stat //查看1486进程的1503线程的优先级
busybox renice -10 1503 //修改线程1503的优先级(n+renice = 24-10)

busybox chrt -h
-p Operate on PID
-r Set SCHED_RR class (实时进程的轮流调度)
-f Set SCHED_FIFO class (实时进程的先进一次处理完)
-o Set SCHED_OTHER class (普通进程)
-m Show min/max priorities

busybox chrt -f -p 1 1486 //设置进程的优先级(0~99表示实时进程,100~139表示普通进程,跟renice相比chrt可以把进程改为实时进程,renice只能是普通进程即nice值-20~19对应100~139)

taskset -p 1486 //调整进程所使用的CPU
pid 1486's current affinity mask: f (f实际是二进制4个低位均为1的bitmask,每一个1对应1个CPU,即在CPU0~3上运行)

taskset -p 1 1486 //指定1486在CPU0上运行

busybox mpstat //查看各cpu的占用率,比top更平滑

============GPU============
cat /sys/module/mali_kbase/parameters/mali_gpu_clock //GPU运行频率
cat /sys/module/mali_kbase/parameters/mali_gpu_utilization //GPU实时值,最大255,如果一直很大则表示gpu满了

 

2.bootchart(系统启动时间)

Linux主机需要先安装工具:
sudo apt-get install pybootchartgui
sudo apt-get install bootchart

1.touch /data/bootchart/enabled //创建文件启动bootchart,重启
2.adb pull /data/bootchart/ //拷贝bootchart目录出来,包含4个文件:header proc_diskstats.log proc_ps.log proc_stat.log
3.tar -czf bootchart.tgz *命令将这4个文件打包起来,然后执行bootchart bootchart.tgz 生成bootchart.png查看

 

3.ZRAM(虚拟内存):

zram swap 分区的应用程序,所占用的内存压缩率为 0.4,里面可以存放后台临时不用的应用程序,变相扩展了内存的大小。

(1)如果是将 zram 编译成模块,则可以使用下面命令动态加载,这个命令会创建 4 个设备 /dev/zram{0,1,2,3}

modprobe zram num_devices=4

如果是直接将 zram 编译到内核,那只能在代码里面直接修改 num_devices,3.15 之前的版本代码路径是 drivers/staging/zram/zram_drv.c,3.15 及之后的版本代码路径是 ./drivers/block/zram/zram_drv.c ,默认 zram 设备个数是一个。

(2)内核3.15 版本及以后的版本支持设置压缩流个数进行并行执行,避免单个压缩流卡死

  • 查看压缩流的最大个数,默认是 1
  • cat /sys/block/zram0/max_comp_streams
  • 设定压缩流的最大个数
  • echo 3 > /sys/block/zram0/max_comp_streams
  • 查看目前支持的压缩算法
  • cat /sys/block/zram0/comp_algorithm
    lzo [lz4]

     

  • 修改压缩算法

  • echo lzo > /sys/block/zram0/comp_algorithm

(3)zram 内存大小设定,大小建议为总内存的 10%-25%

  • 可以使用数值直接设置大小,单位是 bytes
  • echo $((512*1024*1024)) > /sys/block/zram0/disksize
  • 也可以使用带内存单位作为后缀的方式设置内存大小
  • echo 256K > /sys/block/zram0/disksize
    echo 512M > /sys/block/zram0/disksize
    echo 1G > /sys/block/zram0/disksize
  • 启用 zram 设备为 swap

  • mkswap /dev/zram0

    swapon /dev/zram0

  • reset zram后,zram的大小就会变为0,在使用之前必须需要设置大小

  • echo 1 > /sys/block/zram0/reset
  • 改变zram的大小,设置之前需要先关闭设备并reset

  • root@test:/data # cat /proc/swaps 
    Filename                Type        Size    Used    Priority
    /dev/zram0                              partition   409596  4456    -1
    root@test:/data # swapoff /dev/zram0 
    root@test:/data # cat /proc/swaps    
    Filename                Type        Size    Used    Priority

      root@test:/data # echo 1 > /sys/block/zram0/reset
      root@test:/data # echo $((512*1024*1024)) > /sys/block/zram0/disksize

     

4.perfetto(系统跟踪):

Perfetto工具是Android下一代全新的统一的trace收集和分析框架,可以抓取平台和app的trace信息,用来取代systrace。

setprop persist.traced.enable 1 //开启,默认0关闭
logcat -s perfetto //通过log查看是否开启成功

perfetto -h //查看帮助信息
其中 --out是用来指定trace输出文件,--config 是用来指定配置的,也就是像抓多长时间,间隔多久把内存数据写回文件,抓取哪些tracepoints等等,这个config文件内容。

例如:adb shell perfetto -o /data/misc/perfetto-traces/trace_file.perfetto-trace -t 20s  sched freq idle am wm gfx view binder_driver hal dalvik camera input res memory

可以自己手动编写,也可以用Perfetto UI网站(https://ui.perfetto.dev/#!/record)生成:

 

 可以拷贝出来直接在终端执行:

perfetto \
-c - --txt \
-o /data/misc/perfetto-traces/trace \
<<EOF

buffers: {
size_kb: 63488
fill_policy: DISCARD
}
buffers: {
size_kb: 2048
fill_policy: DISCARD
}
data_sources: {
config {
name: "android.gpu.memory"
}
}
data_sources: {
config {
name: "linux.process_stats"
target_buffer: 1
process_stats_config {
scan_all_processes_on_start: true
}
}
}
data_sources: {
config {
name: "linux.sys_stats"
sys_stats_config {
meminfo_period_ms: 1000
}
}
}
data_sources: {
config {
name: "android.java_hprof"
target_buffer: 0
java_hprof_config {
}
}
}
data_sources: {
config {
name: "linux.ftrace"
ftrace_config {
ftrace_events: "sched/sched_switch"
ftrace_events: "power/suspend_resume"
ftrace_events: "sched/sched_wakeup"
ftrace_events: "sched/sched_wakeup_new"
ftrace_events: "sched/sched_waking"
ftrace_events: "power/gpu_frequency"
ftrace_events: "gpu_mem/gpu_mem_total"
ftrace_events: "regulator/regulator_set_voltage"
ftrace_events: "regulator/regulator_set_voltage_complete"
ftrace_events: "power/clock_enable"
ftrace_events: "power/clock_disable"
ftrace_events: "power/clock_set_rate"
ftrace_events: "mm_event/mm_event_record"
ftrace_events: "kmem/rss_stat"
ftrace_events: "ion/ion_stat"
ftrace_events: "dmabuf_heap/dma_heap_stat"
ftrace_events: "kmem/ion_heap_grow"
ftrace_events: "kmem/ion_heap_shrink"
ftrace_events: "sched/sched_process_exit"
ftrace_events: "sched/sched_process_free"
ftrace_events: "task/task_newtask"
ftrace_events: "task/task_rename"
buffer_size_kb: 2048
drain_period_ms: 250
}
}
}
duration_ms: 15000

EOF

 

另外在Perfetto里面默认集成了一个test配置,你可以使用如下命令抓取一个使用test config的trace文件:

perfetto --config :test --out /data/misc/perfetto-traces/trace //使用内置的test配置,然后输出到/data/misc/perfetto-traces/trace

抓取完后,把/data/misc/perfetto-traces/trace文件内容pull出来,然后使用Perfetto UI网站打开即可,如下所示:

 

PS:开关framework
setprop vold.decrypt trigger_shutdown_framework #disable
setprop vold.decrypt trigger_restart_framework #enable

 

5、Android VM的内存空间

Android是一个多任务系统, 为了保证多任务的运行, Android给每个App可使用的Heap大小设定了一个限定值.

这个值是系统设置的prop值, 保存在System/build.prop文件中. 一般国内的手机厂商都会做修改, 根据手机配置不同而不同, 可以直接打开查看与修改。

其中和虚拟机内存相关的主要有以下三个:

  1. dalvik.vm.heapstartsize

    – App启动后,系统分配给它的Heap初始大小,随着App使用可增加。

  2. dalvik.vm.heapgrowthlimit

    – 默认情况下, App可使用的Heap的最大值, 超过这个值就会产生OOM.

  3. dalvik.vm.heapsize

    – 如果App的manifest文件中配置了largeHeap属性, 那么App可使用的Heap的最大值为此项设定值。

    1
    2
    3
    4
    <application
    android:largeHeap="true">
    ...
    </application>

  所以对于同一个手机,不开启largeHeap属性时与多进程时,每个APP的虚拟机分配的内存的上限都是heapgrowthlimit

 

6、使用drop cache机制

#清理文件页、目录项、inodes等各种缓存

echo 3 > /proc/sys/vm/drop_caches

可以考虑在以下情况主动回收内存:

①顶层APP退出、回到home界面等。

参考系统源码:frameworks/base/core/java/android/app/ActivityThread.java 中 的 scheduleTrimMemory方法,通过level值可判断APP的运行状态。

public void scheduleTrimMemory(int level) {
    final Runnable r = PooledLambda.obtainRunnable(ActivityThread::handleTrimMemory,
            ActivityThread.this, level);
    // Schedule trimming memory after drawing the frame to minimize jank-risk.
    Choreographer choreographer = Choreographer.getMainThreadInstance();
    if (choreographer != null) {
        choreographer.postCallback(Choreographer.CALLBACK_COMMIT, r, null);
    } else {
        mH.post(r);
    }
}

具体 level 值的定义:

  • TRIM_MEMORY_UI_HIDDEN:App 的所有 UI 界面被隐藏,最常见的就是 App 被 home 键或者 back 键,置换到后台了。
  • TRIM_MEMORY_RUNNING_MODERATE:表示 App 正常运行,并且不会被杀掉,但是目前手机内存已经有点低了,系统可能会根据 LRU List 来开始杀进程。
  • TRIM_MEMORY_RUNNING_LOW:表示 App正常运行,并且不会被杀掉。但是目前手机内存已经非常低了。
  • TRIM_MEMORY_RUNNING_CRITICAL:表示 App 正在正常运行,但是系统已经开始根据 LRU List 的缓存规则杀掉了一部分缓存的进程。这个时候应该尽可能的释放掉不需要的内存资源,否者系统可能会继续杀掉其他缓存中的进程。
  • TRIM_MEMORY_BACKGROUND:表示 App 退出到后台,并且已经处于 LRU List 比较靠后的位置,暂时前面还有一些其他的 App 进程,暂时不用担心被杀掉。
  • TRIM_MENORY_MODERATE:表示 App 退出到后台,并且已经处于 LRU List 中间的位置,如果手机内存仍然不够的话,还是有被杀掉的风险的。
  • TRIM_MEMORY_COMPLETE:表示 App 退出到后台,并且已经处于 LRU List 比较考靠前的位置,并且手机内存已经极低,随时都有可能被系统杀掉。

 

②系统原生内存检测逻辑中判断是否发生低内存情况,不同Android版本代码逻辑有差异,具体查找 ADJ_MEM_FACTOR 关键字找到对应的处理逻辑。

// Now determine the memory trimming level of background processes.
// Unfortunately we need to start at the back of the list to do this
// properly.  We only do this if the number of background apps we
// are managing to keep around is less than half the maximum we desire;
// if we are keeping a good number around, we'll let them use whatever
// memory they want.
final int numCachedAndEmpty = numCached + numEmpty;
int memFactor;
if (numCached <= mConstants.CUR_TRIM_CACHED_PROCESSES
        && numEmpty <= mConstants.CUR_TRIM_EMPTY_PROCESSES) {
    if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) {
        memFactor = ProcessStats.ADJ_MEM_FACTOR_CRITICAL;
    } else if (numCachedAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) {
        memFactor = ProcessStats.ADJ_MEM_FACTOR_LOW;
    } else {
        memFactor = ProcessStats.ADJ_MEM_FACTOR_MODERATE;
    }
} else {
    memFactor = ProcessStats.ADJ_MEM_FACTOR_NORMAL;
}
  • 若是后台进程数(包含空进程)<= 3 ,说明内存很是紧张,內存裁剪因子就是ProcessStats.ADJ_MEM_FACTOR_CRITICAL
  • 若是后台进程数(包含空進程)<= 5 ,说明内存比较紧张,內存裁剪因子就是ProcessStats.ADJ_MEM_FACTOR_LOW
  • 若是后台进程数(包含空進程)> 5,可仍是不足正常的后台数目 ,內存裁剪因子就是ProcessStats.ADJ_MEM_FACTOR_MODERATE

内存裁剪因子定义值:

int ADJ_MEM_FACTOR_NORMAL = 0;
int ADJ_MEM_FACTOR_MODERATE = 1;
int ADJ_MEM_FACTOR_LOW = 2;
int ADJ_MEM_FACTOR_CRITICAL = 3;

可以发现与第①点中的level值对应起来了。

 

7、默认开启CPU性能模式

write /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor performance

 

8、限制cache进程数

具体查看 ActivityManagerConstants.java 文件,对 MAX_CACHED_PROCESSES 变量进行定制。

 

9、配置内核参数来增加swap的使用

swappiness=0的时候表示最大限度使用物理内存,然后才是 swap空间,swappiness=100的时候表示积极的使用swap分区,并且把内存上的数据及时的搬运到swap空间里面。在linux里面,默认设置swappiness这个值等于60。

修改指令:

console:/ # sysctl vm.swappiness=100                                             
vm.swappiness = 100
console:/ # cat /proc/sys/vm/swappiness                                        
100

 

10、进程/线程绑定在某一个 CPU 核心上

当有多个同时执行「计算密集型」的线程,为了防止因为切换到不同的核心,而导致缓存命中率下降的问题,可以使用 Linux 上提供的 sched_setaffinity 方法,来实现将进程或线程绑定到某个 CPU 核心上,这样性能可以得到非常可观的提升。具体使用可参考另一篇文章:https://www.cnblogs.com/blogs-of-lxl/p/10926824.html

 

posted on 2022-05-27 16:39  sheldon_blogs  阅读(1064)  评论(0编辑  收藏  举报

导航