1 /*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 * conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 * of conditions and the following disclaimer in the documentation and/or other materials
13 * provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16 * to endorse or promote products derived from this software without specific prior written
17 * permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include "los_cpup.h"
33 #include "securec.h"
34 #include "los_memory.h"
35 #include "los_debug.h"
36 #include "los_tick.h"
37
38 #if (LOSCFG_BASE_CORE_CPUP == 1)
39
40 /**
41 * @ingroup los_cpup
42 * CPU usage-type macro: used for tasks.
43 */
44 #define OS_THREAD_TYPE_TASK 0
45
46 /**
47 * @ingroup los_cpup
48 * CPU usage-type macro: used for hardware interrupts.
49 */
50 #define OS_THREAD_TYPE_HWI 1
51
52 #define OS_CPUP_RECORD_PERIOD (g_sysClock)
53
54 LITE_OS_SEC_BSS UINT16 g_cpupInitFlg = 0;
55 LITE_OS_SEC_BSS OsCpupCB *g_cpup = NULL;
56 LITE_OS_SEC_BSS UINT64 g_lastRecordTime;
57 LITE_OS_SEC_BSS UINT16 g_hisPos; /* <current Sampling point of historyTime */
58
59 /*****************************************************************************
60 Function : OsCpupInit
61 Description: initialization of CPUP
62 Input : None
63 Return : LOS_OK or Error Information
64 *****************************************************************************/
OsCpupInit()65 LITE_OS_SEC_TEXT_INIT UINT32 OsCpupInit()
66 {
67 UINT32 size;
68
69 size = g_taskMaxNum * sizeof(OsCpupCB);
70 g_cpup = (OsCpupCB *)LOS_MemAlloc(m_aucSysMem0, size);
71
72 if (g_cpup == NULL) {
73 return LOS_ERRNO_CPUP_NO_MEMORY;
74 }
75
76 // Ignore the return code when matching CSEC rule 6.6(3).
77 (VOID)memset_s(g_cpup, size, 0, size);
78 g_cpupInitFlg = 1;
79
80 return LOS_OK;
81 }
82
83 /*****************************************************************************
84 Function : OsTskCycleStart
85 Description: start task to get cycles count in current task beginning
86 Input : None
87 Return : None
88 *****************************************************************************/
OsTskCycleStart(VOID)89 LITE_OS_SEC_TEXT_MINOR VOID OsTskCycleStart(VOID)
90 {
91 UINT32 taskID;
92
93 if (g_cpupInitFlg == 0) {
94 return;
95 }
96
97 taskID = g_losTask.newTask->taskID;
98 g_cpup[taskID].cpupID = taskID;
99 g_cpup[taskID].startTime = LOS_SysCycleGet();
100
101 return;
102 }
103 /*****************************************************************************
104 Function : OsTskCycleEnd
105 Description: quit task and get cycle count
106 Input : None
107 Return : None
108 *****************************************************************************/
OsTskCycleEnd(VOID)109 LITE_OS_SEC_TEXT_MINOR VOID OsTskCycleEnd(VOID)
110 {
111 UINT32 taskID;
112 UINT64 cpuCycle;
113
114 if (g_cpupInitFlg == 0) {
115 return;
116 }
117
118 taskID = g_losTask.runTask->taskID;
119
120 if (g_cpup[taskID].startTime == 0) {
121 return;
122 }
123
124 cpuCycle = LOS_SysCycleGet();
125
126 if (cpuCycle < g_cpup[taskID].startTime) {
127 cpuCycle += g_cyclesPerTick;
128 }
129
130 g_cpup[taskID].allTime += (cpuCycle - g_cpup[taskID].startTime);
131 g_cpup[taskID].startTime = 0;
132
133 return;
134 }
135 /*****************************************************************************
136 Function : OsTskCycleEndStart
137 Description: start task to get cycles count in current task ending
138 Input : None
139 Return : None
140 *****************************************************************************/
OsTskCycleEndStart(VOID)141 LITE_OS_SEC_TEXT_MINOR VOID OsTskCycleEndStart(VOID)
142 {
143 UINT32 taskID;
144 UINT64 cpuCycle;
145 UINT16 loopNum;
146
147 if (g_cpupInitFlg == 0) {
148 return;
149 }
150
151 taskID = g_losTask.runTask->taskID;
152 cpuCycle = LOS_SysCycleGet();
153
154 if (g_cpup[taskID].startTime != 0) {
155 if (cpuCycle < g_cpup[taskID].startTime) {
156 cpuCycle += g_cyclesPerTick;
157 }
158
159 g_cpup[taskID].allTime += (cpuCycle - g_cpup[taskID].startTime);
160 g_cpup[taskID].startTime = 0;
161 }
162
163 taskID = g_losTask.newTask->taskID;
164 g_cpup[taskID].cpupID = taskID;
165 g_cpup[taskID].startTime = cpuCycle;
166
167 if ((cpuCycle - g_lastRecordTime) > OS_CPUP_RECORD_PERIOD) {
168 g_lastRecordTime = cpuCycle;
169
170 for (loopNum = 0; loopNum < g_taskMaxNum; loopNum++) {
171 g_cpup[loopNum].historyTime[g_hisPos] = g_cpup[loopNum].allTime;
172 }
173
174 if (g_hisPos == (OS_CPUP_HISTORY_RECORD_NUM - 1)) {
175 g_hisPos = 0;
176 } else {
177 g_hisPos++;
178 }
179 }
180
181 return;
182 }
183
OsGetPrePos(UINT16 curPos)184 LITE_OS_SEC_TEXT_MINOR static inline UINT16 OsGetPrePos(UINT16 curPos)
185 {
186 return (curPos == 0) ? (OS_CPUP_HISTORY_RECORD_NUM - 1) : (curPos - 1);
187 }
188
OsGetPositions(UINT16 mode,UINT16 * curPosAddr,UINT16 * prePosAddr)189 LITE_OS_SEC_TEXT_MINOR static VOID OsGetPositions(UINT16 mode, UINT16* curPosAddr, UINT16* prePosAddr)
190 {
191 UINT16 curPos;
192 UINT16 prePos = 0;
193
194 curPos = g_hisPos;
195
196 if (mode == CPUP_IN_1S) {
197 curPos = OsGetPrePos(curPos);
198 prePos = OsGetPrePos(curPos);
199 } else if (mode == CPUP_LESS_THAN_1S) {
200 curPos = OsGetPrePos(curPos);
201 }
202
203 *curPosAddr = curPos;
204 *prePosAddr = prePos;
205 }
206
207 /*****************************************************************************
208 Function : LOS_SysCpuUsage
209 Description: get current CPU usage
210 Input : None
211 Return : cpupRet:current CPU usage
212 *****************************************************************************/
LOS_SysCpuUsage(VOID)213 LITE_OS_SEC_TEXT_MINOR UINT32 LOS_SysCpuUsage(VOID)
214 {
215 UINT64 cpuCycleAll = 0;
216 UINT32 cpupRet = 0;
217 UINT16 loopNum;
218 UINT32 intSave;
219
220 if (g_cpupInitFlg == 0) {
221 return LOS_ERRNO_CPUP_NO_INIT;
222 }
223
224 // get end time of current task
225 intSave = LOS_IntLock();
226 OsTskCycleEnd();
227
228 for (loopNum = 0; loopNum < g_taskMaxNum; loopNum++) {
229 cpuCycleAll += g_cpup[loopNum].allTime;
230 }
231
232 if (cpuCycleAll) {
233 cpupRet = LOS_CPUP_PRECISION - (UINT32)((LOS_CPUP_PRECISION *
234 g_cpup[g_idleTaskID].allTime) / cpuCycleAll);
235 }
236
237 OsTskCycleStart();
238 LOS_IntRestore(intSave);
239
240 return cpupRet;
241 }
242
243 /*****************************************************************************
244 Function : LOS_HistorySysCpuUsage
245 Description: get CPU usage history
246 Input : mode: mode,0 = usage in 10s,1 = usage in last 1s, else = less than 1s
247 Return : cpupRet:CPU usage history
248 *****************************************************************************/
LOS_HistorySysCpuUsage(UINT16 mode)249 LITE_OS_SEC_TEXT_MINOR UINT32 LOS_HistorySysCpuUsage(UINT16 mode)
250 {
251 UINT64 cpuCycleAll = 0;
252 UINT64 idleCycleAll = 0;
253 UINT32 cpupRet = 0;
254 UINT16 loopNum;
255 UINT16 curPos;
256 UINT16 prePos = 0;
257 UINT32 intSave;
258
259 if (g_cpupInitFlg == 0) {
260 return LOS_ERRNO_CPUP_NO_INIT;
261 }
262
263 // get end time of current task
264 intSave = LOS_IntLock();
265 OsTskCycleEnd();
266
267 OsGetPositions(mode, &curPos, &prePos);
268
269 for (loopNum = 0; loopNum < g_taskMaxNum; loopNum++) {
270 if (mode == CPUP_IN_1S) {
271 cpuCycleAll += g_cpup[loopNum].historyTime[curPos] - g_cpup[loopNum].historyTime[prePos];
272 } else {
273 cpuCycleAll += g_cpup[loopNum].allTime - g_cpup[loopNum].historyTime[curPos];
274 }
275 }
276
277 if (mode == CPUP_IN_1S) {
278 idleCycleAll += g_cpup[g_idleTaskID].historyTime[curPos] -
279 g_cpup[g_idleTaskID].historyTime[prePos];
280 } else {
281 idleCycleAll += g_cpup[g_idleTaskID].allTime - g_cpup[g_idleTaskID].historyTime[curPos];
282 }
283
284 if (cpuCycleAll) {
285 cpupRet = (LOS_CPUP_PRECISION - (UINT32)((LOS_CPUP_PRECISION * idleCycleAll) / cpuCycleAll));
286 }
287
288 OsTskCycleStart();
289 LOS_IntRestore(intSave);
290
291 return cpupRet;
292 }
293
294 /*****************************************************************************
295 Function : LOS_TaskCpuUsage
296 Description: get CPU usage of certain task
297 Input : taskID : task ID
298 Return : cpupRet:CPU usage of certain task
299 *****************************************************************************/
LOS_TaskCpuUsage(UINT32 taskID)300 LITE_OS_SEC_TEXT_MINOR UINT32 LOS_TaskCpuUsage(UINT32 taskID)
301 {
302 UINT64 cpuCycleAll = 0;
303 UINT16 loopNum;
304 UINT32 intSave;
305 UINT32 cpupRet = 0;
306
307 if (g_cpupInitFlg == 0) {
308 return LOS_ERRNO_CPUP_NO_INIT;
309 }
310 if (OS_TSK_GET_INDEX(taskID) >= g_taskMaxNum) {
311 return LOS_ERRNO_CPUP_TSK_ID_INVALID;
312 }
313 if (g_cpup[taskID].cpupID != taskID) {
314 return LOS_ERRNO_CPUP_THREAD_NO_CREATED;
315 }
316 if ((g_cpup[taskID].status & OS_TASK_STATUS_UNUSED) || (g_cpup[taskID].status == 0)) {
317 return LOS_ERRNO_CPUP_THREAD_NO_CREATED;
318 }
319 intSave = LOS_IntLock();
320 OsTskCycleEnd();
321
322 /* get total Cycle */
323 for (loopNum = 0; loopNum < g_taskMaxNum; loopNum++) {
324 if ((g_cpup[loopNum].status & OS_TASK_STATUS_UNUSED) || (g_cpup[loopNum].status == 0)) {
325 continue;
326 }
327 cpuCycleAll += g_cpup[loopNum].allTime;
328 }
329
330 if (cpuCycleAll) {
331 cpupRet = (UINT32)((LOS_CPUP_PRECISION * g_cpup[taskID].allTime) / cpuCycleAll);
332 }
333
334 OsTskCycleStart();
335 LOS_IntRestore(intSave);
336
337 return cpupRet;
338 }
339
340 /*****************************************************************************
341 Function : LOS_HistoryTaskCpuUsage
342 Description: get CPU usage history of certain task
343 Input : taskID : task ID
344 : mode: mode,0 = usage in 10s,1 = usage in last 1s, else = less than 1s
345 Return : cpupRet:CPU usage history of task
346 *****************************************************************************/
LOS_HistoryTaskCpuUsage(UINT32 taskID,UINT16 mode)347 LITE_OS_SEC_TEXT_MINOR UINT32 LOS_HistoryTaskCpuUsage(UINT32 taskID, UINT16 mode)
348 {
349 UINT64 cpuCycleAll = 0;
350 UINT64 cpuCycleCurTsk = 0;
351 UINT16 loopNum, curPos;
352 UINT16 prePos = 0;
353 UINT32 intSave;
354 UINT32 cpupRet = 0;
355
356 if (g_cpupInitFlg == 0) {
357 return LOS_ERRNO_CPUP_NO_INIT;
358 }
359 if (OS_TSK_GET_INDEX(taskID) >= g_taskMaxNum) {
360 return LOS_ERRNO_CPUP_TSK_ID_INVALID;
361 }
362 if (g_cpup[taskID].cpupID != taskID) {
363 return LOS_ERRNO_CPUP_THREAD_NO_CREATED;
364 }
365 if ((g_cpup[taskID].status & OS_TASK_STATUS_UNUSED) || (g_cpup[taskID].status == 0)) {
366 return LOS_ERRNO_CPUP_THREAD_NO_CREATED;
367 }
368 intSave = LOS_IntLock();
369 OsTskCycleEnd();
370
371 OsGetPositions(mode, &curPos, &prePos);
372
373 /* get total Cycle in history */
374 for (loopNum = 0; loopNum < g_taskMaxNum; loopNum++) {
375 if ((g_cpup[loopNum].status & OS_TASK_STATUS_UNUSED) || (g_cpup[loopNum].status == 0)) {
376 continue;
377 }
378
379 if (mode == CPUP_IN_1S) {
380 cpuCycleAll += g_cpup[loopNum].historyTime[curPos] - g_cpup[loopNum].historyTime[prePos];
381 } else {
382 cpuCycleAll += g_cpup[loopNum].allTime - g_cpup[loopNum].historyTime[curPos];
383 }
384 }
385
386 if (mode == CPUP_IN_1S) {
387 cpuCycleCurTsk += g_cpup[taskID].historyTime[curPos] - g_cpup[taskID].historyTime[prePos];
388 } else {
389 cpuCycleCurTsk += g_cpup[taskID].allTime - g_cpup[taskID].historyTime[curPos];
390 }
391 if (cpuCycleAll) {
392 cpupRet = (UINT32)((LOS_CPUP_PRECISION * cpuCycleCurTsk) / cpuCycleAll);
393 }
394
395 OsTskCycleStart();
396 LOS_IntRestore(intSave);
397
398 return cpupRet;
399 }
400
LOS_AllTaskCpuUsage(CPUP_INFO_S * cpupInfo,UINT16 mode)401 LITE_OS_SEC_TEXT_MINOR UINT32 LOS_AllTaskCpuUsage(CPUP_INFO_S *cpupInfo, UINT16 mode)
402 {
403 UINT16 loopNum;
404 UINT16 curPos;
405 UINT16 prePos = 0;
406 UINT32 intSave;
407 UINT64 cpuCycleAll = 0;
408 UINT64 cpuCycleCurTsk = 0;
409
410 if (g_cpupInitFlg == 0) {
411 return LOS_ERRNO_CPUP_NO_INIT;
412 }
413
414 if (cpupInfo == NULL) {
415 return LOS_ERRNO_CPUP_TASK_PTR_NULL;
416 }
417
418 intSave = LOS_IntLock();
419 OsTskCycleEnd();
420
421 OsGetPositions(mode, &curPos, &prePos);
422
423 for (loopNum = 0; loopNum < g_taskMaxNum; loopNum++) {
424 if ((g_cpup[loopNum].status & OS_TASK_STATUS_UNUSED) ||
425 (g_cpup[loopNum].status == 0)) {
426 continue;
427 }
428
429 if (mode == CPUP_IN_1S) {
430 cpuCycleAll += g_cpup[loopNum].historyTime[curPos] - g_cpup[loopNum].historyTime[prePos];
431 } else {
432 cpuCycleAll += g_cpup[loopNum].allTime - g_cpup[loopNum].historyTime[curPos];
433 }
434 }
435
436 for (loopNum = 0; loopNum < g_taskMaxNum; loopNum++) {
437 if ((g_cpup[loopNum].status & OS_TASK_STATUS_UNUSED) ||
438 (g_cpup[loopNum].status == 0)) {
439 continue;
440 }
441
442 if (mode == CPUP_IN_1S) {
443 cpuCycleCurTsk += g_cpup[loopNum].historyTime[curPos] - g_cpup[loopNum].historyTime[prePos];
444 } else {
445 cpuCycleCurTsk += g_cpup[loopNum].allTime - g_cpup[loopNum].historyTime[curPos];
446 }
447 cpupInfo[loopNum].usStatus = g_cpup[loopNum].status;
448 if (cpuCycleAll) {
449 cpupInfo[loopNum].uwUsage = (UINT32)((LOS_CPUP_PRECISION * cpuCycleCurTsk) / cpuCycleAll);
450 }
451
452 cpuCycleCurTsk = 0;
453 }
454
455 OsTskCycleStart();
456 LOS_IntRestore(intSave);
457
458 return LOS_OK;
459 }
460
461 /*****************************************************************************
462 Function : LOS_CpupUsageMonitor
463 Description: Get CPU usage history of certain task.
464 Input : type: cpup type, SYS_CPU_USAGE and TASK_CPU_USAGE
465 : taskID: task ID, Only in SYS_CPU_USAGE type, taskID is invalid
466 : mode: mode, CPUP_IN_10S = usage in 10s, CPUP_IN_1S = usage in last 1s, CPUP_LESS_THAN_1S = less than 1s
467 Return : LOS_OK on success, or OS_ERROR on failure
468 *****************************************************************************/
LOS_CpupUsageMonitor(CPUP_TYPE_E type,CPUP_MODE_E mode,UINT32 taskID)469 LITE_OS_SEC_TEXT_MINOR UINT32 LOS_CpupUsageMonitor(CPUP_TYPE_E type, CPUP_MODE_E mode, UINT32 taskID)
470 {
471 UINT32 ret;
472 LosTaskCB *taskCB = NULL;
473
474 switch (type) {
475 case SYS_CPU_USAGE:
476 if (mode == CPUP_IN_10S) {
477 PRINTK("\nSysCpuUsage in 10s: ");
478 } else if (mode == CPUP_IN_1S) {
479 PRINTK("\nSysCpuUsage in 1s: ");
480 } else {
481 PRINTK("\nSysCpuUsage in <1s: ");
482 }
483 ret = LOS_HistorySysCpuUsage(mode);
484 PRINTK("%d.%d", ret / LOS_CPUP_PRECISION_MULT, ret % LOS_CPUP_PRECISION_MULT);
485 break;
486
487 case TASK_CPU_USAGE:
488 if (taskID > LOSCFG_BASE_CORE_TSK_LIMIT) {
489 PRINT_ERR("\nThe taskid is invalid.\n");
490 return OS_ERROR;
491 }
492 taskCB = OS_TCB_FROM_TID(taskID);
493 if ((taskCB->taskStatus & OS_TASK_STATUS_UNUSED)) {
494 PRINT_ERR("\nThe taskid is invalid.\n");
495 return OS_ERROR;
496 }
497 if (mode == CPUP_IN_10S) {
498 PRINTK("\nCPUusage of taskID %d in 10s: ", taskID);
499 } else if (mode == CPUP_IN_1S) {
500 PRINTK("\nCPUusage of taskID %d in 1s: ", taskID);
501 } else {
502 PRINTK("\nCPUusage of taskID %d in <1s: ", taskID);
503 }
504 ret = LOS_HistoryTaskCpuUsage(taskID, mode);
505 PRINTK("%u.%u", ret / LOS_CPUP_PRECISION_MULT, ret % LOS_CPUP_PRECISION_MULT);
506 break;
507
508 default:
509 PRINT_ERR("\nThe type is invalid.\n");
510 return OS_ERROR;
511 }
512
513 return LOS_OK;
514 }
515
516 #endif /* LOSCFG_BASE_CORE_CPUP */
517