1 /*
2 * Copyright (c) 2022-2022 Huawei Device Co., Ltd. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific prior written
16 * permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "los_statistics_pri.h"
32 #include "los_task_pri.h"
33 #include "los_process_pri.h"
34
35 #ifdef LOSCFG_SCHED_DEBUG
36 #ifdef LOSCFG_SCHED_TICK_DEBUG
37 typedef struct {
38 UINT64 responseTime;
39 UINT64 responseTimeMax;
40 UINT64 count;
41 } SchedTickDebug;
42 STATIC SchedTickDebug *g_schedTickDebug = NULL;
43
OsSchedDebugInit(VOID)44 UINT32 OsSchedDebugInit(VOID)
45 {
46 UINT32 size = sizeof(SchedTickDebug) * LOSCFG_KERNEL_CORE_NUM;
47 g_schedTickDebug = (SchedTickDebug *)LOS_MemAlloc(m_aucSysMem0, size);
48 if (g_schedTickDebug == NULL) {
49 return LOS_ERRNO_TSK_NO_MEMORY;
50 }
51
52 (VOID)memset_s(g_schedTickDebug, size, 0, size);
53 return LOS_OK;
54 }
55
OsSchedDebugRecordData(VOID)56 VOID OsSchedDebugRecordData(VOID)
57 {
58 SchedRunqueue *rq = OsSchedRunqueue();
59 SchedTickDebug *schedDebug = &g_schedTickDebug[ArchCurrCpuid()];
60 UINT64 currTime = OsGetCurrSchedTimeCycle();
61 LOS_ASSERT(currTime >= rq->responseTime);
62 UINT64 usedTime = currTime - rq->responseTime;
63 schedDebug->responseTime += usedTime;
64 if (usedTime > schedDebug->responseTimeMax) {
65 schedDebug->responseTimeMax = usedTime;
66 }
67 schedDebug->count++;
68 }
69
OsShellShowTickResponse(VOID)70 UINT32 OsShellShowTickResponse(VOID)
71 {
72 UINT32 intSave;
73 UINT16 cpu;
74
75 UINT32 tickSize = sizeof(SchedTickDebug) * LOSCFG_KERNEL_CORE_NUM;
76 SchedTickDebug *schedDebug = (SchedTickDebug *)LOS_MemAlloc(m_aucSysMem1, tickSize);
77 if (schedDebug == NULL) {
78 return LOS_NOK;
79 }
80
81 SCHEDULER_LOCK(intSave);
82 (VOID)memcpy_s((CHAR *)schedDebug, tickSize, (CHAR *)g_schedTickDebug, tickSize);
83 SCHEDULER_UNLOCK(intSave);
84
85 PRINTK("cpu ATRTime(us) ATRTimeMax(us) TickCount\n");
86 for (cpu = 0; cpu < LOSCFG_KERNEL_CORE_NUM; cpu++) {
87 SchedTickDebug *schedData = &schedDebug[cpu];
88 UINT64 averTime = 0;
89 if (schedData->count > 0) {
90 averTime = schedData->responseTime / schedData->count;
91 averTime = (averTime * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US;
92 }
93 UINT64 timeMax = (schedData->responseTimeMax * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US;
94 PRINTK("%3u%14llu%15llu%11llu\n", cpu, averTime, timeMax, schedData->count);
95 }
96
97 (VOID)LOS_MemFree(m_aucSysMem1, schedDebug);
98 return LOS_OK;
99 }
100 #endif
101
102 #ifdef LOSCFG_SCHED_HPF_DEBUG
SchedDataGet(const LosTaskCB * taskCB,UINT64 * runTime,UINT64 * timeSlice,UINT64 * pendTime,UINT64 * schedWait)103 STATIC VOID SchedDataGet(const LosTaskCB *taskCB, UINT64 *runTime, UINT64 *timeSlice,
104 UINT64 *pendTime, UINT64 *schedWait)
105 {
106 if (taskCB->schedStat.switchCount >= 1) {
107 UINT64 averRunTime = taskCB->schedStat.runTime / taskCB->schedStat.switchCount;
108 *runTime = (averRunTime * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US;
109 }
110
111 if (taskCB->schedStat.timeSliceCount > 1) {
112 UINT64 averTimeSlice = taskCB->schedStat.timeSliceTime / (taskCB->schedStat.timeSliceCount - 1);
113 *timeSlice = (averTimeSlice * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US;
114 }
115
116 if (taskCB->schedStat.pendCount > 1) {
117 UINT64 averPendTime = taskCB->schedStat.pendTime / taskCB->schedStat.pendCount;
118 *pendTime = (averPendTime * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US;
119 }
120
121 if (taskCB->schedStat.waitSchedCount > 0) {
122 UINT64 averSchedWait = taskCB->schedStat.waitSchedTime / taskCB->schedStat.waitSchedCount;
123 *schedWait = (averSchedWait * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US;
124 }
125 }
126
OsShellShowSchedStatistics(VOID)127 UINT32 OsShellShowSchedStatistics(VOID)
128 {
129 UINT32 taskLinkNum[LOSCFG_KERNEL_CORE_NUM];
130 UINT32 intSave;
131 LosTaskCB task;
132 SchedEDF *sched = NULL;
133
134 SCHEDULER_LOCK(intSave);
135 for (UINT16 cpu = 0; cpu < LOSCFG_KERNEL_CORE_NUM; cpu++) {
136 SchedRunqueue *rq = OsSchedRunqueueByID(cpu);
137 taskLinkNum[cpu] = OsGetSortLinkNodeNum(&rq->timeoutQueue);
138 }
139 SCHEDULER_UNLOCK(intSave);
140
141 for (UINT16 cpu = 0; cpu < LOSCFG_KERNEL_CORE_NUM; cpu++) {
142 PRINTK("cpu: %u Task SortMax: %u\n", cpu, taskLinkNum[cpu]);
143 }
144
145 PRINTK(" Tid AverRunTime(us) SwitchCount AverTimeSlice(us) TimeSliceCount AverReadyWait(us) "
146 "AverPendTime(us) TaskName \n");
147 for (UINT32 tid = 0; tid < g_taskMaxNum; tid++) {
148 LosTaskCB *taskCB = g_taskCBArray + tid;
149 SCHEDULER_LOCK(intSave);
150 if (OsTaskIsUnused(taskCB) || (taskCB->processCB == (UINTPTR)OsGetIdleProcess())) {
151 SCHEDULER_UNLOCK(intSave);
152 continue;
153 }
154
155 sched = (SchedEDF *)&taskCB->sp;
156 if (sched->policy == LOS_SCHED_DEADLINE) {
157 SCHEDULER_UNLOCK(intSave);
158 continue;
159 }
160
161 (VOID)memcpy_s(&task, sizeof(LosTaskCB), taskCB, sizeof(LosTaskCB));
162 SCHEDULER_UNLOCK(intSave);
163
164 UINT64 averRunTime = 0;
165 UINT64 averTimeSlice = 0;
166 UINT64 averPendTime = 0;
167 UINT64 averSchedWait = 0;
168
169 SchedDataGet(&task, &averRunTime, &averTimeSlice, &averPendTime, &averSchedWait);
170
171 PRINTK("%5u%19llu%15llu%19llu%18llu%19llu%18llu %-32s\n", taskCB->taskID,
172 averRunTime, taskCB->schedStat.switchCount,
173 averTimeSlice, taskCB->schedStat.timeSliceCount - 1,
174 averSchedWait, averPendTime, taskCB->taskName);
175 }
176
177 return LOS_OK;
178 }
179 #endif
180
181 #ifdef LOSCFG_SCHED_EDF_DEBUG
182 #define EDF_DEBUG_NODE 20
183 typedef struct {
184 UINT32 tid;
185 INT32 runTimeUs;
186 UINT64 deadlineUs;
187 UINT64 periodUs;
188 UINT64 startTime;
189 UINT64 finishTime;
190 UINT64 nextfinishTime;
191 UINT64 timeSliceUnused;
192 UINT64 timeSliceRealTime;
193 UINT64 allRuntime;
194 UINT64 pendTime;
195 } EDFDebug;
196
197 STATIC EDFDebug g_edfNode[EDF_DEBUG_NODE];
198 STATIC INT32 g_edfNodePointer = 0;
199
EDFDebugRecord(UINTPTR * task,UINT64 oldFinish)200 VOID EDFDebugRecord(UINTPTR *task, UINT64 oldFinish)
201 {
202 LosTaskCB *taskCB = (LosTaskCB *)task;
203 SchedEDF *sched = (SchedEDF *)&taskCB->sp;
204 SchedParam param;
205
206 // when print edf info, will stop record
207 if (g_edfNodePointer == (EDF_DEBUG_NODE + 1)) {
208 return;
209 }
210
211 taskCB->ops->schedParamGet(taskCB, ¶m);
212 g_edfNode[g_edfNodePointer].tid = taskCB->taskID;
213 g_edfNode[g_edfNodePointer].runTimeUs =param.runTimeUs;
214 g_edfNode[g_edfNodePointer].deadlineUs =param.deadlineUs;
215 g_edfNode[g_edfNodePointer].periodUs =param.periodUs;
216 g_edfNode[g_edfNodePointer].startTime = taskCB->startTime;
217 if (taskCB->timeSlice <= 0) {
218 taskCB->irqUsedTime = 0;
219 g_edfNode[g_edfNodePointer].timeSliceUnused = 0;
220 } else {
221 g_edfNode[g_edfNodePointer].timeSliceUnused = taskCB->timeSlice;
222 }
223 g_edfNode[g_edfNodePointer].finishTime = oldFinish;
224 g_edfNode[g_edfNodePointer].nextfinishTime = sched->finishTime;
225 g_edfNode[g_edfNodePointer].timeSliceRealTime = taskCB->schedStat.timeSliceRealTime;
226 g_edfNode[g_edfNodePointer].allRuntime = taskCB->schedStat.allRuntime;
227 g_edfNode[g_edfNodePointer].pendTime = taskCB->schedStat.pendTime;
228
229 g_edfNodePointer++;
230 if (g_edfNodePointer == EDF_DEBUG_NODE) {
231 g_edfNodePointer = 0;
232 }
233 }
234
EDFInfoPrint(int idx)235 STATIC VOID EDFInfoPrint(int idx)
236 {
237 INT32 runTimeUs;
238 UINT64 deadlineUs;
239 UINT64 periodUs;
240 UINT64 startTime;
241 UINT64 timeSlice;
242 UINT64 finishTime;
243 UINT64 nextfinishTime;
244 UINT64 pendTime;
245 UINT64 allRuntime;
246 UINT64 timeSliceRealTime;
247 CHAR *status = NULL;
248
249 startTime = OS_SYS_CYCLE_TO_US(g_edfNode[idx].startTime);
250 timeSlice = OS_SYS_CYCLE_TO_US(g_edfNode[idx].timeSliceUnused);
251 finishTime = OS_SYS_CYCLE_TO_US(g_edfNode[idx].finishTime);
252 nextfinishTime = OS_SYS_CYCLE_TO_US(g_edfNode[idx].nextfinishTime);
253 pendTime = OS_SYS_CYCLE_TO_US(g_edfNode[idx].pendTime);
254 allRuntime = OS_SYS_CYCLE_TO_US(g_edfNode[idx].allRuntime);
255 timeSliceRealTime = OS_SYS_CYCLE_TO_US(g_edfNode[idx].timeSliceRealTime);
256 runTimeUs = g_edfNode[idx].runTimeUs;
257 deadlineUs = g_edfNode[idx].deadlineUs;
258 periodUs = g_edfNode[idx].periodUs;
259
260 if (timeSlice > 0) {
261 status = "TIMEOUT";
262 } else if (nextfinishTime == finishTime) {
263 status = "NEXT PERIOD";
264 } else {
265 status = "WAIT RUN";
266 }
267
268 PRINTK("%4u%9d%9llu%9llu%12llu%12llu%12llu%9llu%9llu%9llu%9llu %-12s\n",
269 g_edfNode[idx].tid, runTimeUs, deadlineUs, periodUs,
270 startTime, finishTime, nextfinishTime, allRuntime, timeSliceRealTime,
271 timeSlice, pendTime, status);
272 }
273
OsEDFDebugPrint(VOID)274 VOID OsEDFDebugPrint(VOID)
275 {
276 INT32 max;
277 UINT32 intSave;
278 INT32 i;
279
280 SCHEDULER_LOCK(intSave);
281 max = g_edfNodePointer;
282 g_edfNodePointer = EDF_DEBUG_NODE + 1;
283 SCHEDULER_UNLOCK(intSave);
284
285 PRINTK("\r\nlast %d sched is: (in microsecond)\r\n", EDF_DEBUG_NODE);
286
287 PRINTK(" TID RunTime Deadline Period StartTime "
288 "CurPeriod NextPeriod AllRun RealRun TimeOut WaitTime Status\n");
289
290 for (i = max; i < EDF_DEBUG_NODE; i++) {
291 EDFInfoPrint(i);
292 }
293
294 for (i = 0; i < max; i++) {
295 EDFInfoPrint(i);
296 }
297
298 SCHEDULER_LOCK(intSave);
299 g_edfNodePointer = max;
300 SCHEDULER_UNLOCK(intSave);
301 }
302
OsShellShowEdfSchedStatistics(VOID)303 UINT32 OsShellShowEdfSchedStatistics(VOID)
304 {
305 UINT32 intSave;
306 LosTaskCB task;
307 UINT64 curTime;
308 UINT64 deadline;
309 UINT64 finishTime;
310 SchedEDF *sched = NULL;
311
312 PRINTK("Now Alive EDF Thread:\n");
313 PRINTK("TID CurTime DeadTime FinishTime taskName\n");
314
315 for (UINT32 tid = 0; tid < g_taskMaxNum; tid++) {
316 LosTaskCB *taskCB = g_taskCBArray + tid;
317 SCHEDULER_LOCK(intSave);
318 if (OsTaskIsUnused(taskCB)) {
319 SCHEDULER_UNLOCK(intSave);
320 continue;
321 }
322
323 sched = (SchedEDF *)&taskCB->sp;
324 if (sched->policy != LOS_SCHED_DEADLINE) {
325 SCHEDULER_UNLOCK(intSave);
326 continue;
327 }
328
329 (VOID)memcpy_s(&task, sizeof(LosTaskCB), taskCB, sizeof(LosTaskCB));
330
331 curTime = OS_SYS_CYCLE_TO_US(HalClockGetCycles());
332 finishTime = OS_SYS_CYCLE_TO_US(sched->finishTime);
333 deadline = OS_SYS_CYCLE_TO_US(taskCB->ops->deadlineGet(taskCB));
334 SCHEDULER_UNLOCK(intSave);
335
336 PRINTK("%3u%15llu%15llu%15llu %-32s\n",
337 task.taskID, curTime, deadline, finishTime, task.taskName);
338 }
339
340 OsEDFDebugPrint();
341
342 return LOS_OK;
343 }
344 #endif
345 #endif
346