Add profiler to measure based on IVA-HD processing time
[ivimm/ipumm.git] / src / ti / utils / profile.c
1 /*
2  * Copyright (c) 2010, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 /*
33 *   @file  profile.c
34 *   This file contains kpi psi instrumentation code for cpu load as well
35 *   as tracing codec + BIOS Events
36 *
37 *   @path src/ti/utils
38 *
39 *  @rev 1.0
40 */
42 /* PSI_KPI profiler */
43 #include "profile.h"
45 #include <string.h>
46 #include <xdc/std.h>
47 #include <xdc/runtime/Error.h>
48 #include <xdc/runtime/System.h>
50 #include <ti/sysbios/BIOS.h>
51 #include <ti/sysbios/knl/Task.h>
52 #include <ti/sysbios/hal/Hwi.h>
53 #include <ti/sysbios/knl/Swi.h>
54 #include <xdc/runtime/Types.h>
55 #include <xdc/runtime/Timestamp.h>
56 #ifdef  BUILD_FOR_SMP
57 #include <ti/sysbios/hal/Core.h>
58 #endif //BUILD_FOR_SMP
59 #include <ti/sysbios/family/arm/ducati/TimestampProvider.h>
60 #include <ti/pm/IpcPower.h>
61 #include <ti/ipc/remoteproc/Resource.h>
63 #define REG_32K (0x4AE04030) //J6 and OMAP5
64 #define TRACEGRP 0
65 #define MAX_STRINGNAME_SIZE 255
67 /* private function prototypes */
68 void kpi_IVA_profiler_init  (void);
69 void kpi_CPU_profiler_init  (void);
70 void kpi_IVA_profiler_print (void);
71 void kpi_CPU_profiler_print (void);
72 void psi_kpi_task_test(Task_Handle prev, Task_Handle next);
75 /***************************************************************
76  * psi_tsk_info
77  * -------------------------------------------------------------
78  * Structure maintaining task data for Duacti CPU load
79  *
80  ***************************************************************/
81 #define KPI_CONTEXT_TASK  0
82 #define KPI_CONTEXT_SWI   1
83 #define KPI_CONTEXT_HWI   2
85 typedef struct {
86     void         *handle;     /* Pointer to task handle, used to identify task */
87     char          name[50];   /* Task name */
88     unsigned long total_time; /* Total time spent in the task context */
89     unsigned long nb_switch;  /* Number of times the context get activated */
90 } psi_context_info;
93 /***************************************************************
94  * psi_bios_kpi
95  * -------------------------------------------------------------
96  * Structure maintaining data for Ducati CPU load
97  *
98  ***************************************************************/
99 #define CTX_DIRECT_NUM   256
100 #define KPI_MAX_NB_TASKS 64
101 #define KPI_MAX_NB_SWI   16
102 #define KPI_MAX_NB_HWI   16
103 #define MAX_NB_IT 32
105 typedef struct {
106     unsigned long prev_t32;                       /* Store T32K value of previous task switch */
107     unsigned long total_time;                     /* Total processing time */
108     unsigned long kpi_time;                       /* Total instrumentation processing time */
109     unsigned long kpi_count;                      /* Number of time instrumentation run */
110     unsigned long nb_switch;                      /* Number of context switches */
112     psi_context_info tasks[KPI_MAX_NB_TASKS];     /* Tasks info DB */
113     unsigned long    nb_tasks;                    /* Number of tasks in task info */
114     psi_context_info hwi[KPI_MAX_NB_SWI];         /* HWI info DB */
115     unsigned long    nb_hwi;                      /* Number of HWI in HWI info */
116     psi_context_info swi[KPI_MAX_NB_HWI];         /* SWI info DB */
117     unsigned long    nb_swi;                      /* Number of SWI in SWI info */
119     psi_context_info *context_cache[CTX_DIRECT_NUM]; /* pointers to tasks info DB */
121     void   *context_stack[MAX_NB_IT];             /* to keep handles because of swi hwi */
122     void * *pt_context_stack;                     /* stack pointer */
124     unsigned long *ptr_idle_total;                /* to access to idle task total directly */
125     unsigned long  idle_prev;                     /* total ticks of idle task previously */
126     unsigned long  idle_time_prev;                /* time of idle_prev measure */
128     unsigned long trace_time;                     /* time spent tracing */
129 } psi_bios_kpi;
132 /***************************************************************
133  * ivahd_kpi
134  * -------------------------------------------------------------
135  * Structure maintaining data for IVA-HD load and fps
136  *
137  ***************************************************************/
138 typedef struct {
139     unsigned long ivahd_t_tot;       /* IVA-HD tot processing time per frame */
140     unsigned long ivahd_t_max;       /* IVA-HD max processing time per frame */
141     unsigned long ivahd_t_min;       /* IVA-HD min processing time per frame */
142     unsigned long ivahd_t_max_frame;
143     unsigned long ivahd_t_min_frame;
144     unsigned long ivahd_MHz;
145     unsigned long ivahd_MHzTime;
147     unsigned long nb_frames;     /* Number of frames      */
149     unsigned long before_time;       /* T32K before codec execution */
150     unsigned long after_time;        /* T32K after codec execution */
152     unsigned long t32k_start;        /* T32K value at the beginning of video decode */
153     unsigned long t32k_end;          /* T32K value at the end of video decode */
154     unsigned long t32k_mpu_time;     /* T32K value at MPU side */
155 } psi_iva_kpi;
158 /***************************************************************
159  * Globals
160  ***************************************************************/
161 unsigned long    kpi_control = 0;    /* instrumentation control (set with omapconf) */
162 unsigned long    kpi_status  = 0;    /* instrumentation status variables */
164 psi_iva_kpi     iva_kpi;             /* IVA data base */
165 psi_bios_kpi    bios_kpi[2];         /* CPU data base (2 cores) */
168 /***************************************************************
169  * Functions
170  ***************************************************************/
172 #ifndef BUILD_FOR_SMP
173 /***************************************************************
174  * Core_getId
175  * -------------------------------------------------------------
176  * Temporary function to remove with SMP BIOS
177  *
178  * @params: none
179  *
180  * @return: 1 to force CoreId to 1
181  *
182  ***************************************************************/
183 unsigned long Core_getId(void)
185     return (1);
188 #else
190 #endif //BUILD_FOR_SMP
192 /***************************************************************
193  * get_32k
194  * -------------------------------------------------------------
195  * Function used to get 32k timer value
196  *
197  * @params: none
198  *
199  * @return: T32k value
200  *
201  ***************************************************************/
202 unsigned long get_32k(void)
204     Uint32 va;
205     volatile Uint32 pa = REG_32K;
206     if(!Resource_physToVirt(pa, &va)) {
207         //DEBUG("pa = 0x%x, va = 0x%x\n", pa, va);
208         return *( (volatile Uint32*)va);
209     }
210     else {
211         System_printf("Unable to read the timer value\n");
212         return 0;
213     }
216 /***************************************************************
217  * get_time
218  * -------------------------------------------------------------
219  * Left here for test
220  *
221  * @params: none
222  *
223  * @return: CTM timer value / 4096 (~100KHz)
224  *          or 32K value (slower to read)
225  *
226  ***************************************************************/
227 inline unsigned long get_time(void)
229     return (get_32k());
232 /***************************************************************
233  * get_time_core
234  * -------------------------------------------------------------
235  * Left here for test
236  *
237  * @params: int core
238  *
239  * @return: CTM timer value / 4096 (~100KHz)
240  *          or 32K value (slower to read)
241  *
242  * This function is equivalent to get_time().
243  * it can be called when interrupts have been masked
244  * and when current core Id is known already (therefore faster)
245  ***************************************************************/
246 inline unsigned long get_time_core(int core)
248     return (get_32k());
251 /***************************************************************
252  * set_WKUPAON
253  * -------------------------------------------------------------
254  * Function used to get fast access to the 32k timer value
255  *
256  * @params: int force_restore (1 or 0)
257  *
258  * @return: none
259  *
260  * This function prevents sleep mode to the L4 WKUPAON_CM
261  * register, to avoid large stalls when reading the 32k timer
262  ***************************************************************/
263 /* Commenting set_WKUPAON() to make sure it isn't used. Need to
264  * investigate if this function is still needed. This code is
265  * attempting to directly access a physical address when only
266  * virtual addresses should be accessed. This function is not
267  * currently called. If we don't need this function, can we
268  * remove it?
269  */
270 #if 0
271 extern void *MEMUTILS_getPhysicalAddr(Ptr vaddr);
272 void set_WKUPAON(int force_restore)
274     static unsigned long    clktrctrl_01=0;
275     unsigned long  reg = *((volatile Uint32 *)
276                           MEMUTILS_getPhysicalAddr((Ptr)0xAAE07800));
278     /* Force nosleep mode or restore original configuration */
279     if( force_restore == 1 ) {
280         clktrctrl_01 = reg & 0x3;     /* save clktrctrl */
281         reg &= 0xfffffffc;
282         //reg |= 0x2;                     /* force SW_WAKEUP */
283         reg |= 0;                     /* force NO_SLEEP */
284     } else {
285         reg &= 0xfffffffc;
286         reg |= clktrctrl_01;          /* restore bits 01 */
287         clktrctrl_01 = 0;             /* restore done */
288     }
289     *(Uint32 *)0xAAE07800 = reg;
291 #endif
293 /***************************************************************
294  * PSI_TracePrintf
295  * -------------------------------------------------------------
296  * Function used to get 32k timer value
297  *
298  * @params: TIMM_OSAL_TRACEGRP eTraceGrp, TIMM_OSAL_CHAR *pcFormat, ...
299  *
300  * @return: none
301  *
302  ***************************************************************/
303 void PSI_TracePrintf(Uint32 eTraceGrp, char *pcFormat, ...)
305     //  static TIMM_OSAL_PTR MyMutex = NULL;
306     unsigned long    tstart = get_time();
307     unsigned long    key = Task_disable();
308     unsigned long    CoreId = Core_getId();
310     va_list    varArgs;
312     va_start(varArgs, pcFormat);
313     System_vprintf(pcFormat, varArgs);
314     va_end(varArgs);
316     Task_restore(key);
318     /* count overhead due to tracing when running (phase 1)*/
319     if( kpi_status & KPI_INST_RUN ) {
320         bios_kpi[CoreId].trace_time += get_time() - tstart;
321     }
325 /***************************************************************
326  * kpi_instInit
327  * -------------------------------------------------------------
328  * Function used to do the aquisition of the instrumentation
329  * setting. Then initialising the DBs and variables
330  *
331  * @params: none
332  *
333  * @return: none
334  *
335  ***************************************************************/
336 void kpi_instInit(void)
338     /* don't change setup when already active */
339     if( kpi_status & KPI_INST_RUN ) {
340         return;
341     }
343     /* read control from the memory */
345     /* Note:
346      * kpi_control |= KPI_END_SUMMARY;     bit0 : Activate the IVA and CPU load measure and print summary
347      * kpi_control |= KPI_IVA_DETAILS;     bit1 : Activate the IVA trace
348      * kpi_control |= KPI_COMP_DETAILS;    bit2 : Activate the COMP trace
349      * kpi_control |= KPI_CPU_DETAILS;     bit3 : Activate the CPU Idle trace
350      */
352     /* reset kpi_status */
353     kpi_status = 0;
355     /* nothing to do if no instrumentation required */
356     if( !kpi_control ) {
357         return;
358     }
360     /* force clktrctrl to no sleep mode (fast 32k access) */
361     //set_WKUPAON( 1 );
362 #ifdef  USE_CTM_TIMER
363     IpcPower_wakeLock();
364 #endif /*USE_CTM_TIMER*/
366     /* IVA load setup */
367     if( kpi_control & (KPI_END_SUMMARY | KPI_IVA_DETAILS)) {
368         /* Initialize the IVA data base */
369         kpi_IVA_profiler_init();
370         kpi_status |= KPI_IVA_LOAD;
371         if( kpi_control & KPI_IVA_DETAILS ) {
372             kpi_status |= KPI_IVA_TRACE;
373         }
374     }
376     /* CPU load setup */
377     if( kpi_control & (KPI_END_SUMMARY | KPI_CPU_DETAILS)) {
378         /* Initialize the CPU data base */
379         kpi_CPU_profiler_init();
380         kpi_status |= KPI_CPU_LOAD;
381         if( kpi_control & KPI_CPU_DETAILS ) {
382             kpi_status |= KPI_CPU_TRACE;
383         }
384     }
386     /* COMP trace setup */
387     if( kpi_control & KPI_COMP_DETAILS ) {
388         kpi_status |= KPI_COMP_TRACE;
389     }
391     /* Mark as running */
392     kpi_status |= KPI_INST_RUN;
396 /***************************************************************
397  * kpi_instDeinit
398  * -------------------------------------------------------------
399  * Function used stop the instrumentation
400  * Then initialising the summary if required
401  *
402  * @params: none
403  *
404  * @return: none
405  *
406  ***************************************************************/
407 void kpi_instDeinit(void)
409     unsigned long    cpu_summary=0;
410     unsigned long    iva_summary=0;
412     /* noting to do when not running */
413     if( !(kpi_status & KPI_INST_RUN)) {
414         return;
415     }
417     if( kpi_control & KPI_END_SUMMARY ) {
418         cpu_summary = kpi_status & KPI_CPU_LOAD;
419         iva_summary = kpi_status & KPI_IVA_LOAD;
420     }
422     /* now stop everything since measure is completed */
423     kpi_status = 0;
425     /* Print the summarys */
426     PSI_TracePrintf(TRACEGRP, "\n<KPI> Profiler Deinit %-8lu\n", get_32k());
427     if( iva_summary ) {
428         kpi_IVA_profiler_print();
429     }
430     if( cpu_summary ) {
431         kpi_CPU_profiler_print();
432     }
434     /* restore clktrctrl register */
435     //set_WKUPAON( 0 );
436 #ifdef  USE_CTM_TIMER
437     IpcPower_wakeUnlock();
438 #endif /*USE_CTM_TIMER*/
442 /***************************/
443 /* IVA fps and IVA-HD load */
444 /***************************/
446 #ifdef  CPU_LOAD_DETAILS
447 /***************************************************************
448  * psi_cpu_load_details
449  * -------------------------------------------------------------
450  * Function to be called once a frame
451  *
452  * @params: none
453  *
454  * @return: none
455  *
456  ***************************************************************/
457 void psi_cpu_load_details(void)
459     unsigned long    time_curr = get_time();
460     unsigned long    CoreId, time_delta, idle_delta, idle;
461     psi_bios_kpi    *core_kpi;
462     char             trace[2][50];
464     /* calculate delta_time and delta_idle */
465     for( CoreId = 0; CoreId < 2; CoreId++ ) {
466         core_kpi = &bios_kpi[CoreId];
467         System_sprintf(trace[CoreId], "");
468         idle_delta= *(core_kpi->ptr_idle_total) - core_kpi->idle_prev;
469         time_delta = time_curr - core_kpi->idle_time_prev;
470         /* calculate idle value only if it was updated (idle task switch happend at least once!) */
471         if( idle_delta ) {
472             core_kpi->idle_time_prev = time_curr;
473             core_kpi->idle_prev = *(core_kpi->ptr_idle_total);
474             if( time_delta ) {
475                 /* calculate Idle %time */
476                 idle = ((idle_delta * 100) + time_delta / 2) / time_delta;
477                 System_sprintf(trace[CoreId], "Idle.%lu : %lu%%", CoreId, idle);
478             }
479         }
480     }
482     PSI_TracePrintf(TRACEGRP, "%s   %s\n", trace[0], trace[1]);
485 #endif //CPU_LOAD_DETAILS
488 /***************************************************************
489  * kpi_IVA_profiler_init
490  * -------------------------------------------------------------
491  * Function to be called at start of processing.
492  *
493  * @params: none
494  *
495  * @return: none
496  *
497  ***************************************************************/
498 void kpi_IVA_profiler_init(void)
501     PSI_TracePrintf(TRACEGRP, "<KPI> IVA Profiler Init %-8lu\n", get_32k());
503     iva_kpi.ivahd_t_tot       = 0;       /* IVA-HD tot processing time per frame */
504     iva_kpi.ivahd_t_max       = 0;       /* IVA-HD max processing time per frame */
505     iva_kpi.ivahd_t_min       =~0;       /* IVA-HD min processing time per frame */
506     iva_kpi.ivahd_t_max_frame = 0;
507     iva_kpi.ivahd_t_min_frame = 0;
508     iva_kpi.ivahd_MHzTime     = 0;
510     iva_kpi.nb_frames     = 0;       /* Number of frames      */
512     iva_kpi.before_time       = 0;
513     iva_kpi.after_time        = 0;
515     iva_kpi.t32k_start        = 0;
516     iva_kpi.t32k_end          = 0;
517     iva_kpi.t32k_mpu_time     = 0;
521 /***************************************************************
522  * kpi_before_codec
523  * -------------------------------------------------------------
524  * Function to be called before codec execution.
525  *
526  * @params: none
527  *
528  * @return: none
529  *
530  ***************************************************************/
531 void kpi_before_codec(void)
533     unsigned long    start, prev, delta;
535 #ifndef COMP_ENABLE_DUCATI_LOAD
536     /* Started 1st time */
537     if( !(kpi_status & KPI_INST_RUN)) {
538         kpi_instInit();
539     }
540 #endif //COMP_ENABLE_DUCATI_LOAD
542     if( kpi_status & KPI_IVA_LOAD ) {
543         /* read the 32k timer */
544         start = get_32k();
546         prev = iva_kpi.before_time;
547         iva_kpi.before_time = start;
549         /* record very 1st time codec is used */
550         if( !iva_kpi.t32k_start ) {
551             iva_kpi.t32k_start = iva_kpi.before_time;
552             iva_kpi.t32k_mpu_time = 0;  /* before the 1st codec call */
553         } else {
554             /* calculate the time from after codec done (iva_kpi.after_time) until now (iva_kpi.before_time) which is the time on MPU side */
555             iva_kpi.t32k_mpu_time += iva_kpi.before_time - iva_kpi.after_time;
556         }
558         /* calculate delta frame time in ticks */
559         delta = start - prev;
560         if( !iva_kpi.nb_frames ) {
561             delta = 0;
562         }
564 #ifdef  IVA_DETAILS
565         if( kpi_status & KPI_IVA_TRACE ) {
566             PSI_TracePrintf(TRACEGRP, "BEG %-7s %-4u %-8lu %d\n",
567                             "IVA", iva_kpi.nb_frames + 1, start, (delta * 100000) / 32768);
568         }
569 #endif /*IVA_DETAILS*/
571     }
573 #ifdef  CPU_LOAD_DETAILS
574     if( kpi_status & KPI_CPU_TRACE ) {
575         kpi_status |= KPI_IVA_USED; /* mark IVA actually used */
576         psi_cpu_load_details();
577     }
578 #endif //CPU_LOAD_DETAILS
582 /***************************************************************
583  * kpi_after_codec
584  * -------------------------------------------------------------
585  * Function to be called at the end of processing.
586  *
587  * @params: none
588  *
589  * @return: none
590  *
591  ***************************************************************/
592 void kpi_after_codec(void)
594     unsigned long    processing_time;
596     if( kpi_status & KPI_IVA_LOAD ) {
597         /* Read 32k timer */
598         iva_kpi.after_time = get_32k();
599         iva_kpi.t32k_end   = iva_kpi.after_time;
601         /* Process IVA-HD working time */
602         processing_time = iva_kpi.after_time - iva_kpi.before_time;
604 #ifdef  IVA_DETAILS
605         if( kpi_status & KPI_IVA_TRACE ) {
606             /* transform 32KHz ticks into ms */
607             PSI_TracePrintf(TRACEGRP, "END %-7s %-4u %-8lu %d\n",
608                             "IVA", iva_kpi.nb_frames + 1, iva_kpi.after_time, (processing_time * 100000) / 32768);
609         }
610 #endif /*IVA_DETAILS*/
612         /* Total for Average */
613         iva_kpi.ivahd_t_tot = (iva_kpi.ivahd_t_tot + processing_time);
615         /* Max */
616         if( processing_time > iva_kpi.ivahd_t_max ) {
617             iva_kpi.ivahd_t_max       = processing_time;
618             iva_kpi.ivahd_t_max_frame = iva_kpi.nb_frames + 1;
619         }
621         /* Min */
622         if( processing_time < iva_kpi.ivahd_t_min ) {
623             iva_kpi.ivahd_t_min       = processing_time;
624             iva_kpi.ivahd_t_min_frame = iva_kpi.nb_frames + 1;
625         }
627         iva_kpi.nb_frames++;
629         /* Processing time x MHz */
630         iva_kpi.ivahd_MHzTime += (iva_kpi.ivahd_MHz * processing_time);
631     }
635 /***************************************************************
636  * kpi_IVA_new_freq
637  * -------------------------------------------------------------
638  * Function to be called when changing IVA frequency
639  *
640  * @params: unsigned long freq
641  *
642  * @return: none
643  *
644  ***************************************************************/
645 void kpi_IVA_new_freq( unsigned long freq )
648      iva_kpi.ivahd_MHz = freq;
649      if( kpi_status & KPI_IVA_TRACE ) {
650             PSI_TracePrintf(TRACEGRP, "MHz %-7s %-4u \n", "IVA", freq);
651      }
654 /***************************************************************
655  * kpi_IVA_profiler_print
656  * -------------------------------------------------------------
657  * Function to be called after codec execution.
658  *
659  * It is printing all results. syslink_trace_daemon must be enabled
660  *
661  * @params: none
662  *
663  * @return: none
664  *
665  ***************************************************************/
666 void kpi_IVA_profiler_print(void)
668     unsigned long    total_time, fps_x100, fps, frtick_x10, Ivatick_x10, Iva_pct, Iva_mhz;
669     total_time = fps_x100 = fps = frtick_x10 = Ivatick_x10 = Iva_pct = Iva_mhz = 0;
670     unsigned long    iva_frtick_x10, iva_fps_x100, iva_fps;
672     /* Calculate the total time */
673     total_time = iva_kpi.t32k_end - iva_kpi.t32k_start;
675     if( total_time ) {
677         /* Calculate the frame period and the framerate */
678         if( iva_kpi.nb_frames ) {
679             frtick_x10 = total_time * 10 / iva_kpi.nb_frames;
680             fps_x100 = 32768 * 1000 / frtick_x10;
681             fps = fps_x100 / 100;
683             iva_frtick_x10 = iva_kpi.ivahd_t_tot * 10 / iva_kpi.nb_frames;
684             iva_fps_x100 = 32768 * 1000 / iva_frtick_x10;
685             iva_fps = iva_fps_x100 / 100;
686         }
688         /* Calculate the IVA load */
689         if( iva_kpi.nb_frames ) {
690             Ivatick_x10 = (iva_kpi.ivahd_t_tot * 10 / iva_kpi.nb_frames);
691             Iva_pct = Ivatick_x10 * 100 / frtick_x10;
692         }
694         /* Cakculate the IVA MHz used */
695         Iva_mhz = iva_kpi.ivahd_MHzTime / total_time;
697         PSI_TracePrintf(TRACEGRP, "\n");
698         PSI_TracePrintf(TRACEGRP, "----------------------------------\n");
699         PSI_TracePrintf(TRACEGRP, "M4 stats:\n");
700         PSI_TracePrintf(TRACEGRP, "-------------\n");
701         PSI_TracePrintf(TRACEGRP, "                 IVA  1st beg: %lu\n", iva_kpi.t32k_start);
702         PSI_TracePrintf(TRACEGRP, "                 IVA last end: %lu\n", iva_kpi.t32k_end);
703         PSI_TracePrintf(TRACEGRP, "            Total time at MPU: %lu\n", iva_kpi.t32k_mpu_time);
704         PSI_TracePrintf(TRACEGRP, "        Total time at IVA (A): %lu\n", iva_kpi.ivahd_t_tot);
705         PSI_TracePrintf(TRACEGRP, "     Total (IVA+MPU) time (B): %lu\n", total_time);
706         PSI_TracePrintf(TRACEGRP, "        Number of samples (C): %lu\n", iva_kpi.nb_frames);
707         PSI_TracePrintf(TRACEGRP, "  IVA period per sample (A/C): %lu\n", iva_frtick_x10 / 10);
708         PSI_TracePrintf(TRACEGRP, "Total period per sample (B/C): %lu\n", frtick_x10 / 10);
709         PSI_TracePrintf(TRACEGRP, "  fps based on total IVA time: %2d.%02d\n", iva_fps, iva_fps_x100 - (iva_fps * 100));
710         PSI_TracePrintf(TRACEGRP, "      fps based on total time: %2d.%02d\n", fps, fps_x100 - (fps * 100));
712         /* stat existing only if frames were processed */
713         if( iva_kpi.nb_frames ) {
714             PSI_TracePrintf(TRACEGRP, "\n");
715             PSI_TracePrintf(TRACEGRP, "----------------------------------\n");
716             PSI_TracePrintf(TRACEGRP, "IVA-HD processing time:\n");
717             PSI_TracePrintf(TRACEGRP, "-----------------------\n");
718             PSI_TracePrintf(TRACEGRP, "  IVA average: %d\n", iva_kpi.ivahd_t_tot / iva_kpi.nb_frames);
719             PSI_TracePrintf(TRACEGRP, "      IVA max: %d frame: %d\n", iva_kpi.ivahd_t_max, iva_kpi.ivahd_t_max_frame);
720             PSI_TracePrintf(TRACEGRP, "      IVA min: %d frame: %d\n", iva_kpi.ivahd_t_min, iva_kpi.ivahd_t_min_frame);
721             PSI_TracePrintf(TRACEGRP, "      IVA use: %d %%\n", Iva_pct);
722             if (Iva_mhz) {
723                 PSI_TracePrintf(TRACEGRP, "      IVA MHz: %d MHz\n\n", Iva_mhz);
724             }
725         }
726     }
730 /***************************************************************
731  * psi_component
732  * -------------------------------------------------------------
733  * Structure maintenaing data for Ducati Component traces
734  *
735  ***************************************************************/
736 typedef struct {
737     void *         hComponent;
738     char           name[50];
739 } psi_component;
741 /* we trace up to MAX_COMPONENTS components */
742 #define MAX_COMPONENTS 8
744 /***************************************************************
745  * kpi_comp_monitor
746  * -------------------------------------------------------------
747  * Contains up to 8 components data
748  *
749  ***************************************************************/
750 psi_component    kpi_comp_monitor[MAX_COMPONENTS]; /* we trace up to MAX_COMPONENTS components */
751 Uint32              kpi_comp_monitor_cnt=0;      /* no component yet */
754 /***************************************************************
755  * kpi_comp_init
756  * -------------------------------------------------------------
757  * setup monitor data
758  *
759  * @params: void* hComponent : Object of the component
760  *
761  * @return: none
762  *
763  ***************************************************************/
764 void kpi_comp_init(void *hComponent)
767     Uint32            comp_cnt;
769 #ifdef  COMP_ENABLE_DUCATI_LOAD
770     /* Started 1st time */
771     if( !(kpi_status & KPI_INST_RUN)) {
772         kpi_instInit();
773     }
774 #endif //COMP_ENABLE_DUCATI_LOAD
776     if( kpi_status & KPI_COMP_TRACE ) {
778         /* First init: clear kpi_comp_monitor components */
779         if( kpi_comp_monitor_cnt == 0 ) {
780             for( comp_cnt=0; comp_cnt < MAX_COMPONENTS; comp_cnt++ ) {
781                 /*clear handler registery */
782                 kpi_comp_monitor[comp_cnt].hComponent = 0;
783             }
784         }
786         /* identify the 1st component free in the table (maybe one was removed previously) */
787         for( comp_cnt=0; comp_cnt < MAX_COMPONENTS; comp_cnt++ ) {
788             if( kpi_comp_monitor[comp_cnt].hComponent == 0 ) {
789                 break;
790             }
791         }
793         if( comp_cnt >= MAX_COMPONENTS ) {
794             return;
795         }
797         /* current comp num and update */
798         kpi_comp_monitor_cnt++;
800         /* register the component handle */
801         kpi_comp_monitor[comp_cnt].hComponent = hComponent;
804         //TBD : Need to figure out how to get component name here. Setting default to rpmsg-dce
805         strcpy(kpi_comp_monitor[comp_cnt].name, "rpmsg-dce");
806         System_sprintf(kpi_comp_monitor[comp_cnt].name, "%s%d", kpi_comp_monitor[comp_cnt].name, comp_cnt); // Add index to the name
807         /* trace component init */
808         PSI_TracePrintf(TRACEGRP, "<KPI> DCE %-8s Init %-8lu \n", kpi_comp_monitor[comp_cnt].name, get_32k());
810     }
814 /***************************************************************
815  * kpi_comp_deinit
816  * -------------------------------------------------------------
817  * deinit monitor data
818  *
819  * @params: void * hComponent
820  *
821  * @return: none
822  *
823  ***************************************************************/
824 void kpi_comp_deinit(void* hComponent)
827     Uint32    comp_cnt;
829     if( kpi_comp_monitor_cnt > 0 ) {
830         /* identify the component from the registery */
831         for( comp_cnt=0; comp_cnt < MAX_COMPONENTS; comp_cnt++ ) {
832             if( kpi_comp_monitor[comp_cnt].hComponent == hComponent ) {
833                 break;
834             }
835         }
837         /* trace component deinit */
838         if( comp_cnt < MAX_COMPONENTS ) {
839             PSI_TracePrintf(TRACEGRP, "<KPI> DCE %-7s Deinit %-8lu\n", kpi_comp_monitor[comp_cnt].name, get_32k());
841             /* unregister the component */
842             kpi_comp_monitor[comp_cnt].hComponent = 0;
843         }
845         kpi_comp_monitor_cnt--;
846     }
848     /* stop the instrumentation */
849     if( kpi_comp_monitor_cnt == 0 ) {
850         kpi_instDeinit();
851     }
855 /***************************************************************
856  * kpi_load_pct_x_100
857  * -------------------------------------------------------------
858  * calculate percentage with 2 digit such as 78.34 %
859  *
860  * @params: unsigned long load, total
861  *
862  * @return: unsigned long result
863  *
864  ***************************************************************/
865 unsigned long kpi_load_pct_x_100(unsigned long load, unsigned long total)
867     unsigned long    mult = 100 * 100;
869     while( total > (32768 * 8)) {
870         total /= 2;
871         mult /= 2;
872     }
874     /* load = 100 * 100 * load / total */
875     load = ((load * mult) + total / 2) / total;
876     return (load);
879 /***************************************************************
880  * kpi_CPU_profiler_init
881  * -------------------------------------------------------------
882  * Initialize profiler data
883  *
884  * @params: none
885  *
886  * @return: none
887  *
888  ***************************************************************/
889 void kpi_CPU_profiler_init(void)
891     unsigned int    CoreId, i;
893     PSI_TracePrintf(TRACEGRP, "<KPI> CPU Profiler Init %-8lu\n", get_32k());
895     for( CoreId = 0; CoreId < 2; CoreId++ ) {
896         psi_bios_kpi   *core_kpi = &bios_kpi[CoreId];
898         core_kpi->total_time       = 0;
899         core_kpi->kpi_time         = 0;
900         core_kpi->kpi_count        = 0;
901         core_kpi->nb_switch        = 0;
903         core_kpi->nb_tasks         = 0;
904         core_kpi->nb_hwi           = 0;
905         core_kpi->nb_swi           = 0;
907         core_kpi->tasks[0].handle  = 0;                         /* for startup set task[0].handle to 0 */
909         /* reserve last task slot in DB to others task that wouldn't fit in the DB */
910         core_kpi->tasks[KPI_MAX_NB_TASKS - 1].handle = (void *) 0x11000011;
911         core_kpi->tasks[KPI_MAX_NB_TASKS - 1].total_time = 0;
912         core_kpi->tasks[KPI_MAX_NB_TASKS - 1].nb_switch  = 0;
913         strcpy(core_kpi->tasks[KPI_MAX_NB_TASKS - 1].name, "Other tasks");
914         /* reserve last swi slot in DB to others task that wouldn't fit in the DB */
915         core_kpi->swi[KPI_MAX_NB_SWI - 1].handle = (void *) 0x22000022;
916         core_kpi->swi[KPI_MAX_NB_SWI - 1].total_time = 0;
917         core_kpi->swi[KPI_MAX_NB_SWI - 1].nb_switch  = 0;
918         strcpy(core_kpi->swi[KPI_MAX_NB_SWI - 1].name, "Other swis");
919         /* reserve last hwi slot in DB to others task that wouldn't fit in the DB */
920         core_kpi->hwi[KPI_MAX_NB_HWI - 1].handle = (void *) 0x33000033;
921         core_kpi->hwi[KPI_MAX_NB_HWI - 1].total_time = 0;
922         core_kpi->hwi[KPI_MAX_NB_HWI - 1].nb_switch  = 0;
923         strcpy(core_kpi->hwi[KPI_MAX_NB_HWI - 1].name, "Other hwis");
925         /* clear the context pointers table */
926         for( i=0; i < CTX_DIRECT_NUM; i++ ) {
927             core_kpi->context_cache[i]= &(core_kpi->tasks[0]);  /* point to the Data Base */
928         }
930         core_kpi->context_stack[0] = &(core_kpi->tasks[0]);     /* point to 1st context element */
931         core_kpi->pt_context_stack = &(core_kpi->context_stack[0]); /* stack beginning */
933         core_kpi->ptr_idle_total   = &(core_kpi->idle_prev);    /* will point later on to idle_total_ticks */
934         core_kpi->idle_prev        = 0;
935         core_kpi->idle_time_prev   = 0;
937         core_kpi->trace_time       = 0;
939     }
941     /* set current time into prev_t32 in each data based */
942     bios_kpi[0].prev_t32 = get_time();
943     bios_kpi[1].prev_t32 = bios_kpi[0].prev_t32;
947 /***************************************************************
948  * kpi_CPU_profiler_print
949  * -------------------------------------------------------------
950  * Print profiler data
951  *
952  * @params: none
953  *
954  * @return: none
955  *    if (prev != NULL)
957  ***************************************************************/
958 void kpi_CPU_profiler_print(void)
960     unsigned long    load, ld00, Idle, CoreId, i;
961     psi_bios_kpi    *core_kpi;
963 #ifdef  COST_AFTER
964     unsigned long    instx1024;
965     /* calculate instrumentation cost a posteriori */
966     {
967         Task_Handle      test;
968         unsigned long    key = Task_disable();
969         core_kpi = &bios_kpi[ Core_getId() ];
970         test = core_kpi->tasks[0].handle;
971         instx1024 = get_time();
973         for( i = 0; i < 1024; i++ ) {
974             psi_kpi_task_test(test, test);
975         }
977         instx1024 = get_time() - instx1024;
978         Task_restore(key);
979     }
980 #endif //COST_AFTER
982     /* Print the results for each core */
983     for( CoreId = 0; CoreId < 2; CoreId++ ) {
984         core_kpi = &bios_kpi[CoreId];
986         /* Reconstruct global counts */
987         for( i=0; i < core_kpi->nb_tasks; i++ ) {
988             core_kpi->nb_switch += core_kpi->tasks[i].nb_switch; /* nb_switch  (nb interrupts + task switchs) */
989             core_kpi->kpi_count += core_kpi->tasks[i].nb_switch; /* kpi_count (nunber of times the intrumentation run) */
990             core_kpi->total_time+= core_kpi->tasks[i].total_time; /* total_time (all times measured) */
991         }
993         for( i=0; i < core_kpi->nb_swi; i++ ) {
994             core_kpi->nb_switch += core_kpi->swi[i].nb_switch;
995             core_kpi->kpi_count += core_kpi->swi[i].nb_switch * 2; /* 2 runs per interrupts */
996             core_kpi->total_time+= core_kpi->swi[i].total_time;
997         }
999         for( i=0; i < core_kpi->nb_hwi; i++ ) {
1000             core_kpi->nb_switch += core_kpi->hwi[i].nb_switch;
1001             core_kpi->kpi_count += core_kpi->hwi[i].nb_switch * 2; /* 2 runs per interrupts */
1002             core_kpi->total_time+= core_kpi->hwi[i].total_time;
1003         }
1005         /* add cost of measured if stored as a separate task */
1006         core_kpi->total_time += core_kpi->kpi_time;
1008         if( core_kpi->total_time ) {
1009             /* Print global stats */
1010             PSI_TracePrintf(TRACEGRP, "----------------------------------\n");
1011             PSI_TracePrintf(TRACEGRP, "Core %d :\n", CoreId);
1012             PSI_TracePrintf(TRACEGRP, "--------\n");
1013             PSI_TracePrintf(TRACEGRP, "  type  #: handle   ticks    counts  ( %%cpu )   instance-name\n");
1014             PSI_TracePrintf(TRACEGRP, "----------------------------------\n");
1015             PSI_TracePrintf(TRACEGRP, "  Total test        %-8lu %-7ld\n", core_kpi->total_time, core_kpi->nb_switch);
1016             PSI_TracePrintf(TRACEGRP, "----------------------------------\n");
1018             if( core_kpi->kpi_time ) {
1019                 ld00 = kpi_load_pct_x_100(core_kpi->kpi_time, core_kpi->total_time); /* ex. 7833 -> 78.33 % */
1020                 load = ld00 / 100;                                        /* 78.33 % -> 78 */
1021                 ld00 = ld00 - load * 100;                                 /* 78.33 % -> 33 */
1022                 PSI_TracePrintf(TRACEGRP, "  Measure: Overhead %-8lu ----    (%2d.%02d %%)  CPU load-inst-cost\n",
1023                                 core_kpi->kpi_time, load, ld00);
1024             }
1026             for( i=0; i < core_kpi->nb_tasks; i++ ) {
1027                 ld00 = kpi_load_pct_x_100(core_kpi->tasks[i].total_time, core_kpi->total_time);
1028                 load = ld00 / 100;                                      /* 78.33 % -> 78 */
1029                 ld00 = ld00 - load * 100;                               /* 78.33 % -> 33 */
1030                 PSI_TracePrintf(TRACEGRP, "  task %2d: %-8lx %-8lu %-7ld (%2d.%02d %%)  %s\n",
1031                                 i, core_kpi->tasks[i].handle, core_kpi->tasks[i].total_time, core_kpi->tasks[i].nb_switch, load, ld00, core_kpi->tasks[i].name);
1032             }
1034             for( i=0; i < core_kpi->nb_swi; i++ ) {
1035                 ld00 = kpi_load_pct_x_100(core_kpi->swi[i].total_time, core_kpi->total_time);
1036                 load = ld00 / 100;                                      /* 78.33 % -> 78 */
1037                 ld00 = ld00 - load * 100;                               /* 78.33 % -> 33 */
1038                 PSI_TracePrintf(TRACEGRP, "   swi %2d: %-8lx %-8lu %-7ld (%2d.%02d %%)  %s\n",
1039                                 i, core_kpi->swi[i].handle, core_kpi->swi[i].total_time, core_kpi->swi[i].nb_switch, load, ld00, core_kpi->swi[i].name);
1040             }
1042             for( i=0; i < core_kpi->nb_hwi; i++ ) {
1043                 ld00 = kpi_load_pct_x_100(core_kpi->hwi[i].total_time, core_kpi->total_time);
1044                 load = ld00 / 100;                                      /* 78.33 % -> 78 */
1045                 ld00 = ld00 - load * 100;                               /* 78.33 % -> 33 */
1046                 PSI_TracePrintf(TRACEGRP, "   hwi %2d: %-8lx %-8lu %-7ld (%2d.%02d %%)  %s\n",
1047                                 i, core_kpi->hwi[i].handle, core_kpi->hwi[i].total_time, core_kpi->hwi[i].nb_switch, load, ld00, core_kpi->hwi[i].name);
1048             }
1050             PSI_TracePrintf(TRACEGRP, "----------------------------------\n");
1052 #ifdef  COST_AFTER
1053             if( !core_kpi->kpi_time ) {
1054                 /* calculate the cost in the instrumentation */
1055                 core_kpi->kpi_time = (core_kpi->kpi_count * instx1024) / 1024;
1056                 ld00 = kpi_load_pct_x_100(core_kpi->kpi_time, core_kpi->total_time); /* ex. 7833 -> 78.33 % */
1057                 load = ld00 / 100;                                        /* 78.33 % -> 78 */
1058                 ld00 = ld00 - load * 100;                                 /* 78.33 % -> 33 */
1059                 PSI_TracePrintf(TRACEGRP, "  CPU load measure overhead  %2d.%02d %%\n", load, ld00);
1060             }
1061 #endif //COST_AFTER
1063             if( core_kpi->trace_time ) {
1064                 ld00 = kpi_load_pct_x_100(core_kpi->trace_time, core_kpi->total_time);
1065                 load = ld00 / 100;                                      /* 78.33 % -> 78 */
1066                 ld00 = ld00 - load * 100;                               /* 78.33 % -> 33 */
1067                 PSI_TracePrintf(TRACEGRP, "  Real time traces overhead  %2d.%02d %%\n", load, ld00);
1068             }
1070             /* restore to Idle Inst cost + print cost if idle exists */
1071             if( *(core_kpi->ptr_idle_total)) {
1072                 Idle = *(core_kpi->ptr_idle_total) + core_kpi->kpi_time + core_kpi->trace_time;
1073                 ld00 = kpi_load_pct_x_100(Idle, core_kpi->total_time);
1074                 load = ld00 / 100;                                      /* 78.33 % -> 78 */
1075                 ld00 = ld00 - load * 100;                               /* 78.33 % -> 33 */
1076                 PSI_TracePrintf(TRACEGRP, "----------------------------------\n");
1077                 PSI_TracePrintf(TRACEGRP, "  Idle task compensated  =>  %2d.%02d %% \n", load, ld00);
1078                 PSI_TracePrintf(TRACEGRP, "----------------------------------\n\n");
1079             }
1081         }
1082     }
1085 /***************************************************************
1086  * psi_kpi_search_create_context_task
1087  * -------------------------------------------------------------
1088  * Search for a context entry to context DB.
1089  * Create a new on if not existing
1090  *
1091  * @params: void *task, unsigned int CoreId
1092  *
1093  * @return: psi_context_info *db_ptr
1094  *
1095  ***************************************************************/
1096 psi_context_info *psi_kpi_search_create_context_task(void *task, psi_bios_kpi *core_kpi)
1098     int                 i, nb_items, strLenght;
1099     String              taskName;
1100     psi_context_info   *db_ptr;
1102     /* KPI_CONTEXT_TASK */
1103     nb_items = core_kpi->nb_tasks;
1104     db_ptr   = core_kpi->tasks;
1106     /* Search handle existing in task table */
1107     for( i=0; i < nb_items; i++ ) {
1108         if( task == db_ptr[i].handle ) {
1109             break;
1110         }
1111     }
1113     /* handle found in our DB */
1114     if( i < nb_items ) {
1115         return (&db_ptr[i]);
1116     }
1118     /* check for space left in the DB. When last-1 reached use last for others tasks together */
1119     if( nb_items >= KPI_MAX_NB_TASKS - 1 ) {
1120         core_kpi->nb_tasks = KPI_MAX_NB_TASKS;
1121         return (&db_ptr[KPI_MAX_NB_TASKS - 1]);
1122     }
1124     /* add the new task */
1125     core_kpi->nb_tasks = nb_items + 1;
1127     /* get the task name Make sure task name fits into the item.name */
1128     taskName = Task_Handle_name((Task_Handle)task);
1129     strLenght = strlen(taskName);
1130     if( strLenght > 40 ) {
1131         strLenght = 40;
1132     }
1134     /* For Idle direct access */
1135     if( strstr(taskName, "Idle")) {
1136         core_kpi->ptr_idle_total = &(db_ptr[i].total_time);
1137     }
1139     /* create the new entry */
1140     db_ptr[i].handle     = task;
1141     db_ptr[i].total_time = 0;
1142     db_ptr[i].nb_switch  = 0;
1143     strncpy(db_ptr[i].name, taskName, strLenght);
1144     *(db_ptr[i].name + strLenght) = '\0';                // complete the chain of char
1146     return (&(db_ptr[i]));
1149 /***************************************************************
1150  * psi_kpi_search_create_context_swi
1151  * -------------------------------------------------------------
1152  * Search for a context entry to context DB.
1153  * Create a new on if not existing
1154  *
1155  * @params: void *task, unsigned int CoreId
1156  *
1157  * @return: psi_context_info *db_ptr
1158  *
1159  ***************************************************************/
1160 psi_context_info *psi_kpi_search_create_context_swi(void *task, psi_bios_kpi *core_kpi)
1162     int                 i, nb_items, strLenght;
1163     String              taskName;
1164     psi_context_info   *db_ptr;
1166     /* KPI_CONTEXT_SWI */
1167     nb_items = core_kpi->nb_swi;
1168     db_ptr   = core_kpi->swi;
1170     /* Search handle existing in task table */
1171     for( i=0; i < nb_items; i++ ) {
1172         if( task == db_ptr[i].handle ) {
1173             break;
1174         }
1175     }
1177     /* handle found in our DB */
1178     if( i < nb_items ) {
1179         return (&db_ptr[i]);
1180     }
1182     /* check for space left in the DB. When last-1 reached use last for others swi together */
1183     if( nb_items >= KPI_MAX_NB_SWI - 1 ) {
1184         core_kpi->nb_swi = KPI_MAX_NB_SWI;
1185         return (&db_ptr[KPI_MAX_NB_SWI - 1]);
1186     }
1188     /* add the new swi */
1189     core_kpi->nb_swi = nb_items + 1;
1191     /* get the task name Make sure task name fits into the item.name */
1192     taskName = Swi_Handle_name((Swi_Handle)task);
1193     strLenght = strlen(taskName);
1194     if( strLenght > 40 ) {
1195         strLenght = 40;
1196     }
1198     /* create the new entry */
1199     db_ptr[i].handle     = task;
1200     db_ptr[i].total_time = 0;
1201     db_ptr[i].nb_switch  = 0;
1202     strncpy(db_ptr[i].name, taskName, strLenght);
1203     *(db_ptr[i].name + strLenght) = '\0';                // complete the chain of char
1205     return (&(db_ptr[i]));
1208 /***************************************************************
1209  * psi_kpi_search_create_context_hwi
1210  * -------------------------------------------------------------
1211  * Search for a context entry to context DB.
1212  * Create a new on if not existing
1213  *
1214  * @params: void *task, unsigned int CoreId
1215  *
1216  * @return: psi_context_info *db_ptr
1217  *
1218  ***************************************************************/
1219 psi_context_info *psi_kpi_search_create_context_hwi(void *task, psi_bios_kpi *core_kpi)
1221     int                 i, nb_items, strLenght;
1222     String              taskName;
1223     psi_context_info   *db_ptr;
1225     /* KPI_CONTEXT_HWI */
1226     nb_items = core_kpi->nb_hwi;
1227     db_ptr   = core_kpi->hwi;
1229     /* Search handle existing in task table */
1230     for( i=0; i < nb_items; i++ ) {
1231         if( task == db_ptr[i].handle ) {
1232             break;
1233         }
1234     }
1236     /* handle found in our DB */
1237     if( i < nb_items ) {
1238         return (&db_ptr[i]);
1239     }
1241     /* check for space left in the DB. When last-1 reached use last for others hwi together */
1242     if( nb_items >= KPI_MAX_NB_HWI - 1 ) {
1243         core_kpi->nb_hwi = KPI_MAX_NB_HWI;
1244         return (&db_ptr[KPI_MAX_NB_HWI - 1]);
1245     }
1247     /* add the new hwi */
1248     core_kpi->nb_hwi = nb_items + 1;
1250     /* get the task name Make sure task name fits into the item.name */
1251     taskName = Hwi_Handle_name((Hwi_Handle)task);
1252     strLenght = strlen(taskName);
1253     if( strLenght > 40 ) {
1254         strLenght = 40;
1255     }
1257     /* create the new entry */
1258     db_ptr[i].handle     = task;
1259     db_ptr[i].total_time = 0;
1260     db_ptr[i].nb_switch  = 0;
1261     strncpy(db_ptr[i].name, taskName, strLenght);
1262     *(db_ptr[i].name + strLenght) = '\0';                // complete the chain of char
1264     return (&(db_ptr[i]));
1267 /***************************************************************
1268  * psi_kpi_task_switch
1269  * -------------------------------------------------------------
1270  * Task switch hook:
1271  *  - identify new tasks
1272  *  - accumulate task load
1273  *  - process total execution time
1274  *
1275  * @params: Task_Handle prev, Task_Handle next
1276  *
1277  * @return: none
1278  *
1279  ***************************************************************/
1280 void psi_kpi_task_switch(Task_Handle prev, Task_Handle next)
1282     if( kpi_status & KPI_CPU_LOAD ) {
1283         unsigned long       key    = Core_hwiDisable();
1284         unsigned long       CoreId = Core_getId();
1285         unsigned long       tick   = get_time_core(CoreId);
1286         psi_bios_kpi       *core_kpi = &bios_kpi[CoreId];
1287         psi_context_info   *context_next, *context;
1288         unsigned long       cachePtr;
1290         /* Ending context */
1291         context = (psi_context_info *) *core_kpi->pt_context_stack;
1293         /* Starting context */
1294         cachePtr= ((((long) next) >> 4) ^ (((long) next) >> 12)) & 0xff; /* build a simple 8 bits address for trying cache DB search */
1295         context_next = core_kpi->context_cache[ cachePtr ];
1296         if( context_next->handle != next ) {                      /* if NOT pointing to our handle make exhaustive seartch */
1297             context_next = psi_kpi_search_create_context_task(next, core_kpi);
1298             core_kpi->context_cache[ cachePtr ] = context_next;   /* update direct table (this may evict one already here) */
1299         }
1301         /* Maintain stack for interrupts: save context starting */
1302         *core_kpi->pt_context_stack = (void *) context_next;
1304         /* update tasks stats */
1305         context->total_time  += tick - core_kpi->prev_t32;        /* count the time spend in the ending task */
1306         context->nb_switch++;                                     /* count the switch */
1308 #ifdef  INST_COST
1309         /* will start processing the task now */
1310         {
1311             unsigned long    tick2 = get_time_core(CoreId);
1312             core_kpi->kpi_time += tick2 - tick;                   /* update kpi_time (instrumentation cost) */
1313             core_kpi->prev_t32  = tick2;                          /* store tick: time when task actually starts */
1314         }
1315 #else //INST_COST
1316         core_kpi->prev_t32    = tick;                             /* store tick: time when task actually starts */
1317 #endif //INST_COST
1319         Core_hwiRestore(key);
1320     }
1323 /***************************************************************
1324  * psi_kpi_swi_begin
1325  * -------------------------------------------------------------
1326  * SWI begin hook: memorizes SWI start time
1327  *
1328  * @params: Swi_Handle swi
1329  *
1330  * @return: none
1331  *
1332  ***************************************************************/
1333 void psi_kpi_swi_begin(Swi_Handle swi)
1335     if( kpi_status & KPI_CPU_LOAD ) {
1336         unsigned long       key    = Core_hwiDisable();
1337         unsigned long       CoreId = Core_getId();
1338         unsigned long       tick   = get_time_core(CoreId);
1339         psi_bios_kpi       *core_kpi = &bios_kpi[CoreId];
1340         psi_context_info   *context_next, *context;
1341         unsigned long       cachePtr;
1343         /* Ending context */
1344         context = (psi_context_info *) *core_kpi->pt_context_stack++; /* Going from a TASK or SWI to new SWI */
1346         /* Starting context */
1347         cachePtr= ((((long) swi) >> 4) ^ (((long) swi) >> 12)) & 0xff; /* build a simple 8 bits address for trying cache DB search */
1348         context_next = core_kpi->context_cache[ cachePtr ];
1349         if( context_next->handle != swi ) {                       /* if NOT pointing to our handle make exhaustive seartch */
1350             context_next = psi_kpi_search_create_context_swi(swi, core_kpi);
1351             core_kpi->context_cache[ cachePtr ] = context_next;   /* update direct table (this may evict one already here) */
1352         }
1354         /* Maintain stack for interrupts: save context starting */
1355         *core_kpi->pt_context_stack = (void *) context_next;
1357         /* update tasks stats */
1358         context->total_time  += tick - core_kpi->prev_t32;        /* count the time spend in the ending task */
1360 #ifdef  INST_COST
1361         /* will start processing the task now */
1362         {
1363             unsigned long    tick2 = get_time_core(CoreId);
1364             core_kpi->kpi_time += tick2 - tick;                   /* update kpi_time (instrumentation cost) */
1365             core_kpi->prev_t32  = tick2;                          /* store tick: time when task actually starts */
1366         }
1367 #else //INST_COST
1368         core_kpi->prev_t32    = tick;                             /* store tick: time when task actually starts */
1369 #endif //INST_COST
1371         Core_hwiRestore(key);
1372     }
1375 /***************************************************************
1376  * psi_kpi_swi_end
1377  * -------------------------------------------------------------
1378  * SWI end hook: accumulates SWI execution time
1379  *
1380  * @params: Swi_Handle swi
1381  *
1382  * @return: none
1383  *
1384  ***************************************************************/
1385 void psi_kpi_swi_end(Swi_Handle swi)
1387     if( kpi_status & KPI_CPU_LOAD ) {
1388         unsigned long       key    = Core_hwiDisable();
1389         unsigned long       CoreId = Core_getId();
1390         unsigned long       tick   = get_time_core(CoreId);
1391         psi_bios_kpi       *core_kpi = &bios_kpi[CoreId];
1392         psi_context_info   *context;
1394         /* Ending context */
1395         context = (psi_context_info *) *core_kpi->pt_context_stack--; /* Going back to interrupted TASK or SWI */
1397         /* update tasks stats */
1398         context->total_time  += tick - core_kpi->prev_t32;        /* count the time spend in the ending task */
1399         context->nb_switch++;                                     /* count the switch */
1401 #ifdef  INST_COST
1402         /* will start processing the task now */
1403         {
1404             unsigned long    tick2 = get_time_core(CoreId);
1405             core_kpi->kpi_time += tick2 - tick;                   /* update kpi_time (instrumentation cost) */
1406             core_kpi->prev_t32  = tick2;                          /* store tick: time when task actually starts */
1407         }
1408 #else //INST_COST
1409         core_kpi->prev_t32    = tick;                             /* store tick: time when task actually starts */
1410 #endif //INST_COST
1412         Core_hwiRestore(key);
1413     }
1416 /***************************************************************
1417  * psi_kpi_hwi_begin
1418  * -------------------------------------------------------------
1419  * HWI begin hook: memorizes HWI start time
1420  *
1421  * @params: Hwi_Handle hwi
1422  *
1423  * @return: none
1424  *
1425  ***************************************************************/
1426 void psi_kpi_hwi_begin(Hwi_Handle hwi)
1428     if( kpi_status & KPI_CPU_LOAD ) {
1429         unsigned long       key    = Core_hwiDisable();
1430         unsigned long       CoreId = Core_getId();
1431         unsigned long       tick   = get_time_core(CoreId);
1432         psi_bios_kpi       *core_kpi = &bios_kpi[CoreId];
1433         psi_context_info   *context_next, *context;
1434         unsigned long       cachePtr;
1436         /* Ending context */
1437         context = (psi_context_info *) *core_kpi->pt_context_stack++; /* Going from previous TASK or SWI to a HWI */
1439         /* Starting context */
1440         cachePtr= ((((long) hwi) >> 4) ^ (((long) hwi) >> 12)) & 0xff; /* build a simple 8 bits address for trying cache DB search */
1441         context_next = core_kpi->context_cache[ cachePtr ];
1442         if( context_next->handle != hwi ) {                       /* if NOT pointing to our handle make exhaustive seartch */
1443             context_next = psi_kpi_search_create_context_hwi(hwi, core_kpi);
1444             core_kpi->context_cache[ cachePtr ] = context_next;   /* update direct table (this may evict one already here) */
1445         }
1447         /* Maintain stack for interrupts: save context starting */
1448         *core_kpi->pt_context_stack = (void *) context_next;
1450         /* update tasks stats */
1451         context->total_time  += tick - core_kpi->prev_t32;        /* count the time spend in the ending task */
1453 #ifdef  INST_COST
1454         /* will start processing the task now */
1455         {
1456             unsigned long    tick2 = get_time_core(CoreId);
1457             core_kpi->kpi_time += tick2 - tick;                   /* update kpi_time (instrumentation cost) */
1458             core_kpi->prev_t32  = tick2;                          /* store tick: time when task actually starts */
1459         }
1460 #else //INST_COST
1461         core_kpi->prev_t32    = tick;                             /* store tick: time when task actually starts */
1462 #endif //INST_COST
1464         Core_hwiRestore(key);
1465     }
1468 /***************************************************************
1469  * psi_kpi_hwi_end
1470  * -------------------------------------------------------------
1471  * HWI end hook: accumulates HWI execution time
1472  *
1473  * @params: Hwi_Handle hwi
1474  *
1475  * @return: none
1476  *
1477  ***************************************************************/
1478 void psi_kpi_hwi_end(Hwi_Handle hwi)
1480     if( kpi_status & KPI_CPU_LOAD ) {
1481         unsigned long       key    = Core_hwiDisable();
1482         unsigned long       CoreId = Core_getId();
1483         unsigned long       tick   = get_time_core(CoreId);
1484         psi_bios_kpi       *core_kpi = &bios_kpi[CoreId];
1485         psi_context_info   *context;
1487         /* Ending context */
1488         context = (psi_context_info *) *core_kpi->pt_context_stack--; /* Going back to interrupted TASK or SWI or HWI */
1490         /* update tasks stats */
1491         context->total_time  += tick - core_kpi->prev_t32;        /* count the time spend in the ending task */
1492         context->nb_switch++;                                     /* count the switch */
1494 #ifdef  INST_COST
1495         /* will start processing the task now */
1496         {
1497             unsigned long    tick2 = get_time_core(CoreId);
1498             core_kpi->kpi_time += tick2 - tick;                   /* update kpi_time (instrumentation cost) */
1499             core_kpi->prev_t32  = tick2;                          /* store tick: time when task actually starts */
1500         }
1501 #else //INST_COST
1502         core_kpi->prev_t32    = tick;                             /* store tick: time when task actually starts */
1503 #endif //INST_COST
1505         Core_hwiRestore(key);
1506     }
1509 /***************************************************************
1510  * psi_kpi_task_test
1511  * -------------------------------------------------------------
1512  * Task switch hook:
1513  *  - identify new tasks
1514  *  - used for measuring execution time of the instrumentation
1515  *
1516  * @params: Task_Handle prev, Task_Handle next
1517  *
1518  * @return: none
1519  *
1520  ***************************************************************/
1521 void psi_kpi_task_test(Task_Handle prev, Task_Handle next)
1523     unsigned long       key    = Core_hwiDisable();
1524     unsigned long       CoreId = Core_getId();
1525     unsigned long       tick   = get_time_core(CoreId);
1526     psi_bios_kpi       *core_kpi = &bios_kpi[CoreId];
1527     psi_context_info   *context_next;
1528     unsigned long       cachePtr;
1530     /* Starting context */
1531     cachePtr= ((((long) next) >> 4) ^ (((long) next) >> 12)) & 0xff; /* build a simple 8 bits address for trying cache DB search */
1532     context_next = core_kpi->context_cache[ cachePtr ];
1533     if( context_next->handle != next ) {                           /* if NOT pointing to our handle make exhaustive seartch */
1534         context_next = psi_kpi_search_create_context_task(next, core_kpi);
1535         core_kpi->context_cache[ cachePtr ] = context_next;       /* update direct table (this may evict one already here) */
1536     }
1538     /* Maintain stack for interrupts: save context starting */
1539     *core_kpi->pt_context_stack = (void *) context_next;
1541     core_kpi->prev_t32    = tick;                                 /* store tick: time when task actually starts */
1543     Core_hwiRestore(key);