LPCOpen Platform  v1.03
LPCOpen Platform for NXP LPC Microcontrollers
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
os_stat.c
Go to the documentation of this file.
1 /*
2 ************************************************************************************************************************
3 * uC/OS-III
4 * The Real-Time Kernel
5 *
6 * (c) Copyright 2009-2012; Micrium, Inc.; Weston, FL
7 * All rights reserved. Protected by international copyright laws.
8 *
9 * STATISTICS MODULE
10 *
11 * File : OS_STAT.C
12 * By : JJL
13 * Version : V3.03.00
14 *
15 * LICENSING TERMS:
16 * ---------------
17 * uC/OS-III is provided in source form for FREE short-term evaluation, for educational use or
18 * for peaceful research. If you plan or intend to use uC/OS-III in a commercial application/
19 * product then, you need to contact Micrium to properly license uC/OS-III for its use in your
20 * application/product. We provide ALL the source code for your convenience and to help you
21 * experience uC/OS-III. The fact that the source is provided does NOT mean that you can use
22 * it commercially without paying a licensing fee.
23 *
24 * Knowledge of the source code may NOT be used to develop a similar product.
25 *
26 * Please help us continue to provide the embedded community with the finest software available.
27 * Your honesty is greatly appreciated.
28 *
29 * You can contact us at www.micrium.com, or by phone at +1 (954) 217-2036.
30 ************************************************************************************************************************
31 */
32 
33 #define MICRIUM_SOURCE
34 #include <os.h>
35 
36 #ifdef VSC_INCLUDE_SOURCE_FILE_NAMES
37 const CPU_CHAR *os_stat__c = "$Id: $";
38 #endif
39 
40 
41 #if OS_CFG_STAT_TASK_EN > 0u
42 
43 /*
44 ************************************************************************************************************************
45 * RESET STATISTICS
46 *
47 * Description: This function is called by your application to reset the statistics.
48 *
49 * Argument(s): p_err is a pointer to a variable that will contain an error code returned by this function.
50 *
51 * OS_ERR_NONE
52 *
53 * Returns : none
54 ************************************************************************************************************************
55 */
56 
57 void OSStatReset (OS_ERR *p_err)
58 {
59 #if (OS_CFG_DBG_EN > 0u)
60  OS_TCB *p_tcb;
61 #if (OS_MSG_EN > 0u)
62  OS_MSG_Q *p_msg_q;
63 #endif
64 #if (OS_CFG_Q_EN > 0u)
65  OS_Q *p_q;
66 #endif
67  CPU_SR_ALLOC();
68 #endif
69 
70 
71 
72 #ifdef OS_SAFETY_CRITICAL
73  if (p_err == (OS_ERR *)0) {
74  OS_SAFETY_CRITICAL_EXCEPTION();
75  return;
76  }
77 #endif
78 
80 #if OS_CFG_ISR_POST_DEFERRED_EN > 0u
81  OSIntQTaskTimeMax = (CPU_TS )0; /* Reset the task execution times */
82  OSIntQNbrEntriesMax = (OS_OBJ_QTY)0; /* Reset the queue maximum number of entries */
83 #endif
84 
85 #if OS_CFG_STAT_TASK_EN > 0u
86  OSStatTaskCPUUsageMax = 0u;
87  OSStatTaskTimeMax = (CPU_TS)0;
88 #endif
89 
91 
92 #if OS_CFG_TMR_EN > 0u
93  OSTmrTaskTimeMax = (CPU_TS)0;
94 #endif
95 
96 #ifdef CPU_CFG_INT_DIS_MEAS_EN
97  OSIntDisTimeMax = (CPU_TS)0; /* Reset the maximum interrupt disable time */
98 #endif
99 
100 #if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u
101  OSSchedLockTimeMax = (CPU_TS)0; /* Reset the maximum scheduler lock time */
102 #endif
103 
104 #if OS_MSG_EN > 0u
105  OSMsgPool.NbrUsedMax = 0;
106 #endif
108 
109 #if OS_CFG_DBG_EN > 0u
111  p_tcb = OSTaskDbgListPtr;
113  while (p_tcb != (OS_TCB *)0) { /* Reset per-Task statistics */
115 
116 #ifdef CPU_CFG_INT_DIS_MEAS_EN
117  p_tcb->IntDisTimeMax = (CPU_TS )0;
118 #endif
119 
120 #if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u
121  p_tcb->SchedLockTimeMax = (CPU_TS )0;
122 #endif
123 
124 #if OS_CFG_TASK_PROFILE_EN > 0u
125 #if OS_CFG_TASK_Q_EN > 0u
126  p_tcb->MsgQPendTimeMax = (CPU_TS )0;
127 #endif
128  p_tcb->SemPendTimeMax = (CPU_TS )0;
129  p_tcb->CtxSwCtr = (OS_CTR )0;
130  p_tcb->CPUUsage = (OS_CPU_USAGE)0;
131  p_tcb->CPUUsageMax = (OS_CPU_USAGE)0;
132  p_tcb->CyclesTotal = (OS_CYCLES )0;
133  p_tcb->CyclesTotalPrev = (OS_CYCLES )0;
134  p_tcb->CyclesStart = OS_TS_GET();
135 #endif
136 
137 #if OS_CFG_TASK_Q_EN > 0u
138  p_msg_q = &p_tcb->MsgQ;
139  p_msg_q->NbrEntriesMax = (OS_MSG_QTY )0;
140 #endif
141  p_tcb = p_tcb->DbgNextPtr;
143  }
144 #endif
145 
146 #if (OS_CFG_Q_EN > 0u) && (OS_CFG_DBG_EN > 0u)
148  p_q = OSQDbgListPtr;
150  while (p_q != (OS_Q *)0) { /* Reset message queues statistics */
152  p_msg_q = &p_q->MsgQ;
153  p_msg_q->NbrEntriesMax = (OS_MSG_QTY)0;
154  p_q = p_q->DbgNextPtr;
156  }
157 #endif
158 
159  OS_TickListResetPeak(); /* Reset tick wheel statistics */
160 
161 #if OS_CFG_TMR_EN > 0u
162  OS_TmrResetPeak();
163 #endif
164 
165 
166  *p_err = OS_ERR_NONE;
167 }
168 
169 /*$PAGE*/
170 /*
171 ************************************************************************************************************************
172 * DETERMINE THE CPU CAPACITY
173 *
174 * Description: This function is called by your application to establish CPU usage by first determining how high a 32-bit
175 * counter would count to in 1/10 second if no other tasks were to execute during that time. CPU usage is
176 * then determined by a low priority task which keeps track of this 32-bit counter every second but this
177 * time, with other tasks running. CPU usage is determined by:
178 *
179 * OS_Stat_IdleCtr
180 * CPU Usage (%) = 100 * (1 - ------------------)
181 * OS_Stat_IdleCtrMax
182 *
183 * Argument(s): p_err is a pointer to a variable that will contain an error code returned by this function.
184 *
185 * OS_ERR_NONE
186 *
187 * Returns : none
188 ************************************************************************************************************************
189 */
190 
191 void OSStatTaskCPUUsageInit (OS_ERR *p_err)
192 {
193  OS_ERR err;
194  OS_TICK dly;
195  CPU_SR_ALLOC();
196 
197 
198 
199 #ifdef OS_SAFETY_CRITICAL
200  if (p_err == (OS_ERR *)0) {
201  OS_SAFETY_CRITICAL_EXCEPTION();
202  return;
203  }
204 #endif
205 
206 #if (OS_CFG_TMR_EN > 0u)
207  OSTaskSuspend(&OSTmrTaskTCB, &err);
208  if (err != OS_ERR_NONE) {
209  *p_err = err;
210  return;
211  }
212 #endif
213 
214  OSTimeDly((OS_TICK )2, /* Synchronize with clock tick */
216  (OS_ERR *)&err);
217  if (err != OS_ERR_NONE) {
218  *p_err = err;
219  return;
220  }
222  OSStatTaskCtr = (OS_TICK)0; /* Clear idle counter */
224 
225  dly = (OS_TICK)0;
228  }
229  if (dly == (OS_TICK)0) {
230  dly = (OS_TICK)(OSCfg_TickRate_Hz / (OS_RATE_HZ)10);
231  }
232 
233  OSTimeDly(dly, /* Determine MAX. idle counter value */
234  OS_OPT_TIME_DLY,
235  &err);
236 
237 #if (OS_CFG_TMR_EN > 0u)
238  OSTaskResume(&OSTmrTaskTCB, &err);
239  if (err != OS_ERR_NONE) {
240  *p_err = err;
241  return;
242  }
243 #endif
244 
246  OSStatTaskTimeMax = (CPU_TS)0;
247 
248  OSStatTaskCtrMax = OSStatTaskCtr; /* Store maximum idle counter count */
249  OSStatTaskRdy = OS_STATE_RDY;
251  *p_err = OS_ERR_NONE;
252 }
253 
254 /*$PAGE*/
255 /*
256 ************************************************************************************************************************
257 * STATISTICS TASK
258 *
259 * Description: This task is internal to uC/OS-III and is used to compute some statistics about the multitasking
260 * environment. Specifically, OS_StatTask() computes the CPU usage. CPU usage is determined by:
261 *
262 * OSStatTaskCtr
263 * OSStatTaskCPUUsage = 100 * (1 - ------------------) (units are in %)
264 * OSStatTaskCtrMax
265 *
266 * Arguments : p_arg this pointer is not used at this time.
267 *
268 * Returns : none
269 *
270 * Note(s) : 1) This task runs at a priority level higher than the idle task.
271 *
272 * 2) You can disable this task by setting the configuration #define OS_CFG_STAT_TASK_EN to 0.
273 *
274 * 3) You MUST have at least a delay of 2/10 seconds to allow for the system to establish the maximum value
275 * for the idle counter.
276 *
277 * 4) This function is INTERNAL to uC/OS-III and your application should not call it.
278 ************************************************************************************************************************
279 */
280 
281 void OS_StatTask (void *p_arg)
282 {
283 #if OS_CFG_DBG_EN > 0u
284 #if OS_CFG_TASK_PROFILE_EN > 0u
285  OS_CPU_USAGE usage;
286  OS_CYCLES cycles_total;
287  OS_CYCLES cycles_div;
288  OS_CYCLES cycles_mult;
289  OS_CYCLES cycles_max;
290 #endif
291  OS_TCB *p_tcb;
292 #endif
293  OS_TICK ctr_max;
294  OS_TICK ctr_mult;
295  OS_TICK ctr_div;
296  OS_ERR err;
297  OS_TICK dly;
298  CPU_TS ts_start;
299  CPU_TS ts_end;
300  CPU_SR_ALLOC();
301 
302 
303 
304  p_arg = p_arg; /* Prevent compiler warning for not using 'p_arg' */
305  while (OSStatTaskRdy != DEF_TRUE) {
306  OSTimeDly(2u * OSCfg_StatTaskRate_Hz, /* Wait until statistic task is ready */
307  OS_OPT_TIME_DLY,
308  &err);
309  }
310  OSStatReset(&err); /* Reset statistics */
311 
312  dly = (OS_TICK)0; /* Compute statistic task sleep delay */
315  }
316  if (dly == (OS_TICK)0) {
317  dly = (OS_TICK)(OSCfg_TickRate_Hz / (OS_RATE_HZ)10);
318  }
319 
320  while (DEF_ON) {
321  ts_start = OS_TS_GET();
322 #ifdef CPU_CFG_INT_DIS_MEAS_EN
323  OSIntDisTimeMax = CPU_IntDisMeasMaxGet();
324 #endif
325 
326  CPU_CRITICAL_ENTER(); /* ----------------- OVERALL CPU USAGE ------------------ */
327  OSStatTaskCtrRun = OSStatTaskCtr; /* Obtain the of the stat counter for the past .1 second */
328  OSStatTaskCtr = (OS_TICK)0; /* Reset the stat counter for the next .1 second */
330 
331  if (OSStatTaskCtrMax > OSStatTaskCtrRun) { /* Compute CPU Usage with best resolution */
332  if (OSStatTaskCtrMax < 400000u) { /* 1 to 400,000 */
333  ctr_mult = 10000u;
334  ctr_div = 1u;
335  } else if (OSStatTaskCtrMax < 4000000u) { /* 400,000 to 4,000,000 */
336  ctr_mult = 1000u;
337  ctr_div = 10u;
338  } else if (OSStatTaskCtrMax < 40000000u) { /* 4,000,000 to 40,000,000 */
339  ctr_mult = 100u;
340  ctr_div = 100u;
341  } else if (OSStatTaskCtrMax < 400000000u) { /* 40,000,000 to 400,000,000 */
342  ctr_mult = 10u;
343  ctr_div = 1000u;
344  } else { /* 400,000,000 and up */
345  ctr_mult = 1u;
346  ctr_div = 10000u;
347  }
348  ctr_max = OSStatTaskCtrMax / ctr_div;
349  OSStatTaskCPUUsage = (OS_CPU_USAGE)((OS_TICK)10000u - ctr_mult * OSStatTaskCtrRun / ctr_max);
350  if (OSStatTaskCPUUsageMax < OSStatTaskCPUUsage) {
351  OSStatTaskCPUUsageMax = OSStatTaskCPUUsage;
352  }
353  } else {
354  OSStatTaskCPUUsage = (OS_CPU_USAGE)10000u;
355  }
356 
357  OSStatTaskHook(); /* Invoke user definable hook */
358 
359 
360 #if OS_CFG_DBG_EN > 0u
361 #if OS_CFG_TASK_PROFILE_EN > 0u
362  cycles_total = (OS_CYCLES)0;
363 
365  p_tcb = OSTaskDbgListPtr;
367  while (p_tcb != (OS_TCB *)0) { /* ----------------- TOTAL CYCLES COUNT ----------------- */
369  p_tcb->CyclesTotalPrev = p_tcb->CyclesTotal; /* Save accumulated # cycles into a temp variable */
370  p_tcb->CyclesTotal = (OS_CYCLES)0; /* Reset total cycles for task for next run */
372 
373  cycles_total += p_tcb->CyclesTotalPrev;/* Perform sum of all task # cycles */
374 
376  p_tcb = p_tcb->DbgNextPtr;
378  }
379 #endif
380 
381 
382 #if OS_CFG_TASK_PROFILE_EN > 0u
383  /* ------------- INDIVIDUAL TASK CPU USAGE -------------- */
384  if (cycles_total > (OS_CYCLES)0u) { /* 'cycles_total' scaling ... */
385  if (cycles_total < 400000u) { /* 1 to 400,000 */
386  cycles_mult = 10000u;
387  cycles_div = 1u;
388  } else if (cycles_total < 4000000u) { /* 400,000 to 4,000,000 */
389  cycles_mult = 1000u;
390  cycles_div = 10u;
391  } else if (cycles_total < 40000000u) { /* 4,000,000 to 40,000,000 */
392  cycles_mult = 100u;
393  cycles_div = 100u;
394  } else if (cycles_total < 400000000u) { /* 40,000,000 to 400,000,000 */
395  cycles_mult = 10u;
396  cycles_div = 1000u;
397  } else { /* 400,000,000 and up */
398  cycles_mult = 1u;
399  cycles_div = 10000u;
400  }
401  cycles_max = cycles_total / cycles_div;
402  } else {
403  cycles_mult = 0u;
404  cycles_max = 1u;
405  }
406 #endif
408  p_tcb = OSTaskDbgListPtr;
410  while (p_tcb != (OS_TCB *)0) {
411 #if OS_CFG_TASK_PROFILE_EN > 0u /* Compute execution time of each task */
412  usage = (OS_CPU_USAGE)(cycles_mult * p_tcb->CyclesTotalPrev / cycles_max);
413  if (usage > 10000u) {
414  usage = 10000u;
415  }
416  p_tcb->CPUUsage = usage;
417  if (p_tcb->CPUUsageMax < usage) { /* Detect peak CPU usage */
418  p_tcb->CPUUsageMax = usage;
419  }
420 #endif
421 
422 #if OS_CFG_STAT_TASK_STK_CHK_EN > 0u
423  OSTaskStkChk( p_tcb, /* Compute stack usage of active tasks only */
424  &p_tcb->StkFree,
425  &p_tcb->StkUsed,
426  &err);
427 #endif
428 
430  p_tcb = p_tcb->DbgNextPtr;
432  }
433 #endif
434 
435  if (OSStatResetFlag == DEF_TRUE) { /* Check if need to reset statistics */
436  OSStatResetFlag = DEF_FALSE;
437  OSStatReset(&err);
438  }
439 
440  ts_end = OS_TS_GET() - ts_start; /* Measure execution time of statistic task */
441  if (OSStatTaskTimeMax < ts_end) {
442  OSStatTaskTimeMax = ts_end;
443  }
444 
445  OSTimeDly(dly,
446  OS_OPT_TIME_DLY,
447  &err);
448  }
449 }
450 
451 /*$PAGE*/
452 /*
453 ************************************************************************************************************************
454 * INITIALIZE THE STATISTICS
455 *
456 * Description: This function is called by OSInit() to initialize the statistic task.
457 *
458 * Argument(s): p_err is a pointer to a variable that will contain an error code returned by this function.
459 *
460 * OS_ERR_STK_INVALID If you specified a NULL stack pointer during configuration
461 * OS_ERR_STK_SIZE_INVALID If you didn't specify a large enough stack.
462 * OS_ERR_PRIO_INVALID If you specified a priority for the statistic task equal to or
463 * lower (i.e. higher number) than the idle task.
464 * OS_ERR_xxx An error code returned by OSTaskCreate()
465 *
466 * Returns : none
467 *
468 * Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it.
469 ************************************************************************************************************************
470 */
471 
472 void OS_StatTaskInit (OS_ERR *p_err)
473 {
474 #ifdef OS_SAFETY_CRITICAL
475  if (p_err == (OS_ERR *)0) {
476  OS_SAFETY_CRITICAL_EXCEPTION();
477  return;
478  }
479 #endif
480 
481  OSStatTaskCtr = (OS_TICK)0;
482  OSStatTaskCtrRun = (OS_TICK)0;
483  OSStatTaskCtrMax = (OS_TICK)0;
484  OSStatTaskRdy = OS_STATE_NOT_RDY; /* Statistic task is not ready */
485  OSStatResetFlag = DEF_FALSE;
486 
487  /* ---------------- CREATE THE STAT TASK ---------------- */
488  if (OSCfg_StatTaskStkBasePtr == (CPU_STK *)0) {
489  *p_err = OS_ERR_STAT_STK_INVALID;
490  return;
491  }
492 
495  return;
496  }
497 
498  if (OSCfg_StatTaskPrio >= (OS_CFG_PRIO_MAX - 1u)) {
499  *p_err = OS_ERR_STAT_PRIO_INVALID;
500  return;
501  }
502 
503  OSTaskCreate((OS_TCB *)&OSStatTaskTCB,
504  (CPU_CHAR *)((void *)"uC/OS-III Stat Task"),
505  (OS_TASK_PTR )OS_StatTask,
506  (void *)0,
511  (OS_MSG_QTY )0,
512  (OS_TICK )0,
513  (void *)0,
515  (OS_ERR *)p_err);
516 }
517 
518 #endif