1ada1354e96d3241d0e3cb9ffe40c954bfcc0beb
1 /*
2 * pfp.c
3 *
4 * NOTE: Throughout this code we may refer to the "active queue" or list. That is actually
5 * a queue of Profile Points (PP's) where we are currently "inside". Only one of them
6 * can be really "active" since a CPU core can only execute one task at a time. In short,
7 * whenever we enter the Begin-End bracket we place that profile point on this queue.
8 * The most recent one that is or was executing should be at the tail of the queue.
9 *
10 * Created on: Apr 1, 2017
11 * Author: a0216546
12 */
14 /* DEBUG Flags */
15 #define PFP_DBG_HOOKS 0
17 #include "pfp.h"
19 #define PFP_MIN(a,b) (((a)>(b))?(b):(a)) /* Min/Max macros */
20 #define PFP_MAX(a,b) (((a)<(b))?(b):(a))
22 #include <xdc/runtime/Error.h>
23 #include <xdc/runtime/System.h>
25 #include <xdc/runtime/Timestamp.h> /* for benchmarking/profiling */
26 #define Timestamp_get Timestamp_get32 /* use 32-bit time stamps */
28 #include <ti/sysbios/BIOS.h>
29 #include <ti/sysbios/gates/GateAll.h> /* For Critical Sections */
31 #include <ti/sysbios/knl/Task.h>
32 #include <ti/sysbios/knl/Swi.h>
33 #include <ti/sysbios/hal/Hwi.h>
35 /* Global Variables */
36 pfpInst_t pfpInst; /* Define pfpInst globally. Only one can exist. */
38 /* Critical Section macros */
39 #define PFP_GATE_ENTER() GateAll_enter(pfpInst.ghandle);
40 #define PFP_GATE_LEAVE(key) GateAll_leave(pfpInst.ghandle,key)
42 int pfpTaskHookSetId; /* used for Task hooks */
43 int pfpSwiHookSetId; /* used for Swi hooks */
44 int pfpHwiHookSetId; /* used for Hwi hooks */
46 /*==================================================================================*/
47 /* PFP Functions that are used for profile point management and actual measurements */
48 /*==================================================================================*/
50 /*============================================================================*/
51 /* pfpCreate: initialize all profile point descriptors and instance structure */
52 /*============================================================================*/
54 void pfpCreate (void)
55 {
56 int k;
57 pfpDescriptor_t *pfp;
58 GateAll_Params params;
60 GateAll_Params_init(¶ms);
61 pfpInst.ghandle = GateAll_create(¶ms,NULL);
62 if (pfpInst.ghandle == NULL) {
63 BIOS_exit(1);
64 }
65 pfpInst.head = NULL;
66 pfpInst.tail = NULL;
67 pfpInst.overhead = 0;
68 pfpInst.depth = 0;
69 pfpInst.active_id = -1;
71 for (k = 0; k < PFP_PPCNT_MAX; k++) {
72 pfp = &pfpInst.pfpVector[k]; /* fetch current pp-descriptor */
74 pfp->exhandle = NULL;
75 pfp->id = -1;
76 pfp->scope = BIOS_ThreadType_Main;
77 pfp->enable = 0;
78 pfp->inside = 0;
79 pfp->active = 0;
80 pfp->latch = 0;
81 pfp->reset = 0;
82 pfp->c_total = 0;
83 pfp->n_count = 0;
84 pfp->c_partial = 0;
85 pfp->c_0 = 0;
86 pfp->c_min = (~0UL); /* very large integer */
87 pfp->c_max = 0;
88 pfp->alpha = 0.0;
89 pfp->c_average = 0.0;
90 pfp->next = NULL;
91 pfp->prev = NULL;
92 }
93 } /* pfpCreate */
95 /*===================================================================================*/
96 /* pfpSetAlpha: initialize exponential averaging constant for a single profile point */
97 /*
98 alpha must be in [0,1] range. When 0, exponantial averaging will not be calculated.
99 When 1, the average would equal to the most recent cycle measurement.
101 If a profile point is executed every T seconds and we want our time constant to be
102 tau, alpha should be T/tau. Clearly, tau > T for meaningful measurements.
103 */
104 /*===================================================================================*/
106 void pfpSetAlpha (int id, float alpha)
107 {
108 pfpDescriptor_t *pfp;
109 volatile IArg key;
110 BIOS_ThreadType scope = BIOS_getThreadType();
112 if (scope != BIOS_ThreadType_Main) {
113 key=PFP_GATE_ENTER();
114 }
115 pfp = &pfpInst.pfpVector[id]; /* fetch the PFP descriptor */
117 pfp->alpha = alpha; /* Store new value of exponantial averating constant */
119 if (scope != BIOS_ThreadType_Main) {
120 PFP_GATE_LEAVE(key);
121 }
123 } /* pfpSetAlpha */
125 /*============================================================================*/
126 /* pfpResetStats: Reset statistics for one profile point */
127 /*
128 * Preferably, this should be done from the lowest execution priority
129 * in order to ensure active list is empty. This should not be
130 * done in the middle of a profile point bracket.
131 */
132 /*============================================================================*/
134 void pfpResetStats (int id)
135 {
136 pfpDescriptor_t *pfp;
137 volatile IArg key;
138 BIOS_ThreadType scope = BIOS_getThreadType();
140 if (scope != BIOS_ThreadType_Main) {
141 key=PFP_GATE_ENTER();
142 }
143 pfp = &pfpInst.pfpVector[id]; /* fetch the PFP descriptor */
144 /* We cannot reset stats for currently running or latched profile point. We will do it
145 in next pfpBegin() making sure measurement is not latched. */
146 if (pfp->inside || pfp->latch) {
147 pfp->reset = 1; /* this PP will be reset in pfpBegin() when convenient */
148 if (scope != BIOS_ThreadType_Main) {
149 PFP_GATE_LEAVE(key);
150 }
151 return;
152 }
154 pfp->c_total = 0;
155 pfp->n_count = 0;
156 pfp->c_partial = 0;
157 pfp->c_0 = 0;
158 pfp->c_min = (~0UL); /* very large integer */
159 pfp->c_max = 0;
160 pfp->c_average = 0.0;
162 if (scope != BIOS_ThreadType_Main) {
163 PFP_GATE_LEAVE(key);
164 }
166 } /* pfpResetStats */
168 /*============================================================================*/
169 /* pfpGetStats: Return statistics for one profile point */
170 /*============================================================================*/
172 void pfpGetStats(int id, pfpStats_t *pStats)
173 {
174 pfpDescriptor_t *pfp;
175 volatile IArg key;
176 BIOS_ThreadType scope = BIOS_getThreadType();
178 if (scope != BIOS_ThreadType_Main) {
179 key=PFP_GATE_ENTER();
180 }
181 pfp = &pfpInst.pfpVector[id]; /* fetch the PFP descriptor */
183 pStats->c_total = pfp->c_total;
184 pStats->n_count = pfp->n_count;
185 pStats->c_min = pfp->c_min;
186 pStats->c_max = pfp->c_max;
187 pStats->alpha = pfp->alpha;
188 pStats->c_average = pfp->c_average;
190 if (scope != BIOS_ThreadType_Main) {
191 PFP_GATE_LEAVE(key);
192 }
193 } /* pfpGetStats */
195 /*============================================================================*/
196 /* pfpEnable: Enable one profile point */
197 /*============================================================================*/
199 void pfpEnable (int id)
200 {
201 pfpDescriptor_t *pfp;
202 volatile IArg key;
203 BIOS_ThreadType scope = BIOS_getThreadType();
205 if (scope != BIOS_ThreadType_Main) {
206 key=PFP_GATE_ENTER();
207 }
208 pfp = &pfpInst.pfpVector[id]; /* fetch the PFP descriptor */
210 pfp->enable = 1; /* Enable this profile point */
212 if (scope != BIOS_ThreadType_Main) {
213 PFP_GATE_LEAVE(key);
214 }
216 } /* pfpEnable */
218 /*============================================================================*/
219 /* pfpDisable: Disable one profile point
221 This function should be called from the lowest priority making sure that
222 the PP ID to be disabled is not currently being measured!
223 */
224 /*============================================================================*/
226 void pfpDisable (int id)
227 {
228 pfpDescriptor_t *pfp;
229 volatile IArg key;
230 BIOS_ThreadType scope = BIOS_getThreadType();
232 if (scope != BIOS_ThreadType_Main) {
233 key=PFP_GATE_ENTER();
234 }
235 pfp = &pfpInst.pfpVector[id]; /* fetch the PFP descriptor */
237 pfp->enable = 0; /* Disable this profile point */
239 /* WARNING: Should we check here to remove this PP from the active list in case we are disabling it? */
240 /* pfpEnd is not going to remove it if it was disabled!!! */
242 if (scope != BIOS_ThreadType_Main) {
243 PFP_GATE_LEAVE(key);
244 }
245 } /* pfpDisable */
247 /*============================================================================*/
248 /* pfpBegin: Begin profile point measurement */
249 /*============================================================================*/
251 void pfpBegin (int id, void *exhandle)
252 {
253 volatile uint_least32_t t1;
254 uint_least32_t dt;
255 pfpDescriptor_t *pfp;
256 volatile IArg key;
257 BIOS_ThreadType scope = BIOS_getThreadType();
259 if (scope != BIOS_ThreadType_Main) {
260 key=PFP_GATE_ENTER();
261 }
262 t1 = Timestamp_get(); /* fetch the current time stamp */
263 pfp = &pfpInst.pfpVector[id]; /* fetch the PFP descriptor */
265 if (!pfp->enable) {
266 if (scope != BIOS_ThreadType_Main) {
267 PFP_GATE_LEAVE(key);
268 }
269 return; /* do nothing if disabled */
270 }
272 /* First check to see if the current tail element is nesting this one */
273 if (pfpInst.tail != NULL) {
274 if (pfpInst.tail->exhandle == exhandle) { /* are we nested? */
275 /* We could check here to see if we have Begin followed by Begin for the same PP ID ! */
276 if (pfpInst.tail == pfp) {
277 /* INVALID USAGE OF THE API!!!!! */
278 /* Remove this from the list and DISABLE this ID */
279 pfpInst.depth--; /* reduce the depth! */
280 pfpInst.tail = pfp->prev;
281 if (pfpInst.tail != NULL) {
282 pfpInst.tail->next = NULL;
283 }
284 pfp->enable = 0; /* DISABLE it so it would not create these problems again! */
285 pfp->inside = 0;
286 pfp->active = 0;
287 pfp->latch = 0;
288 if (scope != BIOS_ThreadType_Main) {
289 PFP_GATE_LEAVE(key);
290 }
291 return;
292 }
293 pfpInst.tail->active = 0; /* mark as not-active */
294 dt = t1 - pfpInst.tail->c_0;
295 pfpInst.tail->c_partial += dt;
296 /* c_0 will have to be initialized before coming back! (see pfpEnd()) */
297 }
298 }
300 /* Now we can focus on the new profile point */
301 pfp->exhandle = exhandle; /* record execution object handle */
302 pfp->id = id; /* record your ID */
303 pfp->scope = scope; /* record the scope */
304 if (!pfp->latch) { /* if not latched */
305 pfp->c_partial = 0; /* initialize partial sum */
306 if (pfp->reset) { /* execute delayed reset if necessary */
307 pfp->reset = 0; /* no need to do it again */
308 pfp->c_total = 0;
309 pfp->n_count = 0;
310 pfp->c_min = (~0UL);
311 pfp->c_max = 0;
312 pfp->c_average = 0.0;
313 }
314 }
316 /* Link this PP to the end of active list */
317 pfp->prev = pfpInst.tail; /* Previous is the current last element */
318 pfp->next = NULL; /* nobody after this one */
319 if (pfpInst.head == NULL) {
320 pfpInst.head = pfp; /* now we are not empty */
321 pfpInst.tail = pfp;
322 }
323 else {
324 pfpInst.tail->next = pfp; /* current last now has a next one */
325 pfpInst.tail = pfp; /* move the last to point to this one */
326 }
327 pfpInst.depth++; /* record new depth of the list */
329 pfp->inside = 1; /* indicate that we entered this PP now */
330 pfp->active = 1; /* and we are about to start running through it */
331 pfpInst.active_id = id; /* record the currently active id */
333 /* Record time as late as possible to reduce overhead during measurement */
334 pfp->c_0 = Timestamp_get(); /* fetch the current time stamp */
336 if (scope != BIOS_ThreadType_Main) {
337 PFP_GATE_LEAVE(key);
338 }
339 } /* pfpBegin */
341 /*============================================================================*/
342 /* pfpEnd: Complete profile point measurement */
343 /*============================================================================*/
345 void pfpEnd (int id, int latch)
346 {
347 volatile uint_least32_t t1; /* completion time */
348 uint_least32_t dt; /* completion time and delta time */
349 uint_least32_t partial; /* partial sum */
350 float alpha; /* exponential averaging constant */
351 pfpDescriptor_t *pfp;
352 void *exhandle; /* Execution handle pointer which may be used */
353 volatile IArg key;
354 BIOS_ThreadType scope = BIOS_getThreadType();
356 if (scope != BIOS_ThreadType_Main) {
357 key=PFP_GATE_ENTER();
358 }
359 /* Record time ASAP to minimize measurement overhead */
360 t1 = Timestamp_get(); /* fetch the current time stamp */
361 pfp = &pfpInst.pfpVector[id]; /* fetch the PFP descriptor */
363 if (!pfp->enable || !pfp->inside) { /* if disabled or we had "end" before "begin" */
364 if (scope != BIOS_ThreadType_Main) {
365 PFP_GATE_LEAVE(key);
366 }
367 return; /* do nothing if disabled */
368 }
370 pfp->active = 0; /* We are going to stop running this measurement */
371 pfp->inside = 0; /* getting out after this */
373 /* This has to be done in case we are not nested. It will be fixed below in case of nesting */
374 pfpInst.active_id = -1; /* we were most likely the currently active PP, but not any more */
376 dt = t1 - pfp->c_0;
377 partial = pfp->c_partial + dt - pfpInst.overhead;
378 if (!latch) {
379 pfp->c_total += partial; /* complete this measurement */
380 pfp->n_count++; /* count it */
381 pfp->c_min = PFP_MIN(pfp->c_min, partial);
382 pfp->c_max = PFP_MAX(pfp->c_max, partial);
383 /* do the exponential averaging */
384 alpha = pfp->alpha;
385 if (alpha > 0.0) {
386 pfp->c_average += alpha*(partial - pfp->c_average);
387 }
388 }
389 else {
390 pfp->c_partial = partial; /* latch the partial sum */
391 }
392 pfp->latch = latch; /* record the latch flag */
394 /* Remove this PP from the active list */
395 if (pfpInst.head == pfp) { /* Was I at the head of the list? */
396 pfpInst.head = pfp->next;
397 if (pfp->next != NULL) {
398 pfp->next->prev = NULL; /* Next one (if any) is now at the head of the list! */
399 }
400 }
401 else {
402 pfp->prev->next = pfp->next; /* previous element should point forward to my next */
403 }
404 if (pfpInst.tail == pfp) { /* Was I at the tail of the list? */
405 pfpInst.tail = pfp->prev;
406 if (pfp->prev != NULL) {
407 pfp->prev->next = NULL; /* Previous one (if any) is now at the tail of the list! */
408 }
409 }
410 else {
411 pfp->next->prev = pfp->prev; /* next element should point back to my previous */
412 }
413 pfpInst.depth--; /* record new depth of the list */
415 /* Now check to see if the queue has a region nesting this one within the same task */
416 /* We cannot look only at the tail since the tail could be from different task and
417 * it may be currently blocked without ability to run! */
419 /* IMPORTANT: Here we will move the nesting region to the tail of the QUEUE
420 if it is not there already!!!!! */
422 exhandle = pfp->exhandle; /* Remember current execution handle */
423 pfp = pfpInst.tail; /* Start from the tail */
424 while (pfp != NULL) { /* Do this until we hit the head */
425 if (pfp->exhandle == exhandle) { /* were we nested with this one? */
426 pfp->active = 1; /* mark it as active */
427 pfpInst.active_id = pfp->id; /* fix the active id */
429 /* Take the new one we found and move it to the tail if it was not there */
430 /* Order is A -> PFP -> B */
431 if (pfpInst.tail != pfp) {
432 if (pfpInst.head != pfp) {
433 pfp->prev->next = pfp->next; /* A->next = B */
434 }
435 else {
436 pfpInst.head = pfp->next; /* New head since pfp is going to the tail */
437 }
438 pfp->next->prev = pfp->prev; /* B->prev = A (this is safe since PFP is not at the tail!) */
439 pfp->prev = pfpInst.tail; /* pfp->prev = TAIL */
440 pfp->next = NULL; /* pfp is now going to be at the tail! */
441 pfpInst.tail->next = pfp; /* TAIL->next = pfp (old tail points to pfp now) */
442 pfpInst.tail = pfp; /* new tail is pfp finally */
443 }
445 pfp->c_0 = Timestamp_get(); /* Record new time */
447 break; /* stop looking */
448 }
449 pfp = pfp->prev; /* move back through the queue */
450 }
452 if (scope != BIOS_ThreadType_Main) {
453 PFP_GATE_LEAVE(key);
454 }
455 } /* pfpEnd */
457 /*============================================================================*/
458 /* pfpCalibrate: Calibrate Begin-End pair.
460 This must run with all interrupts disabled. The best would be to run it
461 during boot or in main. Although one could argue more precise measurement
462 could be obtained if the GATE execution would be included.
463 Currently, that is not supported. This must be called after pfpCreate.
464 If the loopcnt is less than 16 calibration will not be done.
466 If reset is used, ID #0 will be reset once the overhead has been stored.
467 */
468 /*============================================================================*/
470 void pfpCalibrate(int loopcnt, int reset)
471 {
472 int k, enable;
473 float alpha;
474 BIOS_ThreadType scope = BIOS_getThreadType();
476 if (scope != BIOS_ThreadType_Main || loopcnt < 16) {
477 pfpInst.overhead = 0;
478 return; /* must be run before BIOS start */
479 }
481 /* Use PP #0 for this purpose */
482 enable = pfpInst.pfpVector[0].enable;
483 alpha = pfpInst.pfpVector[0].alpha;
485 pfpResetStats(0);
486 pfpInst.pfpVector[0].enable = 1;
487 pfpInst.pfpVector[0].alpha = 0.25;
488 for (k = 0; k < loopcnt; k++) {
489 pfpBegin(0,0);
490 pfpEnd(0,0);
491 }
492 pfpInst.pfpVector[0].alpha = alpha;
493 pfpInst.pfpVector[0].enable = enable;
495 /* Take the minimum and call it overhead */
496 pfpInst.overhead = pfpInst.pfpVector[0].c_min;
498 if (reset) {
499 pfpResetStats(0);
500 }
501 } /* pfpCalibrate */
503 /*==================================================================================*/
504 /* PFP Functions that are used for scheduling hooks within BIOS. */
505 /*==================================================================================*/
507 /*============================================================================*/
508 /* pfpHwiPause: Stop measurement during HWI. */
509 /*============================================================================*/
511 static void pfpHwiPause(void)
512 {
513 volatile uint_least32_t t1;
514 uint_least32_t dt;
515 pfpDescriptor_t *pfp;
517 /* Find if any measurement is in progress? */
518 t1 = Timestamp_get(); /* fetch the current time stamp */
519 if (pfpInst.active_id < 0) {
520 return;
521 }
522 pfp = pfpInst.tail; /* This should be the active one! */
524 pfpInst.active_id = -1; /* all measurement brackets are inactive now */
526 /* It would be nice to know if we need to accumulate dt here! (e.g. did we come from another HWI? */
527 pfp->active = 0; /* this may be redundant */
528 dt = t1 - pfp->c_0;
529 pfp->c_partial += dt;
530 /* pfp->c_0 will have to be initialized before coming back! */
532 } /* pfpHwiPause */
534 /*============================================================================*/
535 /* pfpHwiResume: Resume measurement after HWI. */
536 /*============================================================================*/
538 static inline void pfpHwiResume(Hwi_Handle hwi)
539 {
540 pfpDescriptor_t *pfp;
542 /* Find the last PP in the list */
543 if (pfpInst.depth < 1) {
544 return;
545 }
546 pfp = pfpInst.tail;
548 if (pfp->scope == BIOS_ThreadType_Task) { /* Check the task mode */
549 Task_Mode mode;
550 mode = Task_getMode(pfp->exhandle);
551 if (mode != Task_Mode_RUNNING) { /* If not running do not take c_0, do not make it active */
552 return;
553 }
554 }
556 pfp->active = 1; /* this should be done only if task is not blocked! */
557 pfpInst.active_id = pfp->id;
558 pfp->c_0 = Timestamp_get();
560 } /* pfpHwiResume */
562 /*============================================================================*/
563 /* pfpSwiPause: Stop measurement during SWI. */
564 /*============================================================================*/
566 static void pfpSwiPause(void)
567 {
568 volatile uint_least32_t t1;
569 uint_least32_t dt;
570 pfpDescriptor_t *pfp;
571 volatile IArg key;
573 key=Hwi_disable(); /* Disable all HWI's */
575 /* Find if any measurement is in progress? */
576 t1 = Timestamp_get(); /* fetch the current time stamp */
577 if (pfpInst.active_id < 0) {
578 Hwi_restore(key);
579 return;
580 }
581 pfp = pfpInst.tail; /* This should be the active one! */
583 pfpInst.active_id = -1; /* all measurement brackets are inactive now */
585 /* It would be nice to know if we have to accumulate dt here. (e.g. did we come from Hwi? */
586 /* If we always come from HWI when entering SWI, we should not accumulate */
587 pfp->active = 0; /* this may be redundant */
588 dt = t1 - pfp->c_0;
589 pfp->c_partial += dt;
590 /* pfp->c_0 will have to be initialized before coming back! */
592 Hwi_restore(key); /* restore the HWI's */
594 } /* pfpSwiPause */
596 /*============================================================================*/
597 /* pfpSwiResume: Resume measurement after SWI. */
598 /*============================================================================*/
600 static inline void pfpSwiResume(Swi_Handle swi)
601 {
602 pfpDescriptor_t *pfp;
603 volatile IArg key;
605 key=Hwi_disable(); /* Disable all HWI's */
607 /* Find the last PP in the list */
608 if (pfpInst.depth < 1) {
609 Hwi_restore(key);
610 return;
611 }
612 pfp = pfpInst.tail;
614 if (pfp->scope == BIOS_ThreadType_Task) { /* Check the task mode */
615 Task_Mode mode;
616 mode = Task_getMode(pfp->exhandle);
617 if (mode != Task_Mode_RUNNING) { /* If not running do not take c_0, do not make it active */
618 Hwi_restore(key);
619 return;
620 }
621 }
623 pfp->active = 1;
624 pfpInst.active_id = pfp->id;
625 pfp->c_0 = Timestamp_get();
627 Hwi_restore(key); /* restore the HWI's */
629 } /* pfpSwiResume */
631 /*============================================================================*/
632 /* pfpTaskRegister: Task registration hook. Stores hook set ID. */
633 /*============================================================================*/
635 void pfpTaskRegister(int hookSetId)
636 {
637 #if PFP_DBG_HOOKS
638 System_printf("T-Register: id=%d\n", hookSetId);
639 pfpTaskHookSetId = hookSetId;
640 #endif
641 } /* pfpTaskRegister */
643 /*============================================================================*/
644 /* pfpTaskCreate: Task creation hook. Sets the hook set context. */
645 /*============================================================================*/
647 void pfpTaskCreate(Task_Handle task, Error_Block *eb)
648 {
649 #if PFP_DBG_HOOKS
650 char *name;
651 void *pEnv;
653 name = Task_Handle_name(task);
654 pEnv = Task_getHookContext(task, pfpTaskHookSetId); /* We have set the hook set ID during registration */
656 System_printf("T-Create: name='%s', pEnv=0x%x\n", name, pEnv);
657 Task_setHookContext(task, pfpTaskHookSetId, (void*)0xdead);
658 #endif
659 } /* pfpTaskCreate */
661 /*============================================================================*/
662 /* pfpTaskReady: Task ready hook. Prepares task for run. */
663 /*============================================================================*/
665 void pfpTaskReady(Task_Handle task)
666 {
667 #if PFP_DBG_HOOKS
668 char *name;
669 void *pEnv;
671 name = Task_Handle_name(task);
672 pEnv = Task_getHookContext(task, pfpTaskHookSetId); /* We have set the hook set ID during registration */
674 System_printf("T-Ready: name='%s', pEnv=0x%x\n", name, pEnv);
675 Task_setHookContext(task, pfpTaskHookSetId, (void*)0xc0de);
676 #endif
677 } /* pfpTaskReady */
679 /*============================================================================*/
680 /* pfpTaskSwitch: Task switch hook. Facilitates task switch operation. */
681 /*============================================================================*/
683 void pfpTaskSwitch(Task_Handle prev, Task_Handle next)
684 {
685 #if PFP_DBG_HOOKS
686 char *prevName;
687 char *nextName;
688 void *pPrevEnv;
689 void *pNextEnv;
690 #endif
692 volatile uint_least32_t t1;
693 uint_least32_t dt;
694 int prev_id, next_id;
696 volatile IArg key;
697 pfpDescriptor_t *pfp;
699 /* Using GATE has more overhead, but using just HWI disabling may not be safe if SWI's can
700 be posted by the tasks. However, once inside the task hook, no other task can run until
701 we're done and since we are not in SWI we are actually safe to use HWI disabling only! */
703 key=Hwi_disable(); /* Enter Critical Section */
704 t1 = Timestamp_get();
706 #if PFP_DBG_HOOKS
707 if (prev == NULL) {
708 System_printf("T-Switch: ignore 1st prev Task\n");
709 }
710 else {
711 prevName = Task_Handle_name(prev);
712 pPrevEnv = Task_getHookContext(prev, pfpTaskHookSetId);
714 System_printf("T-Switch: prev name='%s', pPrevEnv=0x%x\n", prevName, pPrevEnv);
715 Task_setHookContext(prev, pfpTaskHookSetId, (void*)0xcafec0de);
716 }
718 nextName = Task_Handle_name(next);
719 pNextEnv = Task_getHookContext(next, pfpTaskHookSetId);
721 System_printf("T-Switch: next name='%s', pNextEnv=0x%x\n", nextName, pNextEnv);
722 Task_setHookContext(next, pfpTaskHookSetId, (void*)0xc001c0de);
723 #endif
725 if (pfpInst.depth < 1) {
726 Hwi_restore(key); /* Exit critical section and return */
727 return;
728 }
730 /* There are some active measurement PP's but we do not know where yet
731 It may not be in prev nor next task so we have to do some investigation */
733 /* Go through the list and find prev_id and next_id if they are inside any PP */
734 prev_id = next_id = -1;
735 pfp = pfpInst.tail; /* This should be the one with the highest priority */
736 while (pfp != NULL && (prev_id < 0 || next_id < 0)) {
737 if (prev_id < 0 && pfp->exhandle == prev) { /* stop looking after you find the first match */
738 prev_id = pfp->id;
739 }
740 if (next_id < 0 && pfp->exhandle == next) { /* stop looking after you find the first match */
741 next_id = pfp->id;
742 }
743 pfp = pfp->prev;
744 }
746 /* Check to see if any of the two tasks are in the middle of a measurement */
747 if (prev_id < 0 && next_id < 0) {
748 Hwi_restore(key);
749 return;
751 }
753 if (prev_id >= 0) { /* Previous task may have been measuring and it has to be stopped */
754 pfp = &pfpInst.pfpVector[prev_id];
756 pfpInst.active_id = -1; /* all measurement brackets are inactive now */
758 if (pfp->active) { /* This if is required in case we went through HWI/SWI */
759 pfp->active = 0;
760 dt = t1 - pfp->c_0;
761 pfp->c_partial += dt;
762 }
763 }
764 if (next_id >= 0) { /* Next task was in the middle of measurement */
765 pfp = &pfpInst.pfpVector[next_id];
767 pfp->active = 1; /* We are about to continue measurement */
768 pfpInst.active_id = next_id;
770 /* Take the new one and move it to the tail if it was not there */
771 /* Order is A -> PFP -> B where A could be Head and B could be NULL */
772 if (pfpInst.tail != pfp) {
773 if (pfpInst.head != pfp) {
774 pfp->prev->next = pfp->next; /* A->next = B */
775 }
776 else {
777 pfpInst.head = pfp->next; /* New head since pfp is going to the tail */
778 }
779 pfp->next->prev = pfp->prev; /* B->prev = A (this could be NULL if pfp was on the Head) */
780 pfp->prev = pfpInst.tail; /* pfp->prev = TAIL */
781 pfp->next = NULL; /* pfp is now going to be at the tail! */
782 pfpInst.tail->next = pfp; /* TAIL->next = pfp (old tail points to pfp now) */
783 pfpInst.tail = pfp; /* new tail is pfp finally */
784 }
785 pfp->c_0 = Timestamp_get(); /* Record time */
786 }
787 Hwi_restore(key);
788 } /* pfpTaskSwitch */
790 /*============================================================================*/
791 /* pfpSwiRegister: Swi registration hook. Stores hook set ID. */
792 /*============================================================================*/
794 void pfpSwiRegister(int hookSetId)
795 {
796 #if PFP_DBG_HOOKS
797 System_printf("S-Register: id=%d\n", hookSetId);
798 pfpSwiHookSetId = hookSetId;
799 #endif
800 } /* pfpSwiRegister */
802 /*============================================================================*/
803 /* pfpSwiCreate: Swi creation hook. Sets the hook set context. */
804 /*============================================================================*/
806 void pfpSwiCreate(Swi_Handle swi, Error_Block *eb)
807 {
808 #if PFP_DBG_HOOKS
809 char *name;
810 void *pEnv;
812 name = Swi_Handle_name(swi);
813 pEnv = Swi_getHookContext(swi, pfpSwiHookSetId); /* We have set the hook set ID during registration */
815 System_printf("S-Create: name='%s', pEnv=0x%x, time=%d\n", name, pEnv, Timestamp_get());
816 Swi_setHookContext(swi, pfpSwiHookSetId, (void*)0xdead1);
817 #endif
818 } /* pfpSwiCreate */
820 /*============================================================================*/
821 /* pfpSwiReady: Swi ready hook. Prepares Swi for run. */
822 /*============================================================================*/
824 void pfpSwiReady(Swi_Handle swi)
825 {
826 #if PFP_DBG_HOOKS
827 char *name;
828 void *pEnv;
830 name = Swi_Handle_name(swi);
831 pEnv = Swi_getHookContext(swi, pfpSwiHookSetId); /* We have set the hook set ID during registration */
833 System_printf("S-Ready: name='%s', pEnv=0x%x, time=%d\n", name, pEnv, Timestamp_get());
834 Swi_setHookContext(swi, pfpSwiHookSetId, (void*)0xbeef1);
835 #endif
836 } /* pfpSwiReady */
838 /*============================================================================*/
839 /* pfpSwiBegin: Swi begin hook. Start Swi. */
840 /*============================================================================*/
842 void pfpSwiBegin(Swi_Handle swi)
843 {
844 #if PFP_DBG_HOOKS
845 char *name;
846 void *pEnv;
847 #endif
849 pfpSwiPause();
851 #if PFP_DBG_HOOKS
852 name = Swi_Handle_name(swi);
853 pEnv = Swi_getHookContext(swi, pfpSwiHookSetId); /* We have set the hook set ID during registration */
855 System_printf("S-Begin: name='%s', pEnv=0x%x, time=%d\n", name, pEnv, Timestamp_get());
856 Swi_setHookContext(swi, pfpSwiHookSetId, (void*)0xfeeb1);
857 #endif
858 } /* pfpSwiBegin */
860 /*============================================================================*/
861 /* pfpSwiEnd: Swi end hook. End Swi. */
862 /*============================================================================*/
864 void pfpSwiEnd(Swi_Handle swi)
865 {
866 #if PFP_DBG_HOOKS
867 char *name;
868 void *pEnv;
870 name = Swi_Handle_name(swi);
871 pEnv = Swi_getHookContext(swi, pfpSwiHookSetId); /* We have set the hook set ID during registration */
873 System_printf("S-End: name='%s', pEnv=0x%x, time=%d\n", name, pEnv, Timestamp_get());
874 Swi_setHookContext(swi, pfpSwiHookSetId, (void*)0xc0de1);
875 #endif
877 pfpSwiResume(swi);
879 } /* pfpSwiEnd */
881 /*============================================================================*/
882 /* pfpHwiRegister: Hwi registration hook. Stores hook set ID. */
883 /*============================================================================*/
885 void pfpHwiRegister(int hookSetId)
886 {
887 #if PFP_DBG_HOOKS
888 System_printf("H-Register: id=%d\n", hookSetId);
889 pfpHwiHookSetId = hookSetId;
890 #endif
891 } /* pfpHwiRegister */
893 /*============================================================================*/
894 /* pfpHwiCreate: Hwi creation hook. Sets the hook set context. */
895 /*============================================================================*/
897 void pfpHwiCreate(Hwi_Handle hwi, Error_Block *eb)
898 {
899 #if PFP_DBG_HOOKS
900 char *name;
901 void *pEnv;
903 name = Hwi_Handle_name(hwi);
904 pEnv = Hwi_getHookContext(hwi, pfpHwiHookSetId); /* We have set the hook set ID during registration */
906 System_printf("H-Create: name='%s', pEnv=0x%x, time=%d\n", name, pEnv, Timestamp_get());
907 Hwi_setHookContext(hwi, pfpHwiHookSetId, (void*)0xdead2);
908 #endif
909 } /* pfpHwiCreate */
911 /*============================================================================*/
912 /* pfpHwiBegin: Hwi begin hook. Start Hwi. */
913 /*============================================================================*/
915 void pfpHwiBegin(Hwi_Handle hwi)
916 {
917 #if PFP_DBG_HOOKS
918 char *name;
919 void *pEnv;
920 #endif
922 pfpHwiPause();
924 #if PFP_DBG_HOOKS
925 name = Hwi_Handle_name(hwi);
926 pEnv = Hwi_getHookContext(hwi, pfpHwiHookSetId); /* We have set the hook set ID during registration */
928 System_printf("H-Begin: name='%s', pEnv=0x%x, time=%d\n", name, pEnv, Timestamp_get());
929 Hwi_setHookContext(hwi, pfpHwiHookSetId, (void*)0xfeeb2);
930 #endif
931 } /* pfpHwiBegin */
933 /*============================================================================*/
934 /* pfpHwiEnd: Hwi end hook. End Hwi. */
935 /*============================================================================*/
937 void pfpHwiEnd(Hwi_Handle hwi)
938 {
939 #if PFP_DBG_HOOKS
940 char *name;
941 void *pEnv;
943 name = Hwi_Handle_name(hwi);
944 pEnv = Hwi_getHookContext(hwi, pfpHwiHookSetId); /* We have set the hook set ID during registration */
946 System_printf("H-End: name='%s', pEnv=0x%x, time=%d\n", name, pEnv, Timestamp_get());
947 Hwi_setHookContext(hwi, pfpHwiHookSetId, (void*)0xc0de2);
948 #endif
950 pfpHwiResume(hwi);
952 } /* pfpHwiEnd */
954 /* nothing past this point */