add lcd_profile to help find performance issues

This commit is contained in:
xianjimli 2019-03-21 16:29:27 +08:00
parent b8366b06e8
commit a4592c4242
10 changed files with 2043 additions and 1379 deletions

View File

@ -51,6 +51,7 @@ NANOVG_BACKEND_PROJS=[];
COMMON_CCFLAGS=' -DTK_ROOT=\\\"'+TK_ROOT+'\\\" '
COMMON_CCFLAGS=COMMON_CCFLAGS+' -DWITH_STB_FONT '
#COMMON_CCFLAGS=COMMON_CCFLAGS+' -DENABLE_PERFORMANCE_PROFILE=1 '
#COMMON_CCFLAGS=COMMON_CCFLAGS+' -DWITH_FT_FONT '
COMMON_CCFLAGS=COMMON_CCFLAGS+' -DSTBTT_STATIC -DSTB_IMAGE_STATIC -DWITH_STB_IMAGE '
COMMON_CCFLAGS=COMMON_CCFLAGS+' -DWITH_VGCANVAS -DWITH_UNICODE_BREAK -DWITH_DESKTOP_STYLE '

View File

@ -1,4 +1,7 @@
# 最新动态
* 2019/03/21
* 增加lcd\_profile用于对绘制函数进行profile。
* 2019/03/20
* 支持编译Windows 32 位版本(感谢陈谭提供补丁)
* 修改资源生成脚本对于data数据不限制文件名(DATA类型的资源需带扩展名才能访问)。

View File

@ -1,5 +1,7 @@
## 优化技巧
### 一、优化提示
* memcpy是最快的贴图方式所以对于不透明的图片尽量保持与Framebuffer一致的格式这样可以直接使用memcpy贴图。
> 比如FrameBuffer的格式是BGR565请定义宏WITH\_BITMAP\_BGR565。
@ -41,3 +43,56 @@
* 使用3个framebuffer可以避免GUI等待和拷贝能够有效提高帧率有条件时尽量启用。
* 猜测往往是错误的请用函数time\_now\_ms去度量你怀疑的地方。
### 二、工具
如果定义全局的宏(在工程中定义)ENABLE\_PERFORMANCE\_PROFILE会使用lcd\_profile对全部绘制函数(图片、文字和填充等等)进行时间统计。当绘制一帧需要的时间超过25ms会打印一些信息:
```
#####################################
src/base/lcd_profile.c:326
-------------------------------------
total_cost=30
draw_image_cost=18 times=1
draw_text_cost=0 times=15
fill_cost=0 times=15
stroke_cost=0 times=15
end_frame_cost=10
-------------------------------------
```
也可以在lcd\_profile\_end\_frame函数里设置一个断点从profile对象上能查看到更详细的统计信息
```
uint32_t total_cost;
uint32_t swap_cost;
uint32_t flush_cost;
uint32_t draw_image_cost;
uint32_t draw_image_times;
uint32_t draw_image_pixels;
uint32_t draw_text_cost;
uint32_t draw_text_times;
uint32_t draw_text_chars;
uint32_t fill_cost;
uint32_t fill_times;
uint32_t fill_pixels;
uint32_t stroke_cost;
uint32_t stroke_times;
uint32_t stroke_pixels;
```
>参考[lcd_profile.c](https://github.com/zlgopen/awtk/blob/master/src/base/lcd_profile.c)

View File

@ -28,6 +28,8 @@
#include "base/wuxiaolin.inc"
#include "base/system_info.h"
#include "base/lcd_profile.h"
static ret_t canvas_draw_fps(canvas_t* c);
static rect_t* canvas_fix_rect(const rect_t* r, rect_t* o) {
@ -71,7 +73,7 @@ canvas_t* canvas_init(canvas_t* c, lcd_t* lcd, font_manager_t* font_manager) {
memset(c, 0x00, sizeof(canvas_t));
c->lcd = lcd;
c->lcd = lcd_profile_create(lcd);
c->font_manager = font_manager;
return c;
@ -205,6 +207,7 @@ ret_t canvas_set_stroke_color(canvas_t* c, color_t color) {
ret_t canvas_set_global_alpha(canvas_t* c, uint8_t alpha) {
return_value_if_fail(c != NULL, RET_BAD_PARAMS);
c->global_alpha = alpha;
lcd_set_global_alpha(c->lcd, alpha);
return RET_OK;

View File

@ -65,6 +65,7 @@ struct _canvas_t {
align_v_t text_align_v;
align_h_t text_align_h;
font_manager_t* font_manager;
uint8_t global_alpha;
};
/**

View File

@ -138,6 +138,7 @@ typedef enum _lcd_type_t {
*/
LCD_VGCANVAS
} lcd_type_t;
/**
* @class lcd_t
*
@ -258,7 +259,7 @@ struct _lcd_t {
*
* @param {lcd_t*} lcd lcd对象
* @param {rect_t*} dirty_rect
* @param {bool_t} anim_mode 线framebuffer
* @param {lcd_draw_mode_t} anim_mode 线framebuffer
*
* @return {ret_t} RET_OK表示成功
*/
@ -361,9 +362,9 @@ ret_t lcd_set_font_size(lcd_t* lcd, uint32_t font_size);
* @method lcd_draw_vline
* 线
* @param {lcd_t*} lcd lcd对象
* @param {xy_t*} x x坐标
* @param {xy_t*} y y坐标
* @param {xy_t*} h 线
* @param {xy_t} x x坐标
* @param {xy_t} y y坐标
* @param {xy_t} h 线
*
* @return {ret_t} RET_OK表示成功
*/
@ -373,9 +374,9 @@ ret_t lcd_draw_vline(lcd_t* lcd, xy_t x, xy_t y, wh_t h);
* @method lcd_draw_hline
* 线
* @param {lcd_t*} lcd lcd对象
* @param {xy_t*} x x坐标
* @param {xy_t*} y y坐标
* @param {xy_t*} w 线
* @param {xy_t} x x坐标
* @param {xy_t} y y坐标
* @param {xy_t} w 线
*
* @return {ret_t} RET_OK表示成功
*/
@ -393,13 +394,13 @@ ret_t lcd_draw_hline(lcd_t* lcd, xy_t x, xy_t y, wh_t w);
ret_t lcd_draw_points(lcd_t* lcd, point_t* points, uint32_t nr);
/**
* @method lcd_get_point_color_t
* @method lcd_get_point_color
* FrameBuffer的LCDfill_color
* @param {lcd_t*} lcd lcd对象
* @param {xy_t} x x坐标
* @param {xy_t} y y坐标
*
* @return {ret_t} RET_OK表示成功
* @return {color_t} RET_OK表示成功
*/
color_t lcd_get_point_color(lcd_t* lcd, xy_t x, xy_t y);

461
src/base/lcd_profile.c Normal file
View File

@ -0,0 +1,461 @@
/**
* File: lcd_profile.c
* Author: AWTK Develop Team
* Brief: wrap lcd for performance profile.
*
* Copyright (c) 2018 - 2019 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2018-03-21 Li XianJing <xianjimli@hotmail.com> created
*
*/
#include "tkc/mem.h"
#include "tkc/time_now.h"
#include "base/lcd_profile.h"
#ifdef ENABLE_PERFORMANCE_PROFILE
static ret_t lcd_profile_begin_frame(lcd_t* lcd, rect_t* dirty_rect) {
ret_t ret = RET_OK;
lcd_profile_t* profile = LCD_PROFILE(lcd);
profile->draw_image_times = 0;
profile->draw_image_cost = 0;
profile->draw_image_pixels = 0;
profile->draw_text_times = 0;
profile->draw_text_cost = 0;
profile->draw_text_chars = 0;
profile->fill_times = 0;
profile->fill_cost = 0;
profile->fill_pixels = 0;
profile->stroke_times = 0;
profile->stroke_cost = 0;
profile->stroke_pixels = 0;
profile->begin_frame_time = time_now_ms();
ret = lcd_begin_frame(profile->impl, dirty_rect, lcd->draw_mode);
return ret;
}
static ret_t lcd_profile_set_clip_rect(lcd_t* lcd, rect_t* rect) {
lcd_profile_t* profile = LCD_PROFILE(lcd);
return lcd_set_clip_rect(profile->impl, rect);
}
static ret_t lcd_profile_get_clip_rect(lcd_t* lcd, rect_t* rect) {
lcd_profile_t* profile = LCD_PROFILE(lcd);
return lcd_get_clip_rect(profile->impl, rect);
}
static ret_t lcd_profile_resize(lcd_t* lcd, wh_t w, wh_t h, uint32_t line_length) {
lcd_profile_t* profile = LCD_PROFILE(lcd);
return lcd_resize(profile->impl, w, h, line_length);
}
static ret_t lcd_profile_set_global_alpha(lcd_t* lcd, uint8_t alpha) {
lcd_profile_t* profile = LCD_PROFILE(lcd);
return lcd_set_global_alpha(profile->impl, alpha);
}
static ret_t lcd_profile_set_text_color(lcd_t* lcd, color_t color) {
lcd_profile_t* profile = LCD_PROFILE(lcd);
return lcd_set_text_color(profile->impl, color);
}
static ret_t lcd_profile_set_stroke_color(lcd_t* lcd, color_t color) {
lcd_profile_t* profile = LCD_PROFILE(lcd);
return lcd_set_stroke_color(profile->impl, color);
}
static ret_t lcd_profile_set_fill_color(lcd_t* lcd, color_t color) {
lcd_profile_t* profile = LCD_PROFILE(lcd);
return lcd_set_fill_color(profile->impl, color);
}
static ret_t lcd_profile_set_font_name(lcd_t* lcd, const char* name) {
lcd_profile_t* profile = LCD_PROFILE(lcd);
return lcd_set_font_name(profile->impl, name);
}
static ret_t lcd_profile_set_font_size(lcd_t* lcd, uint32_t font_size) {
lcd_profile_t* profile = LCD_PROFILE(lcd);
return lcd_set_font_size(profile->impl, font_size);
}
static ret_t lcd_profile_draw_vline(lcd_t* lcd, xy_t x, xy_t y, xy_t h) {
ret_t ret = RET_OK;
uint32_t cost = 0;
uint32_t start = time_now_ms();
lcd_profile_t* profile = LCD_PROFILE(lcd);
ret = lcd_draw_vline(profile->impl, x, y, h);
cost = time_now_ms() - start;
profile->stroke_times++;
profile->stroke_cost += cost;
profile->stroke_pixels += h;
return ret;
}
static ret_t lcd_profile_draw_hline(lcd_t* lcd, xy_t x, xy_t y, xy_t w) {
ret_t ret = RET_OK;
uint32_t cost = 0;
uint32_t start = time_now_ms();
lcd_profile_t* profile = LCD_PROFILE(lcd);
ret = lcd_draw_hline(profile->impl, x, y, w);
cost = time_now_ms() - start;
profile->stroke_times++;
profile->stroke_cost += cost;
profile->stroke_pixels += w;
return ret;
}
static ret_t lcd_profile_draw_points(lcd_t* lcd, point_t* points, uint32_t nr) {
ret_t ret = RET_OK;
uint32_t cost = 0;
uint32_t start = time_now_ms();
lcd_profile_t* profile = LCD_PROFILE(lcd);
ret = lcd_draw_points(profile->impl, points, nr);
cost = time_now_ms() - start;
profile->stroke_times++;
profile->stroke_cost += cost;
profile->stroke_pixels += nr;
return ret;
}
static color_t lcd_profile_get_point_color(lcd_t* lcd, xy_t x, xy_t y) {
lcd_profile_t* profile = LCD_PROFILE(lcd);
return lcd_get_point_color(profile->impl, x, y);
}
static ret_t lcd_profile_fill_rect(lcd_t* lcd, xy_t x, xy_t y, wh_t w, wh_t h) {
ret_t ret = RET_OK;
uint32_t cost = 0;
uint32_t start = time_now_ms();
lcd_profile_t* profile = LCD_PROFILE(lcd);
ret = lcd_fill_rect(profile->impl, x, y, w, h);
cost = time_now_ms() - start;
profile->fill_times++;
profile->fill_cost += cost;
profile->fill_pixels += w * h;
return ret;
}
static ret_t lcd_profile_stroke_rect(lcd_t* lcd, xy_t x, xy_t y, wh_t w, wh_t h) {
ret_t ret = RET_OK;
uint32_t cost = 0;
uint32_t start = time_now_ms();
lcd_profile_t* profile = LCD_PROFILE(lcd);
ret = lcd_stroke_rect(profile->impl, x, y, w, h);
cost = time_now_ms() - start;
profile->stroke_times++;
profile->stroke_cost += cost;
profile->stroke_pixels += w * h;
return ret;
}
static ret_t lcd_profile_draw_glyph(lcd_t* lcd, glyph_t* glyph, rect_t* src, xy_t x, xy_t y) {
ret_t ret = RET_OK;
uint32_t cost = 0;
uint32_t start = time_now_ms();
lcd_profile_t* profile = LCD_PROFILE(lcd);
ret = lcd_draw_glyph(profile->impl, glyph, src, x, y);
cost = time_now_ms() - start;
profile->draw_text_times++;
profile->draw_text_cost += cost;
profile->draw_text_chars++;
return ret;
}
static float_t lcd_profile_measure_text(lcd_t* lcd, const wchar_t* str, uint32_t nr) {
lcd_profile_t* profile = LCD_PROFILE(lcd);
return lcd_measure_text(profile->impl, str, nr);
}
static ret_t lcd_profile_draw_text(lcd_t* lcd, const wchar_t* str, uint32_t nr, xy_t x, xy_t y) {
ret_t ret = RET_OK;
uint32_t cost = 0;
uint32_t start = time_now_ms();
lcd_profile_t* profile = LCD_PROFILE(lcd);
ret = lcd_draw_text(profile->impl, str, nr, x, y);
cost = time_now_ms() - start;
profile->draw_text_times++;
profile->draw_text_cost += cost;
profile->draw_text_chars += nr;
return ret;
}
static ret_t lcd_profile_draw_image(lcd_t* lcd, bitmap_t* img, rect_t* src, rect_t* dst) {
ret_t ret = RET_OK;
uint32_t cost = 0;
uint32_t start = time_now_ms();
lcd_profile_t* profile = LCD_PROFILE(lcd);
ret = lcd_draw_image(profile->impl, img, src, dst);
cost = time_now_ms() - start;
profile->draw_image_times++;
profile->draw_image_cost += cost;
profile->draw_image_pixels += dst->w * dst->h;
return ret;
}
static ret_t lcd_profile_draw_image_matrix(lcd_t* lcd, draw_image_info_t* info) {
ret_t ret = RET_OK;
uint32_t cost = 0;
uint32_t start = time_now_ms();
lcd_profile_t* profile = LCD_PROFILE(lcd);
ret = lcd_draw_image_matrix(profile->impl, info);
cost = time_now_ms() - start;
profile->draw_image_times++;
profile->draw_image_cost += cost;
return ret;
}
static vgcanvas_t* lcd_profile_get_vgcanvas(lcd_t* lcd) {
lcd_profile_t* profile = LCD_PROFILE(lcd);
return lcd_get_vgcanvas(profile->impl);
}
static ret_t lcd_profile_take_snapshot(lcd_t* lcd, bitmap_t* img, bool_t auto_rotate) {
ret_t ret = RET_OK;
uint32_t cost = 0;
uint32_t start = time_now_ms();
lcd_profile_t* profile = LCD_PROFILE(lcd);
ret = lcd_take_snapshot(profile->impl, img, auto_rotate);
cost = time_now_ms() - start;
return ret;
}
static bitmap_format_t lcd_profile_get_desired_bitmap_format(lcd_t* lcd) {
lcd_profile_t* profile = LCD_PROFILE(lcd);
return lcd_get_desired_bitmap_format(profile->impl);
}
static ret_t lcd_profile_swap(lcd_t* lcd) {
ret_t ret = RET_OK;
uint32_t cost = 0;
uint32_t start = time_now_ms();
lcd_profile_t* profile = LCD_PROFILE(lcd);
ret = lcd_swap(profile->impl);
cost = time_now_ms() - start;
profile->swap_cost = cost;
return ret;
}
static ret_t lcd_profile_flush(lcd_t* lcd) {
ret_t ret = RET_OK;
uint32_t cost = 0;
uint32_t start = time_now_ms();
lcd_profile_t* profile = LCD_PROFILE(lcd);
ret = lcd_flush(profile->impl);
cost = time_now_ms() - start;
profile->flush_cost = cost;
return ret;
}
static ret_t lcd_profile_end_frame(lcd_t* lcd) {
ret_t ret = RET_OK;
uint32_t cost = 0;
uint32_t end = 0;
uint32_t start = time_now_ms();
lcd_profile_t* profile = LCD_PROFILE(lcd);
ret = lcd_end_frame(profile->impl);
end = time_now_ms();
cost = end - start;
profile->total_cost = time_now_ms() - profile->begin_frame_time;
if (profile->total_cost > 25) {
log_debug("#####################################\n");
log_debug("%s:%d\n", __FILE__, __LINE__);
log_debug("-------------------------------------\n");
log_debug(" total_cost=%u \n", profile->total_cost);
log_debug(" draw_image_cost=%u times=%u\n", profile->draw_image_cost,
profile->draw_image_times);
log_debug(" draw_text_cost=%u times=%u\n", profile->draw_text_cost, profile->draw_text_times);
log_debug(" fill_cost=%u times=%u\n", profile->fill_cost, profile->fill_times);
log_debug(" stroke_cost=%u times=%u\n", profile->stroke_cost, profile->stroke_times);
if (cost) {
log_debug(" end_frame_cost=%u\n", cost);
}
if (profile->flush_cost) {
log_debug(" flush_cost=%u\n", profile->flush_cost);
}
if (profile->swap_cost) {
log_debug(" swap_cost=%u\n", profile->swap_cost);
}
log_debug("-------------------------------------\n");
}
return ret;
}
lcd_t* lcd_profile_create(lcd_t* impl) {
lcd_t* lcd = NULL;
return_value_if_fail(impl != NULL, NULL);
lcd = (lcd_t*)TKMEM_ZALLOC(lcd_profile_t);
return_value_if_fail(lcd != NULL, NULL);
lcd->w = impl->w;
lcd->h = impl->h;
lcd->type = impl->type;
lcd->ratio = impl->ratio;
LCD_PROFILE(lcd)->impl = impl;
lcd->support_dirty_rect = impl->support_dirty_rect;
lcd->begin_frame = lcd_profile_begin_frame;
lcd->set_global_alpha = lcd_profile_set_global_alpha;
lcd->set_text_color = lcd_profile_set_text_color;
lcd->set_stroke_color = lcd_profile_set_stroke_color;
lcd->set_fill_color = lcd_profile_set_fill_color;
if (impl->set_font_name != NULL) {
lcd->set_font_name = lcd_profile_set_font_name;
lcd->set_font_size = lcd_profile_set_font_size;
}
if (impl->set_clip_rect != NULL) {
lcd->set_clip_rect = lcd_profile_set_clip_rect;
}
if (impl->get_clip_rect != NULL) {
lcd->get_clip_rect = lcd_profile_get_clip_rect;
}
if (impl->resize != NULL) {
lcd->resize = lcd_profile_resize;
}
if (impl->draw_vline != NULL) {
lcd->draw_vline = lcd_profile_draw_vline;
}
if (impl->draw_hline != NULL) {
lcd->draw_hline = lcd_profile_draw_hline;
}
if (impl->draw_points != NULL) {
lcd->draw_points = lcd_profile_draw_points;
}
if (impl->get_point_color != NULL) {
lcd->get_point_color = lcd_profile_get_point_color;
}
if (impl->fill_rect != NULL) {
lcd->fill_rect = lcd_profile_fill_rect;
}
if (impl->stroke_rect != NULL) {
lcd->stroke_rect = lcd_profile_stroke_rect;
}
if (impl->draw_glyph != NULL) {
lcd->draw_glyph = lcd_profile_draw_glyph;
}
if (impl->measure_text != NULL) {
lcd->measure_text = lcd_profile_measure_text;
}
if (impl->draw_text != NULL) {
lcd->draw_text = lcd_profile_draw_text;
}
if (impl->draw_image != NULL) {
lcd->draw_image = lcd_profile_draw_image;
}
if (impl->draw_image_matrix != NULL) {
lcd->draw_image_matrix = lcd_profile_draw_image_matrix;
}
if (impl->get_vgcanvas != NULL) {
lcd->get_vgcanvas = lcd_profile_get_vgcanvas;
}
if (impl->take_snapshot != NULL) {
lcd->take_snapshot = lcd_profile_take_snapshot;
}
if (impl->get_desired_bitmap_format != NULL) {
lcd->get_desired_bitmap_format = lcd_profile_get_desired_bitmap_format;
}
if (impl->swap != NULL) {
lcd->swap = lcd_profile_swap;
}
if (impl->flush != NULL) {
lcd->flush = lcd_profile_flush;
}
if (impl->end_frame != NULL) {
lcd->end_frame = lcd_profile_end_frame;
}
return lcd;
}
#else
lcd_t* lcd_profile_create(lcd_t* impl) {
return impl;
}
#endif /*ENABLE_PERFORMANCE_PROFILE*/

70
src/base/lcd_profile.h Normal file
View File

@ -0,0 +1,70 @@
/**
* File: lcd_profile.h
* Author: AWTK Develop Team
* Brief: wrap lcd for performance profile.
*
* Copyright (c) 2018 - 2019 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2018-03-21 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef LCD_PROFILE_H
#define LCD_PROFILE_H
#include "base/lcd.h"
BEGIN_C_DECLS
/**
* @class lcd_profile_t
* @parent lcd_t
* LCD对象进行包装
*
*/
typedef struct _lcd_profile_t {
lcd_t lcd;
/*private*/
lcd_t* impl;
uint32_t begin_frame_time;
uint32_t total_cost;
uint32_t swap_cost;
uint32_t flush_cost;
uint32_t draw_image_cost;
uint32_t draw_image_times;
uint32_t draw_image_pixels;
uint32_t draw_text_cost;
uint32_t draw_text_times;
uint32_t draw_text_chars;
uint32_t fill_cost;
uint32_t fill_times;
uint32_t fill_pixels;
uint32_t stroke_cost;
uint32_t stroke_times;
uint32_t stroke_pixels;
} lcd_profile_t;
lcd_t* lcd_profile_create(lcd_t* impl);
#define LCD_PROFILE(lcd) ((lcd_profile_t*)(lcd))
END_C_DECLS
#endif /*LCD_PROFILE_H*/

View File

@ -824,7 +824,7 @@ ret_t widget_paint_helper(widget_t* widget, canvas_t* c, const char* icon, wstr_
static ret_t widget_paint_impl(widget_t* widget, canvas_t* c) {
int32_t ox = widget->x;
int32_t oy = widget->y;
uint8_t save_alpha = c->lcd->global_alpha;
uint8_t save_alpha = c->global_alpha;
if (widget->opacity < TK_OPACITY_ALPHA) {
canvas_set_global_alpha(c, (widget->opacity * save_alpha) / 0xff);

File diff suppressed because it is too large Load Diff