1# QoS 开发指导
2
3## 场景介绍
4
5自多道程序及多任务操作系统问世以来,CPU、内存等有限的系统资源成为系统中所有任务的竞争对象。合理安排各个任务对系统的响应速度以及资源消耗都有非常重大的意义。相比操作系统,开发者更加清楚应用中各个任务的重要程度;根据重要程度对应用的任务进行分类,能帮助系统更好地进行任务的调度。通过本指导,开发者可以了解在OpenHarmony系统中,如何利用QoS特性及相关的接口调节任务在系统中的运行时间分配。
6
7本文用于指导开发者基于QoS特性实现应用任务优先调度属性自定义。
8
9## 基本概念
10
11### QoS
12
13QoS(quality-of-service),即服务质量,在OpenHarmony中QoS特性主要指任务的优先调度属性。开发者可以利用QoS对要执行的工作进行分类,以指示其与用户交互的关联程度;系统则可以根据任务设置的QoS安排各任务的运行时间和运行次序。例如,当系统中有多个任务需要同时执行时,一些与用户交互关联程度不高的后台下载任务可以推迟到更晚的时间执行,且每次执行时分配更少的时间;而用户感知明显的动效绘制等任务则需要立即执行,并分配更多的执行时间。
14
15### QoS等级定义
16目前,OpenHarmony系统一共划分如下了6个QoS等级,从上到下与用户交互的关联程度依次递增,适用于多种不同的应用场景及负载特征情况。
17
18| QoS等级                                                       | 使用场景                                                         | 负载特征                                                         |
19| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
20| QOS_BACKGROUND | 后台且用户不可见任务,例如数据同步、备份。 | 任务完成需要几分钟甚至几小时。 |
21| QOS_UTILITY | 不需要立即看到响应效果的任务,例如下载或导入数据。 | 任务完成需要几秒到几分钟 |
22| QOS_DEFAULT | 默认。 | 任务完成需要几秒钟。 |
23| QOS_USER_INITIATED | 用户触发并且可见进展的任务,例如打开文档。 | 任务在几秒钟之内完成。 |
24| QOS_DEADLINE_REQUEST | 越快越好的关键任务,如页面加载。 | 任务几乎是瞬间完成的。 |
25| QOS_USER_INTERACTIVE	 | 用户交互任务(UI线程、刷新界面、动效)。 | 任务是即时的。 |
26
27QoS等级定义为枚举类型QoS_level,如上表所示;枚举值定义如下。
28### QoS_Level声明
29```{.c}
30typedef enum QoS_Level {
31    /**
32     * 适用于数据同步等用户不可见的后台任务。
33     */
34    QOS_BACKGROUND,
35    /**
36     * 适用于下载等不需要立即看到响应效果的任务。
37     */
38    QOS_UTILITY,
39    /**
40     * 默认的QoS等级。
41     */
42    QOS_DEFAULT,
43    /**
44     * 适用于打开文档等用户触发并且可以看到进展的任务。
45     */
46    QOS_USER_INITIATED,
47    /**
48     * 适用于页面加载等越快越好的任务。
49     */
50    QOS_DEADLINE_REQUEST,
51    /**
52     * 适用于动效绘制等用户交互任务。
53     */
54    QOS_USER_INTERACTIVE,
55} QoS_Level;
56
57```
58
59## 功能效果
60QoS等级更高的任务相对等级更低的可能被分配更多的CPU时间。
61
62下面将展示合理使用QoS对程序执行的优化效果。
63
64### QoS对线程执行的优化
65
66#### 优化前
67![qosfigure1.png](./figures/qosfigure1.png)
68线程1和线程2是某程序的两个关键线程,线程1在运行时会触发新任务线程2,等线程2执行完后会唤醒线程1继续执行。在未标记这两个线程的QoS等级之前,其优先执行顺序低于线程3和线程4;此时线程1和线程2的执行效果如上图所示:
69
701. 线程1等待被线程2唤醒,而线程2优先级低,长时间被抢占,导致线程1长时间睡眠;
71
722. 线程1优先级低,它被唤醒后等待运行时间长;
73
743. 线程1优先级低,运行过程中长时间被其它线程抢占。
75
76#### 优化后
77![qosfigure2.png](./figures/qosfigure2.png)
78
79合理标记线程1和线程2的QoS等级后,两个线程的执行优化效果如上图所示:
80
811. 线程2运行时间占比提高,线程1等待时间减少;
82
832. 线程1被线程2唤醒后,等待的时间减少;
84
853. 线程1运行实际占比提高,被抢占比例减少。
86
87### QoS对RN框架的优化
88在RN框架中合理标记关键线程的QoS等级后,如下表所示,开源benchmark测试的性能提升了约13%。
89
90| 验证场景      | 验证环境 | 总渲染时间 |
91| ----------- | ----------- | ----------- |
92| benchmark<br>1500view      | 无QoS优化       | 270.8 ms       |
93| benchmark<br>1500view   | 使用QoS优化        | 236.6 ms       |
94
95## 接口说明
96
97| 接口名                                                       | 描述                                                         | 参数                                                         | 返回值                                                         |
98| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
99| OH_QoS_SetThreadQoS(QoS_Level level) | 设置当前任务的QoS等级。 | QoS_Level level | 0或-1 |
100| OH_QoS_ResetThreadQoS() | 取消当前任务设置的QoS等级。 | 无 | 0或-1 |
101| OH_QoS_GetThreadQoS(QoS_Level *level) | 获取当前任务的QoS等级。 | QoS_Level *level | 0或-1 |
102
103### 使用限制
104* QoS接口只能设置本任务的QoS等级。
105
106## 函数介绍
107
108### OH_QoS_SetThreadQoS
109
110#### 声明
111```{.c}
112int OH_QoS_SetThreadQoS(QoS_Level level);
113```
114
115#### 参数
116QoS_Level level
117* 该参数用于描述要为任务设置的QoS等级。
118
119#### 返回值
120* 若成功则返回0,失败则返回-1。
121
122#### 描述
123为某个任务设置指定的QoS等级。
124
125#### 样例
126```
127#include <stdio.h>
128#include "qos/qos.h"
129
130int main()
131{
132    // 设置当前任务的QoS等级为QOS_USER_INITIATED
133    int ret = OH_QoS_SetThreadQoS(QoS_Level::QOS_USER_INITIATED);
134
135    if (!ret) { // ret等于0说明设置成功
136        printf("set QoS Success.");
137    } else { // ret不等于0说明设置失败
138        printf("set QoS failed.");
139    }
140
141    return 0;
142}
143```
144
145### OH_QoS_ResetThreadQoS
146
147#### 声明
148```{.c}
149int OH_QoS_ResetThreadQoS();
150```
151
152#### 参数
153* 无。
154
155#### 返回值
156* 若成功则返回0,失败则返回-1。
157
158#### 描述
159取消某个任务设置的QoS等级。
160
161#### 样例
162```
163#include <stdio.h>
164#include "qos/qos.h"
165
166int main()
167{
168    // 重置当前任务的QoS等级
169    int ret = OH_QoS_ResetThreadQoS();
170
171    if (!ret) { // ret等于0说明重置成功
172        printf("reset QoS Success.");
173    } else { // ret不等于0说明重置失败
174        printf("reset QoS failed.");
175    }
176
177    return 0;
178}
179```
180
181### OH_QoS_GetThreadQoS
182
183#### 声明
184```{.c}
185int OH_QoS_GetThreadQoS(QoS_Level *level);
186```
187
188#### 参数
189QoS_Level *level
190* 该参数用于存储任务已经设置的QoS等级。
191
192#### 返回值
193* 若成功则返回0,失败则返回-1。
194
195#### 描述
196获取某个任务之前最近一次设置的QoS等级;如果之前未设置任何QoS等级,则返回-1。
197
198#### 样例
199```
200#include <stdio.h>
201#include "qos/qos.h"
202
203int main()
204{
205    // 获取当前任务的QoS等级
206    QoS_Level level = QoS_Level::QOS_DEFAULT;
207    int ret = OH_QoS_GetThreadQoS(&level);
208
209    if (!ret) { // ret等于0说明获取成功
210        printf("get QoS level %d Success.", level);
211    } else { // ret不等于0说明获取失败
212        printf("get QoS level failed.");
213    }
214
215    return 0;
216}
217```
218
219## 开发步骤
220以下步骤描述了如何使用QoS特性提供的Native API接口,调整或查询任务的QoS等级。
221
222**添加动态链接库**
223
224CMakeLists.txt中添加以下lib:
225```txt
226libqos.so
227```
228
229#### 示例
230```txt
231# the minimum version of CMake.
232cmake_minimum_required(VERSION 3.4.1)
233project(qos)
234
235set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
236
237include_directories(${NATIVERENDER_ROOT_PATH}
238                    ${NATIVERENDER_ROOT_PATH}/include)
239
240add_library(entry SHARED hello.cpp)
241target_link_libraries(entry PUBLIC libqos.so)
242```
243
244**头文件**
245```c
246#include "qos/qos.h"
247```
248**调用QoS接口**
249
250开发者根据自身需求调用相应的QoS接口调整任务的QoS等级,或者查询任务的QoS等级。
251
252