Android亮屏速度分析总结
前面聊的
最近在调试项目的亮屏速度,我们希望在按下power键后到亮屏这个时间能达到500ms以内,在rockchip 3399和3288上面的时间都不能达到要求,因此引发了一系列的调试之路。
计算按下power键到亮屏的时间
android 唤醒时间统计
刚开始的时候,我只在android阶段统计时间,也能看到时间的差异,但是不是最准确的,我统计的时间日志如下
01-18 09:13:40.992 683 772 d surfacecontrol: excessive delay in setpowermode(): 743ms
01-18 09:13:45.304 683 772 d surfacecontrol: excessive delay in setpowermode(): 757ms
01-18 09:13:49.559 683 772 d surfacecontrol: excessive delay in setpowermode(): 725ms
01-18 09:18:27.461 683 772 d surfacecontrol: excessive delay in setpowermode(): 741ms
01-18 09:18:32.766 683 772 d surfacecontrol: excessive delay in setpowermode(): 743ms
01-18 09:18:35.861 683 772 d surfacecontrol: excessive delay in setpowermode(): 745ms
01-18 09:18:38.345 683 772 d surfacecontrol: excessive delay in setpowermode(): 733ms
kernel从power到亮屏的时间统计
后来同事中的精英古总在他的代码上加入了从按下power键到亮屏的时间,直接通过printk打印,代码如下
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c old mode 100644 new mode 100755 index 17c3b94..2b39662 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -504,6 +504,7 @@ static int panel_simple_enable(struct drm_panel *panel) } p->enabled = true; + printk("%s exit\n", __func__); return 0; } diff --git a/drivers/input/keyboard/rk_keys.c b/drivers/input/keyboard/rk_keys.c old mode 100644 new mode 100755 index fed5ced..537b599 --- a/drivers/input/keyboard/rk_keys.c +++ b/drivers/input/keyboard/rk_keys.c @@ -134,6 +134,10 @@ static void keys_timer(unsigned long _data) key_dbg(pdata, "%skey[%s]: report event[%d] state[%d]\n", button->type == type_adc ? "adc" : "gpio", button->desc, button->code, button->state); + if(strcmp(button->desc, "power") == 0) + printk("%skey[%s]: report event[%d] state[%d]\n", + button->type == type_adc ? "adc" : "gpio", + button->desc, button->code, button->state); input_event(input, ev_key, button->code, button->state); input_sync(input); }
统计每个驱动的resume函数调用时间
上面的时间对我们调试非常有用,然后就需要细分到每个驱动的resume函数执行的时间,用的方法是我之前写过的,大概统计了下tp,lcd,sensor的resume时间,发现tp和lcd占用的时间非常多,然后跟同事一起看了下,同事把tp resume里面的代码用工作队列实现后速度明显有了提升。
然后有很长一段时间不知道干嘛,向打印其他每个驱动的resume时间,一直没找到方法,后面看到一个代码,非常有用。
kernel/drivers/base/power/main.c
static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info) { ktime_t calltime; u64 usecs64; int usecs; calltime = ktime_get(); usecs64 = ktime_to_ns(ktime_sub(calltime, starttime)); do_div(usecs64, nsec_per_usec); usecs = usecs64; if (usecs == 0) usecs = 1; pr_info("pm: %s%s%s of devices complete after %ld.%03ld msecs\n", info ?: "", info ? " " : "", pm_verb(state.event), usecs / usec_per_msec, usecs % usec_per_msec); }
这个函数用来打印resume的函数消耗的时间,但是如何去触发打印这个函数呢?
- 一定保证设备进入深度睡眠,串口也进入深度睡眠,没有任何打印后。
- 执行以下命令
echo n > /sys/module/printk/parameters/console_suspend //使控制台在suspend最后才关闭,这样可以打印出休眠过程完整信息 echo 1 > /sys/power/pm_print_times //使能调试变量
打印的log类似下面的
[ 37.031413] bcmsdh_sdmmc_resume exit
[ 37.082174] pm: resume of devices complete after 78.589 msecs
[ 37.085277] [bt_rfkill]: ** disable irq
[ 37.087645] restarting tasks ...
修改lcd配置减小resume时间
古总在调试过程中展现了非常厉害的功底,第一步就是修改了lcd的参数,让亮屏时间加快。修改如下
--- a/arch/arm/boot/dts/rk3288-pad.dts +++ b/arch/arm/boot/dts/rk3288-pad.dts @@ -169,10 +169,10 @@ dsi,lanes = <4>; prepare-delay-ms = <20>; - init-delay-ms = <20>; - enable-delay-ms = <100>; - disable-delay-ms = <20>; - unprepare-delay-ms = <20>; + //init-delay-ms = <20>; + enable-delay-ms = <1>; + disable-delay-ms = <1>; + unprepare-delay-ms = <1>; panel-init-sequence = [ 15 32 02 8f a5 15 01 02 83 00
修改drm 超时时间减小唤醒时间
这是最关键的,drm框架非常复杂,rk也是从开源的drm移植过来使用,在drm部分有个时间导致问题,最终跟rk拿到最新的patch让唤醒时间直接加速500ms.
我们在日志下发现问题,并给询问了rk,最终发现这部分代码没有更新到最新的部分。
hi rk:
为什么亮屏的时候有时候会打印这句vop等待超时?请问下这是什么意思。
[ 1211.293492] rockchip-vop ff930000.vop: wait win close timeout
[ 1211.293514] rockchip-vop ff930000.vop: [drm:vop_crtc_enable] update mode to 1200*1920, close all win
有时候却不会打印。
[ 1216.423283] rockchip-vop ff930000.vop: [drm:vop_crtc_enable] update mode to 12001920, close all win [ 1223.899741] rockchip-vop ff930000.vop: [drm:vop_crtc_enable] update mode to 12001920, close all win
[ 1234.386252] rockchip-vop ff930000.vop: [drm:vop_crtc_enable] update mode to 1200*1920, close all win
代码如下
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -139,6 +139,9 @@ #define to_vop_win(x) container_of(x, struct vop_win, base) #define to_vop_plane_state(x) container_of(x, struct vop_plane_state, base) +/*add by vendor_patch for seep up the drm vop driver at 2018/1/18 for rk defect #191554, vendor_patch pad100-193*/ +#define vendor_patch + struct vop_zpos { int win_id; int zpos; @@ -868,9 +871,15 @@ static void vop_disable_all_planes(struct vop *vop) vop_disable_allwin(vop); vop_cfg_done(vop); +#ifdef vendor_patch ret = readx_poll_timeout_atomic(vop_is_allwin_disabled, vop, active, active, + 0, 100 * 1000); +#else + ret = readx_poll_timeout_atomic(vop_is_allwin_disabled, + vop, active, active, 0, 500 * 1000); +#endif if (ret) dev_err(vop->dev, "wait win close timeout\n"); } @@ -2215,20 +2224,36 @@ static size_t vop_crtc_bandwidth(struct drm_crtc *crtc, u16 htotal = adjusted_mode->crtc_htotal; u16 vdisplay = adjusted_mode->crtc_vdisplay; int clock = adjusted_mode->crtc_clock; +#ifndef vendor_patch struct vop *vop = to_vop(crtc); const struct vop_data *vop_data = vop->data; +#endif struct vop_plane_state *vop_plane_state; struct drm_plane_state *pstate; struct vop_bandwidth *pbandwidth; struct drm_plane *plane; u64 bandwidth; int i, cnt = 0; +#ifdef vendor_patch + int plane_num = 0; +#endif if (!htotal || !vdisplay) return 0; +#ifndef vendor_patch pbandwidth = kmalloc_array(vop_data->win_size, sizeof(*pbandwidth), gfp_kernel); +#else + for_each_plane_in_state(state, plane, pstate, i) { + if (pstate->crtc != crtc || !pstate->fb) + continue; + plane_num++; + } + pbandwidth = kmalloc_array(plane_num, sizeof(*pbandwidth), + gfp_kernel); +#endif + if (!pbandwidth) return -enomem; @@ -2421,7 +2446,10 @@ static void vop_crtc_enable(struct drm_crtc *crtc) rockchip_set_system_status(sys_status); mutex_lock(&vop->vop_lock); vop_initial(crtc); - +#ifdef vendor_patch + vop_disable_allwin(vop); + vop_ctrl_set(vop, standby, 0); +#endif vop_ctrl_set(vop, dclk_pol, 1); val = (adjusted_mode->flags & drm_mode_flag_nhsync) ? 0 : bit(hsync_positive); @@ -2549,8 +2577,9 @@ static void vop_crtc_enable(struct drm_crtc *crtc) /* * enable vop, all the register would take effect when vop exit standby */ +#ifndef vendor_patch vop_ctrl_set(vop, standby, 0); - +#endif enable_irq(vop->irq); drm_crtc_vblank_on(crtc); mutex_unlock(&vop->vop_lock);
休眠唤醒流程图
从网上拷贝了个休眠唤醒的流程图,如果以后有问题需要分析的话,可以跟进这个流程去排查。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。如果你想了解更多相关内容请查看下面相关链接