LCUI 1.1.0 Beta 开发日志

发表于2018年12月22日

2018-02-16

准备添加性能统计功能,统计近一秒内每一帧的运行情况,方便确定哪里需要优化。比较纠结的是如何获取这些数据,有以下几种解决方案:

统计相关代码只在 main.c 中有定义 DEBUG 宏时才启用,应用程序如果要启用这个功能还得手动改 LCUI 源码并重新编译,挺麻烦的,可以加个 config 模块,方便在运行时改变 LCUI 相关功能配置。

配置是全局共用的,按常规套路应该将代码放到 config.c 和 config.h 里,可问题是 configure.ac 生成的配置文件也是 config.h,如何解决这个冲突?

靠应用程序代码来修改配置还不够灵活,要改配置就要改代码,改了代码后要重新编译,应考虑支持从外部加载配置,例如:命令行参数,传入 --enable-profile 参数时启用性能分析功能。其它 GUI 库在初始化时要求传入 argc 和 argv 估计也是为了加载配置,LCUI 以前也是这样,后来因为没有具体用处就砍掉了,现在加回来又有些不妥,那就只能加新的接口了。

渲染部件时会计算每个部件的实际样式,当部件数量达到四万个时,总耗时比预想的要高很多。如下图所示,大部分 CPU 资源都用在计算实际样式上。

vs2017 CPU 使用率报告

看了下相关代码,可以做些优化,例如:

2018-02-12

使用 Widget_CopyHash() 前需要准备模板部件,在列表清空后还要重置部件指针为 NULL,而且递归遍历复制 hash 值的效率也不高。可以加个 Widget_GetHashList(),将部件及子集部件的 hash 都写到数组里,然后加个 Widget_SetHashList() 用来将 hash 数组应用到自身及子部件里,这样改了后,限制条件少了,使用起来也方便一些。

给部件设置最大子部件渲染数量后,排列在后面的子部件会有闪烁,即便它是绝对定位的且在可见区域内也会被忽略掉。

2019-02-11

克隆部件是只克隆自己还是包括子集所有部件?有的类型的部件在初始化时会追加一些子部件,要是把子集部件也克隆一遍的话会重复的。

克隆功能就不加了,只是为了复制 hash 值的话那可以加个 Widget_CopyHash(),指定目标部件然后遍历子部件逐个复制 hash。

2019-02-10

添加了个 only_on_visible 规则,只在该部件处于可见区域时才更新它的子部件,节省 CPU 资源给其它部件。

一个列表四万多张图片,越滚到后面,部件更新会越慢,因为后面的部件都在等前面的部件更新完。需要加一个“优先更新可见区域内的部件”的规则,在启用该规则后,遍历列表,找到第一个在可见区域的部件,然后开始更新它和它后面的部件,直到部件不可见为止。部件的查找方法可以优化,比如用二分法查找,但感觉搞起来有些麻烦,所以先不做调整。

改成一帧更新一次部件后,界面更新有点延迟,还是再加几次吧。

清除缩略图缓存时应该显示个操作中的提示,在缓存大小到了 600MB 以上后,操作耗时明显变长,一直卡住界面会影响用户体验。

又多了个 bug,滚动条的长度计算不正确。

2019-02-09

虽然样式表有缓存,但计算索引 key 很耗时,而且大部分是重复计算。

补充需求:

每次更新都要重新布局,部件多了后很耗时间,LCUI_ProcessEvents() 每处理一个任务都会调用 LCUIDisplay_Update() 更新部件,为降低耗时,决定移除 LCUI_ProcessEvents() 中的 LCUIDisplay_Update() 调用,一帧只调用一次 LCUIDisplay_Update()。

测试时发现渲染耗时也很长,可是渲染时除了填充像素点比较耗时外,剩下的就是遍历部件列表和判断部件区域与重绘区域是否重叠,难道这简单的判断做几万次也需要几百毫秒的时间?找原因挺麻烦的,先加个规则,限制子部件渲染数量,对于图片列表来说,整个屏幕也就够显示几十张图片,剩下的就没必要判断了。

2010-02-08

style 样式表还有其它用处,在部件更新时用来对比新旧样式,布局时也要读取子部件的 style 样式表,看样子只能先改 custom_style 和 inherited_style 表了。

2010-02-07

每个部件都有 style、custom_style 和 inherited_style 三张样式表,太占空间,需要优化:

2019-02-05

每次调用 Widget_Append() 追加部件时都会更新部件的 last-child 和 first-child 状态,在部件样式类和状态变更后都会调用 Widget_HandleChildrenStyleChange() 检查是否需要更新子级部件,这个检查比较耗时,部件数量多的时候就会很慢。

有以下几个优化方案可以考虑:

2019-02-04

用 VS2017 的性能探查器检测 LC-Finder 的内存占用,生成的报告大小有 3GB,这要是用以前的机器来搞的话读取报告都得等很久。

vs2017 内存使用率报告

vs2017 内存使用率快照#2

从快照中可以看出样式表占用内存最多,约有 244MB,字符串占用空间 101MB,比部件还多。

以下是可优化的地方:

2019-01-30

有点纠结该怎么触发 mouseout 和 mouseover 事件,如果给目标部件和它父级所有部件单独触发事件的话,父级部件就无法捕捉到子部件的事件;如果只给目标部件触发事件然后冒泡的话,父部件又不方便判断是不是自己的事件,因为在子部件之间移动鼠标时也会触发 mouseover 和 mouseout 事件,尤其是 mouseout 事件,无法判断是不是因鼠标光标移出父部件而触发的。

mouseout 事件触发条件可以改成单独触发,只要是移出部件,就给这个部件触发 mouseout 事件并默认冒泡,这样就能根据 target 来判断事件是不是自身触发的。

2018-12-23

在给 LCFinder 的标签编辑器输入文字时按了方向键,结果被图片查看器捕获到并切换图片,导致正编辑的输入框被销毁。当输入框获得焦点时,应该阻止事件冒泡,如果绑定的全局按键事件,则需要有个函数用于判断是否有激活输入焦点。

2018-12-22

绑定和触发事件比较麻烦,例如绑定 change 事件,需要先找与 change 关联的事件 id,没有就会绑定失败。需要调整一下,以字符串作为事件名时,如果没有与之关联的事件 id,则创建一个事件 id 并关联它。

对此文章有疑问?你可以点击此链接反馈你的问题