• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &param);
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