简介

在做小智相关图形化界面的开发学习过程中,通常会遇到有关界面性能的问题。为了更好的分析优化性能相关问题,需要使用一定的工具来辅助分析,更好的优化相关性能。
黄山派小智中自带了相关帧率、平均渲染时间显示的相关宏,可以打开相关宏,进行性能分析。

前置准备

需要小智相关代码,同时将小智代码里的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
    );
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐