1 /*
2 * Copyright (c) 2009-2022 Huawei Technologies Co., Ltd. All rights reserved.
3 *
4 * UniProton is licensed under Mulan PSL v2.
5 * You can use this software according to the terms and conditions of the Mulan PSL v2.
6 * You may obtain a copy of Mulan PSL v2 at:
7 * http://license.coscl.org.cn/MulanPSL2
8 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
9 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
10 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
11 * See the Mulan PSL v2 for more details.
12 * Create: 2009-12-22
13 * Description: 线程级CPU占用率模块的C文件
14 */
15 #include "prt_cpup_thread_internal.h"
16
17 /*
18 * 描述:任务切入,中断结束时,统计任务的startTime
19 */
OsNowTskCycleStart(void)20 OS_SEC_L2_TEXT void OsNowTskCycleStart(void)
21 {
22 uintptr_t intSave;
23
24 intSave = OsIntLock();
25
26 /* 处理硬中断、Tick退出钩子时判断是否需要统计CPUP */
27 if (CPUP_FLAG == OS_CPUP_EXIT_FLAG) {
28 OS_TASK_CYCLE_START(RUNNING_TASK->taskPid, OsCurCycleGet64());
29 }
30 CPUP_FLAG--;
31
32 OsIntRestore(intSave);
33 }
34
35 /*
36 * 描述:任务切出,中断开始时,统计任务的allTime
37 */
OsNowTskCycleEnd(void)38 OS_SEC_L2_TEXT void OsNowTskCycleEnd(void)
39 {
40 uintptr_t intSave;
41
42 intSave = OsIntLock();
43
44 /* 处理硬中断、Tick进入钩子时判断是否需要统计CPUP */
45 if (CPUP_FLAG == OS_CPUP_ENTRY_FLAG) {
46 OS_TASK_CYCLE_END(RUNNING_TASK->taskPid, OsCurCycleGet64());
47 }
48 CPUP_FLAG++;
49
50 OsIntRestore(intSave);
51 }
52
53 /*
54 * 描述:第一次任务切换时候CPUP设初始值
55 */
OsCpupFirstSwitch(void)56 OS_SEC_L2_TEXT void OsCpupFirstSwitch(void)
57 {
58 g_cpuWinStart = OsCurCycleGet64();
59 OS_TASK_CYCLE_START(g_highestTask->taskPid, g_cpuWinStart);
60 }
61
62 /*
63 * 描述:任务结束和开始,对任务的CPUP计时
64 * 备注:lastTaskId 结束的任务ID;nextTaskId 开始的任务ID;curCycle 结束和开始的Cycle
65 */
OsCpupStartEnd(U32 lastTaskId,U32 nextTaskId,U64 curCycle)66 OS_SEC_L2_TEXT void OsCpupStartEnd(U32 lastTaskId, U32 nextTaskId, U64 curCycle)
67 {
68 /* 切出任务 */
69 OS_TASK_CYCLE_END(lastTaskId, curCycle);
70
71 /* 切入任务 */
72 OS_TASK_CYCLE_START(nextTaskId, curCycle);
73 }
74
75 /*
76 * 描述:任务切换时候CPUP设初始值
77 */
OsCpupTskSwitch(U32 lastTaskId,U32 nextTaskId)78 OS_SEC_L2_TEXT void OsCpupTskSwitch(U32 lastTaskId, U32 nextTaskId)
79 {
80 uintptr_t intSave;
81
82 intSave = OsIntLock();
83 /* CPUP统计 */
84 OsCpupStartEnd(lastTaskId, nextTaskId, OsCurCycleGet64());
85
86 OsIntRestore(intSave);
87 }
88 /*
89 * 描述:获取输入线程个数的cpup
90 */
OsCpupTask(U32 intNum,struct CpupThread * cpup)91 OS_SEC_L2_TEXT U32 OsCpupTask(U32 intNum, struct CpupThread *cpup)
92 {
93 U32 index;
94 U32 maxNum = 0;
95 cpup[maxNum].id = OS_CPUP_INT_ID;
96 cpup[maxNum].usage = OsCpupIntGet();
97 maxNum++;
98
99 for (index = 0; index < (OS_MAX_TCB_NUM - 1); index++) {
100 if (intNum == maxNum) {
101 break;
102 }
103
104 /* 判断该任务是否被创建 */
105 if (g_tskCbArray[index].taskStatus == OS_TSK_UNUSED) {
106 continue;
107 }
108
109 cpup[maxNum].id = g_tskCbArray[index].taskPid;
110 cpup[maxNum].usage = g_cpup[index].usage;
111
112 maxNum++;
113 }
114 return maxNum;
115 }
116
OsCpupParaCheck(U32 intNum,struct CpupThread * cpup,const U32 * outNum)117 OS_SEC_ALW_INLINE INLINE U32 OsCpupParaCheck(U32 intNum, struct CpupThread *cpup, const U32 *outNum)
118 {
119 if (cpup == NULL || outNum == NULL) {
120 return OS_ERRNO_CPUP_PTR_NULL;
121 }
122
123 if (intNum == 0) {
124 return OS_ERRNO_CPUP_THREAD_INNUM_INVALID;
125 }
126
127 return OS_OK;
128 }
129
130 /*
131 * 描述:获取所有任务线程的运行时间
132 */
OsCpupAllTaskTimeGet(void)133 OS_SEC_L2_TEXT U64 OsCpupAllTaskTimeGet(void)
134 {
135 U32 index;
136 U64 allTime = 0;
137
138 for (index = 0; index < (OS_MAX_TCB_NUM - 1); index++) {
139 allTime += g_cpup[index].allTime;
140 }
141
142 return (allTime + g_cpuTimeDelTask);
143 }
144
145 /*
146 * 描述:清空所有任务运行时间和CPU占用率大小
147 */
OsCpupTimeClear(void)148 OS_SEC_L2_TEXT void OsCpupTimeClear(void)
149 {
150 U32 index;
151
152 for (index = 0; index < (OS_MAX_TCB_NUM - 1); index++) {
153 g_cpup[index].allTime = 0;
154 }
155
156 g_cpuTimeDelTask = 0;
157 }
158 /*
159 * 描述:清空所有任务运行时间和CPU占用率大小
160 */
OsCpupTickCal(void)161 OS_SEC_L2_TEXT void OsCpupTickCal(void)
162 {
163 U32 index;
164
165 for (index = 0; index < (OS_MAX_TCB_NUM - 1); index++) {
166 g_cpup[index].usage = (U16)DIV64(g_cpup[index].allTime * CPUP_USE_RATE, g_baseValue);
167 if (g_cpup[index].usage > CPUP_USE_RATE) {
168 g_cpup[index].usage = CPUP_USE_RATE;
169 }
170 }
171
172 OsMcCpupSet(OsGetHwThreadId(), (U32)(CPUP_USE_RATE - g_cpup[TSK_GET_INDEX(IDLE_TASK_ID)].usage));
173
174 g_cpupDelTask = (U16)DIV64(g_cpuTimeDelTask * CPUP_USE_RATE, g_baseValue);
175 }
176
177 /*
178 * 描述:获取中断线程的占用率接口
179 */
OsCpupIntGet(void)180 OS_SEC_L2_TEXT U16 OsCpupIntGet(void)
181 {
182 U32 index;
183 U16 usage = 0;
184
185 for (index = 0; index < (OS_MAX_TCB_NUM - 1); index++) {
186 usage += g_cpup[index].usage;
187 }
188
189 usage += g_cpupDelTask;
190
191 if (usage >= CPUP_USE_RATE) {
192 usage = CPUP_USE_RATE;
193 }
194
195 return (U16)(CPUP_USE_RATE - usage);
196 }
197
198 /*
199 * 描述:获取当前线程级cpu占用率接口
200 */
OsCpupThreadNow(void)201 OS_SEC_L2_TEXT U32 OsCpupThreadNow(void)
202 {
203 U64 cpuCycleAll;
204 uintptr_t intSave;
205 U32 cpup = 0;
206 U64 curCycle;
207
208 if ((UNI_FLAG & OS_FLG_BGD_ACTIVE) == 0) {
209 OS_REPORT_ERROR(OS_ERRNO_CPUP_OS_NOT_STARTED);
210 return (U32)OS_INVALID;
211 }
212
213 intSave = OsIntLock();
214
215 if (g_ticksPerSample != 0) {
216 cpup = (U32)(CPUP_USE_RATE - g_cpup[TSK_GET_INDEX(IDLE_TASK_ID)].usage);
217
218 OsIntRestore(intSave);
219 return cpup;
220 }
221
222 /* 统计当前系统运行总时间 */
223 curCycle = OsCurCycleGet64();
224
225 if (OS_INT_INACTIVE) {
226 OsCpupStartEnd(RUNNING_TASK->taskPid, RUNNING_TASK->taskPid, curCycle);
227 }
228
229 cpuCycleAll = OsCpupGetWinCycles(curCycle);
230 g_cpuWinStart = curCycle;
231
232 cpup = (U32)(CPUP_USE_RATE - DIV64(CPUP_USE_RATE * g_cpup[TSK_GET_INDEX(IDLE_TASK_ID)].allTime, cpuCycleAll));
233 OsMcCpupSet(OsGetHwThreadId(), cpup);
234
235 OsCpupTimeClear();
236
237 OsIntRestore(intSave);
238
239 return cpup;
240 }
241
242 /*
243 * 描述:获取所有线程的占用率接口
244 */
PRT_CpupThread(U32 inNum,struct CpupThread * cpup,U32 * outNum)245 OS_SEC_L2_TEXT U32 PRT_CpupThread(U32 inNum, struct CpupThread *cpup, U32 *outNum)
246 {
247 U32 index;
248 U32 ret;
249 uintptr_t intSave;
250 U32 maxNum = 1; // 默认中断占用一个
251
252 U64 cpuCycleAll;
253 U64 allTime;
254 U64 curCycle;
255
256 ret = OsCpupPreCheck();
257 if (ret != OS_OK) {
258 return ret;
259 }
260
261 ret = OsCpupParaCheck(inNum, cpup, outNum);
262 if (ret != OS_OK) {
263 return ret;
264 }
265
266 /* 获取当前采样周期内,所有线程运行的总时间 */
267 intSave = OsIntLock();
268
269 if (g_ticksPerSample != 0) {
270 maxNum = OsCpupTask(inNum, cpup);
271 OsIntRestore(intSave);
272 *outNum = maxNum;
273
274 return OS_OK;
275 }
276
277 curCycle = OsCurCycleGet64();
278
279 if (OS_INT_INACTIVE) {
280 OsCpupStartEnd(RUNNING_TASK->taskPid, RUNNING_TASK->taskPid, curCycle);
281 }
282 /* 统计当前系统运行总时间 */
283 cpuCycleAll = OsCpupGetWinCycles(curCycle);
284 g_cpuWinStart = curCycle;
285
286 /*
287 * 配置g_cpup[].iD线程ID
288 */
289 cpup[0].id = OS_CPUP_INT_ID;
290 cpup[0].usage = (U16)DIV64(CPUP_USE_RATE * (cpuCycleAll - OsCpupAllTaskTimeGet()), cpuCycleAll);
291
292 for (index = 0; index < (OS_MAX_TCB_NUM - 1) && maxNum < inNum; index++) {
293 /* 判断该任务是否被创建 */
294 if (g_tskCbArray[index].taskStatus == OS_TSK_UNUSED) {
295 continue;
296 }
297
298 allTime = g_cpup[index].allTime;
299
300 cpup[maxNum].id = g_tskCbArray[index].taskPid;
301 cpup[maxNum].usage = (U16)DIV64(CPUP_USE_RATE * allTime, cpuCycleAll);
302
303 maxNum++;
304 }
305
306 OsMcCpupSet(OsGetHwThreadId(),
307 (U32)DIV64(CPUP_USE_RATE * (cpuCycleAll - g_cpup[TSK_GET_INDEX(IDLE_TASK_ID)].allTime), cpuCycleAll));
308
309 OsCpupTimeClear();
310
311 OsIntRestore(intSave);
312 *outNum = maxNum;
313
314 return OS_OK;
315 }
316