]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - processor-sdk/performance-audio-sr.git/blob - pasdk/common/pfp/pfp.c
1ada1354e96d3241d0e3cb9ffe40c954bfcc0beb
[processor-sdk/performance-audio-sr.git] / pasdk / common / pfp / pfp.c
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(&params);
61   pfpInst.ghandle = GateAll_create(&params,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.
100  
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)
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)
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)
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)
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
220  
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)
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)
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)
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.
459  
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.
465  
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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 */