Android TV : 平台性能调试方法
硬件相关CPU/GPU/DRAM/EMMC
1.指令调试(MTK):
============CPU============
busybox mpstat //查看各cpu的占用率,比top更平滑
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(小核)上运行
注:如果手动绑定失败,可能是配置成了前台进程(rc文件中配置:writepid /dev/cpuset/top-app/tasks /dev/stune/rt/tasks),那么它被限制在大核上,那么需要修改一下该进程的group。
例如改成后台进程:echo 493 > /dev/cpuset/background/tasks ,然后就可以配置绑定到小核。根据需要也可用修改各group的cpu调度策略:
write /dev/cpuset/top-app/cpus 0-7
write /dev/cpuset/foreground/boost/cpus 0-5
write /dev/cpuset/foreground/cpus 0-5
write /dev/cpuset/background/cpus 0-1
write /dev/cpuset/system-background/cpus 0-3
============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
文件中. 一般国内的手机厂商都会做修改, 根据手机配置不同而不同, 可以直接打开查看与修改。
其中和虚拟机内存相关的主要有以下三个:
-
dalvik.vm.heapstartsize
– App启动后,系统分配给它的Heap初始大小,随着App使用可增加。
-
dalvik.vm.heapgrowthlimit
– 默认情况下, App可使用的Heap的最大值, 超过这个值就会产生OOM.
-
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 阅读(1226) 评论(0) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY