黄山派小智 LVGL显示性能分析
显示性能参数显示分析。
简介
在做小智相关图形化界面的开发学习过程中,通常会遇到有关界面性能的问题。为了更好的分析优化性能相关问题,需要使用一定的工具来辅助分析,更好的优化相关性能。
黄山派小智中自带了相关帧率、平均渲染时间显示的相关宏,可以打开相关宏,进行性能分析。
前置准备
需要小智相关代码,同时将小智代码里的SDK拉去到本地中,可以参考官方源代码构建相关文档:官方源码构建文档
拉取小智SDK:git 下输入:git submodule update --init --recursive
FPS显示开关/位置调整
显示开关
打开menuconfig工具,输入 /FPS,选择第二个选项勾选打开,编译下载后,即可在界面右下角位置显示FPS等相关性能参数。
需要注意的是,小智相关的代码使用的都是LVGL V9 相关的代码



位置调整
1、性能相关参数默认显示在屏幕的右下角位置上,但是由于显示屏的圆角问题,这里的部分显示信息会被遮挡,所以可以配置相关选项来设置显示的位置。
2、输入 /LV_PERF 可以看到其中有关位置相关的选项
3、找到SDK下‘lv_conf_kconfig.h’文件,修改里面相关位置的宏:这里我把原理来的CONFIG_LV_PERF_MONITOR_ALIGN_BOTTOM_MID改为了LV_PERF_MONITOR_ALIGN_BOTTOM_MID编译下载后FPS相关信息即可显示在对应位置。
正常情况完成到第二步即可显示到对应位置上,这里应该是适配时忘记了修改,后续应该会修改回来。



性能代码分析
可以看到,默认显示的数据有 :帧率FPS、CPU利用率、平均渲染时间和平均刷新时间,其中前面的54ms是后面的平均渲染时间52ms加上平均刷新时间2ms

代码位置
具体代码位置在:
sdk/external/lvgl_v9/src/others/sysmon/lv_sysmon.c
文件下包含了相关性能计算的函数代码和参数
关键代码
关键参数:
性能统计间隔时间:LV_SYSMON_REFR_PERIOD_DEF
两次性能统计间的间隔时间,默认设置为300ms,每300ms统计一次。
各个参数统计函数
这个函数统计关键的参数包括有:
刷新总时间:refr_elaps_sum刷新次数:refr_cnt
渲染总时间:render_elaps_sum渲染次数:render_cnt
渲染时间中包含的刷新时间:flush_in_render_start
不包含在渲染时间中的刷新时间:flush_not_in_render_start
static void perf_monitor_disp_event_cb(lv_event_t * e)
{
lv_display_t * disp = lv_event_get_target(e);
lv_event_code_t code = lv_event_get_code(e);
lv_sysmon_perf_info_t * info = &disp->perf_sysmon_info;
switch(code) {
case LV_EVENT_REFR_START: //刷新事件开始
info->measured.refr_interval_sum += lv_tick_elaps(info->measured.refr_start);
info->measured.refr_start = lv_tick_get();
break;
case LV_EVENT_REFR_READY: //刷新事件完成
info->measured.refr_elaps_sum += lv_tick_elaps(info->measured.refr_start);
info->measured.refr_cnt++; //刷新次数统计
break;
case LV_EVENT_RENDER_START: //渲染事件开始
info->measured.render_in_progress = 1;
info->measured.render_start = lv_tick_get();
break;
case LV_EVENT_RENDER_READY: //渲染事件完成
info->measured.render_in_progress = 0;
info->measured.render_elaps_sum += lv_tick_elaps(info->measured.render_start);
info->measured.render_cnt++; //渲染次数统计
break;
case LV_EVENT_FLUSH_START:
case LV_EVENT_FLUSH_WAIT_START: //刷新等待开始
if(info->measured.render_in_progress) {
info->measured.flush_in_render_start = lv_tick_get();
}
else {
info->measured.flush_not_in_render_start = lv_tick_get();
}
break;
case LV_EVENT_FLUSH_FINISH:
case LV_EVENT_FLUSH_WAIT_FINISH: //刷新等待结束
if(info->measured.render_in_progress) {
info->measured.flush_in_render_elaps_sum += lv_tick_elaps(info->measured.flush_in_render_start);
}
else {
info->measured.flush_not_in_render_elaps_sum += lv_tick_elaps(info->measured.flush_not_in_render_start);
}
break;
case LV_EVENT_DELETE:
lv_timer_delete(disp->perf_sysmon_backend.timer);
lv_subject_deinit(&disp->perf_sysmon_backend.subject);
break;
default:
break;
}
}
各个参数计算函数
**这个函数是相关性能指标的统计包括:
1、FPS计算:calculated.fps-> 刷新次数除以刷新间隔时间
刷新间隔时间:time_since_last_report->LV_SYSMON_REFR_PERIOD_DEF默认300ms
FPS限制:LV_MIN函数限制了显示的最大帧率30FPS
2、CPU利用率:calculated.cpu-> 100 - CPU空闲率
CPU空闲率统计函数:LV_SYSMON_GET_IDLE();
3、平均刷新时间:refr_avg_time刷新总时间/刷新次数
4、平均刷新传输时间:flush_avg_time(渲染总时间加上不在渲染中的刷新时间)/ 渲染次数
表示将渲染好的图像数据传输到显示设备所需的平均时间
5、平均渲染时间:render_avg_time(渲染总时间-渲染中的刷新时间)/ 渲染次数
6、累计CPU平均使用率:cpu_avg_total(旧平均值 × (计数-1) + 新值) ÷ 计数
系统从启动到当前时刻的平均 CPU 使用率
7、累计平均帧率:fps_avg_total新的累计平均值 = (旧平均值 × (计数-1) + 新值) ÷ 计数
系统从启动到当前时刻的平均帧率
**
static void perf_update_timer_cb(lv_timer_t * t)
{
lv_display_t * disp = lv_timer_get_user_data(t);
uint32_t LV_SYSMON_GET_IDLE(void);
lv_sysmon_perf_info_t * info = &disp->perf_sysmon_info;
info->calculated.run_cnt++; /* 增加运行计数(用于移动平均计算) */
uint32_t time_since_last_report = lv_tick_elaps(info->measured.last_report_timestamp); /* 计算从上一次报告到现在的时间间隔 */
lv_timer_t * disp_refr_timer = lv_display_get_refr_timer(NULL); /* 获取显示刷新定时器和其周期 */
uint32_t disp_refr_period = disp_refr_timer->period;
info->calculated.fps = info->measured.refr_interval_sum ? (1000 * info->measured.refr_cnt / time_since_last_report) : 0;/* 1. 计算帧率(FPS) */
info->calculated.fps = LV_MIN(info->calculated.fps,
1000 / disp_refr_period); /*Limit due to possible off-by-one error*/
info->calculated.cpu = 100 - LV_SYSMON_GET_IDLE(); /* 2. 计算CPU使用率 */
info->calculated.refr_avg_time = info->measured.refr_cnt ? (info->measured.refr_elaps_sum / info->measured.refr_cnt) :
0;/* 3. 计算平均刷新总时间 */
info->calculated.flush_avg_time = info->measured.render_cnt ?
((info->measured.flush_in_render_elaps_sum + info->measured.flush_not_in_render_elaps_sum)
/ info->measured.render_cnt) : 0; /* 4. 计算平均刷新传输时间 */
/*Flush time was measured in rendering time so subtract it*/
info->calculated.render_avg_time = info->measured.render_cnt ? ((info->measured.render_elaps_sum -
info->measured.flush_in_render_elaps_sum) /
info->measured.render_cnt) : 0;/* 5. 计算平均纯渲染时间 */
info->calculated.cpu_avg_total = ((info->calculated.cpu_avg_total * (info->calculated.run_cnt - 1)) +
info->calculated.cpu) / info->calculated.run_cnt; /* 6. 计算累计平均CPU使用率 */
info->calculated.fps_avg_total = ((info->calculated.fps_avg_total * (info->calculated.run_cnt - 1)) +
info->calculated.fps) / info->calculated.run_cnt; /* 7. 计算累计平均帧率 */
lv_subject_set_pointer(&disp->perf_sysmon_backend.subject, info);
lv_sysmon_perf_info_t prev_info = *info;/* 保存需要保留的数据 */
lv_memzero(info, sizeof(lv_sysmon_perf_info_t));/* 清零性能信息结构体(准备下一个统计周期) */
info->measured.refr_start = prev_info.measured.refr_start;
info->calculated.cpu_avg_total = prev_info.calculated.cpu_avg_total;
info->calculated.fps_avg_total = prev_info.calculated.fps_avg_total;
info->calculated.run_cnt = prev_info.calculated.run_cnt;
info->measured.last_report_timestamp = lv_tick_get();
}
相关参数的显示
lv_label_set_text_fmt函数将相关参数显示到屏幕上
static void perf_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
{
lv_obj_t * label = lv_observer_get_target(observer);
const lv_sysmon_perf_info_t * perf = lv_subject_get_pointer(subject);
#if LV_USE_PERF_MONITOR_LOG_MODE
LV_UNUSED(label);
LV_LOG("sysmon: "
"%" LV_PRIu32 " FPS (refr_cnt: %" LV_PRIu32 " | redraw_cnt: %" LV_PRIu32"), "
"refr %" LV_PRIu32 "ms (render %" LV_PRIu32 "ms | flush %" LV_PRIu32 "ms), "
"CPU %" LV_PRIu32 "%%\n",
perf->calculated.fps, perf->measured.refr_cnt, perf->measured.render_cnt,
perf->calculated.refr_avg_time, perf->calculated.render_avg_time, perf->calculated.flush_avg_time,
perf->calculated.cpu);
#else
lv_label_set_text_fmt(
label,
"%" LV_PRIu32" FPS, %" LV_PRIu32 "%% CPU\n"
"%" LV_PRIu32" ms (%" LV_PRIu32" | %" LV_PRIu32")",
perf->calculated.fps, perf->calculated.cpu,
perf->calculated.render_avg_time + perf->calculated.flush_avg_time,
perf->calculated.render_avg_time, perf->calculated.flush_avg_time
);
#endif /*LV_USE_PERF_MONITOR_LOG_MODE*/
}
如果想要显示更多相关参数信息可以修改类似修改代码
lv_label_set_text_fmt(
label,
"%" LV_PRIu32" render_cnt, %" LV_PRIu32" render_time\n" //添加渲染次数、渲染总时间显示
"%" LV_PRIu32" time , %" LV_PRIu32" refer_cnt\n"//添加渲染总时间加上渲染外刷新时间、刷新次数显示
"%" LV_PRIu32" FPS, %" LV_PRIu32 "%% CPU\n"
"%" LV_PRIu32" ms (%" LV_PRIu32" | %" LV_PRIu32")",
perf->measured.render_cnt, perf->measured.render_elaps_sum - perf->measured.flush_in_render_elaps_sum,
perf->measured.render_elaps_sum + perf->measured.flush_not_in_render_elaps_sum,perf->measured.refr_cnt,
perf->calculated.fps, perf->calculated.cpu,
perf->calculated.render_avg_time + perf->calculated.flush_avg_time,
perf->calculated.render_avg_time, perf->calculated.flush_avg_time
);
更多推荐




所有评论(0)