1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - OS
3   File:     os_functionCost.c
4 
5   Copyright 2003-2008 Nintendo.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Date:: 2009-06-19#$
14   $Rev: 10786 $
15   $Author: okajima_manabu $
16  *---------------------------------------------------------------------------*/
17 #include <nitro/os.h>
18 
19 #if defined(OS_PROFILE_AVAILABLE) && defined(OS_PROFILE_FUNCTION_COST)
20 
21 #ifdef OS_NO_FUNCTIONCOST
22 //---- dummy function
__PROFILE_ENTRY(void)23 SDK_WEAK_SYMBOL asm void __PROFILE_ENTRY( void ){  bx   lr }
__PROFILE_EXIT(void)24 SDK_WEAK_SYMBOL asm void __PROFILE_EXIT( void ){   bx   lr }
25 #else  // ifdef OS_NO_FUNCTIONCOST
26 
27 //---- function prototype declaration
28 extern u32 OSi_GetTick_noProfile(void);
29 extern void OSi_SetSystemCallbackInSwitchThread(void *callback);
30 
31 //---- flag for thread initializing
32 extern BOOL OSi_IsThreadInitialized;
33 
34 static OSFunctionCostInfo *OSi_GetFunctionCostInfo(void);
35 static void OSi_SetStatistics(void *statBuf, OSFunctionCost *entry, OSFunctionCost *exit);
36 static void OSi_CalcThreadInterval(register OSThread *saveThread, register OSThread *loadThread);
37 
38 //---- pointer to functionCost at not using threadSystem
39 static OSFunctionCostInfo *OSi_DefaultFunctionCostInfo;
40 
41 //---- buffer check number
42 #define OSi_FUNCTIONCOST_CHECKNUM_BUFFER	0xfddb597d
43 
44 //================================================================================
45 //              ENABLE/DISABLE
46 //================================================================================
47 /*---------------------------------------------------------------------------*
48   Name:         OS_EnableFunctionCost
49 
50   Description:  enable functionCost
51 
52   Arguments:    None
53 
54   Returns:      previous status. TRUE if enable
55  *---------------------------------------------------------------------------*/
56 #include <nitro/code32.h>
OS_EnableFunctionCost(void)57 asm BOOL OS_EnableFunctionCost( void )
58 {
59   //---- check if functionCost not available
60   stmfd   sp!, {lr}
61   bl      OSi_GetFunctionCostInfo
62   ldmfd   sp!, {lr}
63   cmp     r0, #0
64   bxeq    lr
65 
66   mov     r2, r0
67   ldrh    r0, [ r2, #OSFunctionCostInfo.enable ]
68   mov     r1, #1
69   strh    r1, [ r2, #OSFunctionCostInfo.enable ]
70 
71   bx      lr
72 }
73 #include <nitro/codereset.h>
74 
75 /*---------------------------------------------------------------------------*
76   Name:         OS_DisableFunctionCost
77 
78   Description:  disble functionCost
79 
80   Arguments:    None
81 
82   Returns:      previous status. TRUE if enable
83  *---------------------------------------------------------------------------*/
84 #include <nitro/code32.h>
OS_DisableFunctionCost(void)85 asm BOOL OS_DisableFunctionCost( void )
86 {
87   //---- check if functionCost not available
88   stmfd   sp!, {lr}
89   bl      OSi_GetFunctionCostInfo
90   ldmfd   sp!, {lr}
91   cmp     r0, #0
92   bxeq    lr
93 
94   mov     r2, r0
95   ldrh    r0, [ r2, #OSFunctionCostInfo.enable ]
96   mov     r1, #0
97   strh    r1, [ r2, #OSFunctionCostInfo.enable ]
98 
99   bx      lr
100 }
101 #include <nitro/codereset.h>
102 
103 
104 /*---------------------------------------------------------------------------*
105   Name:         OS_RestoreFunctionCost
106 
107   Description:  set status of functionCost
108 
109   Arguments:    enable :  TRUE if set to be enable, FALSE if not
110 
111   Returns:      previous status. TRUE if enable
112  *---------------------------------------------------------------------------*/
113 #include <nitro/code32.h>
OS_RestoreFunctionCost(BOOL)114 asm BOOL OS_RestoreFunctionCost( BOOL )
115 {
116   //---- check if functionCost not available
117   stmfd   sp!, {r0, lr}
118   bl      OSi_GetFunctionCostInfo
119   mov     r1, r0
120   ldmfd   sp!, {r0, lr}
121   cmp     r1, #0
122   bxeq    lr
123 
124   ldrh    r2, [ r1, #OSFunctionCostInfo.enable ]
125   strh    r0, [ r1, #OSFunctionCostInfo.enable ]
126   mov     r0, r2
127 
128   bx      lr
129 }
130 #include <nitro/codereset.h>
131 
132 //================================================================================
133 //             SETTING
134 //================================================================================
135 /*---------------------------------------------------------------------------*
136   Name:         OS_InitFunctionCost
137 
138   Description:  Initialize functionCost buffer,
139                 and start recording.
140 
141   Arguments:    buf    address to buffer for recording entering and exitting function.
142                 size   size of buffer (by byte)
143 
144   Returns:      None
145  *---------------------------------------------------------------------------*/
146 #pragma profile off
OS_InitFunctionCost(void * buf,u32 size)147 void OS_InitFunctionCost(void *buf, u32 size)
148 {
149     OSFunctionCostInfo **infoPtr;
150 
151     SDK_TASSERTMSG(((u32)buf & 3) == 0, "FunctionCost buffer must be aligned by 4");
152     SDK_TASSERTMSG((size >= OSi_COSTINFO_SIZEOF_HEADERPART + sizeof(OSFunctionCost)),
153                   "to small FunctionCost buffer");
154 
155     //---- need Tick
156     if (!OS_IsTickAvailable())
157     {
158         OS_TPanic("OS_InitFunctionCost: need tick.\n");
159     }
160 
161 #ifdef SDK_NO_THREAD
162     //---- pointer to functionCostInfo is in static valiable
163     infoPtr = &OSi_DefaultFunctionCostInfo;
164 #else
165     //---- pointer to requiredCostInfo is in OSThread structure
166     SDK_TASSERTMSG(OS_IsThreadAvailable(), "OS_InitFunctionCost: thread system not initialized.");
167     infoPtr = (OSFunctionCostInfo **)&(OS_GetCurrentThread()->profiler);
168 
169     OSi_SetSystemCallbackInSwitchThread(OSi_CalcThreadInterval);
170 #endif
171 
172     *infoPtr = (OSFunctionCostInfo *)buf;
173     //(*infoPtr)->current = (OSFunctionCost *)(*infoPtr)->array; // not need because clear function includes this.
174     (*infoPtr)->limit = (OSFunctionCost *)((u32)buf
175                                            + OSi_COSTINFO_SIZEOF_HEADERPART
176                                            + OS_CalcFunctionCostLines(size) * sizeof(OSFunctionCost));
177     (*infoPtr)->enable = (u16)TRUE;
178 
179 #ifdef OSi_FUNCTIONCOST_THREAD_INTERVAL
180     (*infoPtr)->breakTime = 0;
181 #endif
182 
183     //---- clear function cost buffer
184     OSi_ClearThreadFunctionCostBuffer(NULL);
185 }
186 
187 #pragma profile reset
188 
189 //================================================================================
190 //              UTILITY
191 //================================================================================
192 /*---------------------------------------------------------------------------*
193   Name:         OS_CalcFunctionCostLines
194 
195   Description:  calculate number of lines to be able to be allocated
196 
197   Arguments:    size :    FunctionCost buffer size
198                           same as argument of OS_InitFunctionCost()'s size
199 
200   Returns:      number of lines to be able to allocate in 'size' byte
201  *---------------------------------------------------------------------------*/
OS_CalcFunctionCostLines(u32 size)202 int OS_CalcFunctionCostLines(u32 size)
203 {
204     int     n = (int)((size - OSi_COSTINFO_SIZEOF_HEADERPART) / sizeof(OSFunctionCost));
205     return (n < 0) ? 0 : n;
206 }
207 
208 /*---------------------------------------------------------------------------*
209   Name:         OS_CalcFunctionCostBufferSize
210 
211   Description:  calculate buffer size to allocate specified lines
212 
213   Arguments:    lines :   lines to want to allocate
214 
215   Returns:      buffer size to need
216  *---------------------------------------------------------------------------*/
OS_CalcFunctionCostBufferSize(int lines)217 u32 OS_CalcFunctionCostBufferSize(int lines)
218 {
219     SDK_ASSERT(lines >= 0);
220 
221     return OSi_COSTINFO_SIZEOF_HEADERPART + lines * sizeof(OSFunctionCost);
222 }
223 
224 /*---------------------------------------------------------------------------*
225   Name:         OSi_ClearThreadFunctionCostBuffer
226 
227   Description:  clear function cost buffer of specified thread
228 
229   Arguments:    thread : NULL means current thread.
230                          Other is thread pointer.
231   Returns:      None
232  *---------------------------------------------------------------------------*/
233 #pragma profile off
OSi_ClearThreadFunctionCostBuffer(OSThread * thread)234 void OSi_ClearThreadFunctionCostBuffer(OSThread *thread)
235 {
236     OSFunctionCostInfo *infoPtr;
237 
238     if (!thread)
239     {
240         infoPtr = OSi_GetFunctionCostInfo();
241     }
242     else
243     {
244         infoPtr = (OSFunctionCostInfo *)(thread->profiler);
245     }
246 
247     if (infoPtr)
248     {
249         infoPtr->current = infoPtr->array;
250 
251         //---- for check overflowing buffer limit
252         *(u32 *)(infoPtr->limit - 1) = OSi_FUNCTIONCOST_CHECKNUM_BUFFER;
253     }
254 }
255 
256 #pragma profile reset
257 
258 /*---------------------------------------------------------------------------*
259   Name:         OS_GetFunctionCostInfo
260 
261   Description:  get pointer to functionCostInfo structure
262 
263   Arguments:    None
264 
265   Returns:      pointer.
266                 NULL if not functionCost initialized
267  *---------------------------------------------------------------------------*/
268 #include <nitro/code32.h>
OSi_GetFunctionCostInfo(void)269 static asm OSFunctionCostInfo* OSi_GetFunctionCostInfo( void )
270 {
271 #ifdef SDK_NO_THREAD
272   ldr     r0, =OSi_DefaultFunctionCostInfo
273   ldr     r0, [ r0, #0 ]
274   bx      lr
275 #else
276   ldr    r0, =OSi_ThreadInfo
277   ldr    r0, [ r0, #OSThreadInfo.current ]           // r0 = currentThread. 0 if no currentThread
278   cmp    r0, #0
279   ldrne  r0, [ r0, #OSThread.profiler ]              // r0 = functionCostInfo
280   bx     lr
281 #endif
282 }
283 #include <nitro/codereset.h>
284 
285 
286 /*---------------------------------------------------------------------------*
287   Name:         OS_CheckFunctionCostBuffer
288 
289   Description:  check if function cost buffer overflows the limit.
290 
291   Arguments:    None
292 
293   Returns:      FALSE if overflowed. TRUE if not
294  *---------------------------------------------------------------------------*/
295 #ifndef OS_NO_FUNCTIONCOST
296 #pragma profile off
OS_CheckFunctionCostBuffer(void * buf)297 BOOL OS_CheckFunctionCostBuffer(void *buf)
298 {
299     OSFunctionCostInfo *infoPtr = buf;
300 
301     if (*(u32 *)(infoPtr->limit - 1) != OSi_FUNCTIONCOST_CHECKNUM_BUFFER)
302     {
303         //OS_TPrintf("OVER!\n");
304         return FALSE;
305     }
306 
307     return TRUE;
308 }
309 
310 #pragma profile reset
311 #endif
312 
313 //================================================================================
314 //              PROFILE
315 //================================================================================
316 /*---------------------------------------------------------------------------*
317   Name:         __PROFILE_ENTRY
318 
319   Description:  entry of function in profiler
320 
321   Arguments:    None
322 
323   Returns:      None
324  *---------------------------------------------------------------------------*/
325 #include <nitro/code32.h>
__PROFILE_ENTRY(void)326 asm void __PROFILE_ENTRY( void )
327 {
328 #ifndef SDK_NO_THREAD
329   //---- check if thread system not initialized
330   stmfd  sp!, {r0}
331   ldr    r0, =OSi_IsThreadInitialized
332   ldr    r0, [ r0, #0 ]
333   cmp    r0, #0
334   ldmfd  sp!, {r0}
335   bxeq   lr
336 #endif
337 
338   stmfd  sp!, {r1-r4, lr}
339 
340   //---- disable interrupt
341   mrs     r4, cpsr
342   orr     r1, r4, #HW_PSR_IRQ_DISABLE
343   msr     cpsr_c, r1
344 
345   //---- check if functionCost not available
346   stmfd  sp!, {r0}
347   bl     OSi_GetFunctionCostInfo
348   mov    r1, r0
349   ldmfd  sp!, {r0}
350   cmp    r1, #0
351   beq    _exit
352 
353   //---- check if functionCost master enable
354   ldrh   r2, [ r1, #OSFunctionCostInfo.enable ]
355   cmp    r2, #0
356   beq    _exit
357 
358   //---- get currentPtr of FunctionCost
359   ldr    r2, [ r1, #OSFunctionCostInfo.current ]
360   cmp    r2, #0
361   beq    _exit
362 
363   //---- check if buffer is over limit
364   ldr    r3, [ r1, #OSFunctionCostInfo.limit ]
365   cmp    r2, r3
366   bpl    _exit
367 
368   //---- store pointer to function name string
369   str    r0, [ r2, #OSFunctionCost.entry.name ]
370 
371   //---- store time
372   stmfd  sp!, {r1-r2}
373   bl     OSi_GetTick_noProfile
374   ldmfd  sp!, {r1-r2}
375   str    r0, [ r2, #OSFunctionCost.entry.time ]
376 
377 #ifdef OSi_FUNCTIONCOST_THREAD_INTERVAL
378   //---- clear interval time
379   mov    r3, #0
380   str    r3, [ r2, #OSFunctionCost.exit.interval ]
381 #endif
382 
383   //---- increment pointer
384   add    r2, r2, #OSi_SIZEOF_FUNCTIONCOST
385   str    r2, [ r1, #OSFunctionCostInfo.current ]
386 
387 _exit:
388   //---- restore interrupt
389   msr     cpsr_c, r4
390 
391   ldmfd  sp!, {r1-r4, lr}
392   bx     lr
393 }
394 #include <nitro/codereset.h>
395 
396 /*---------------------------------------------------------------------------*
397   Name:         __PROFILE_EXIT
398 
399   Description:  exit of function in profiler
400 
401   Arguments:    None
402 
403   Returns:      None
404  *---------------------------------------------------------------------------*/
405 #include <nitro/code32.h>
__PROFILE_EXIT(void)406 asm void __PROFILE_EXIT( void )
407 {
408   stmfd  sp!, {r0-r3, lr}
409 
410 #ifndef SDK_NO_THREAD
411   //---- check if thread system not initialized
412   ldr    r0, =OSi_IsThreadInitialized
413   ldr    r0, [ r0, #0 ]
414   cmp    r0, #0
415   beq    _exit
416 #endif
417 
418   //---- disable interrupt
419   mrs    r3, cpsr
420   orr    r1, r3, #HW_PSR_IRQ_DISABLE
421   msr    cpsr_c, r1
422 
423   //---- check if functionCost not available
424   bl     OSi_GetFunctionCostInfo
425   mov    r1, r0
426   cmp    r1, #0
427   beq    _exit_ri
428 
429   //---- check if functionCost master enable
430   ldrh    r2, [ r1, #OSFunctionCostInfo.enable ]
431   cmp     r2, #0
432   beq     _exit_ri
433 
434   //---- get currentPtr of functionCost
435   ldr    r2, [ r1, #OSFunctionCostInfo.current ]  // r2 = currentPtr of trace
436   cmp    r2, #0
437   beq    _exit_ri
438 
439   //---- check if buffer is over limit
440   ldr    r0, [ r1, #OSFunctionCostInfo.limit ]
441   cmp    r2, r0
442   bpl    _exit_ri
443 
444   //---- store endmark
445   ldr    r0, =OSi_FUNCTIONCOST_EXIT_TAG
446   str    r0, [ r2, #OSFunctionCost.exit.tag ]
447 
448   //---- store time
449   stmfd  sp!, {r1-r3}
450   bl     OSi_GetTick_noProfile
451   ldmfd  sp!, {r1-r3}
452   str    r0, [ r2, #OSFunctionCost.exit.time ]
453 
454   //---- increment pointer
455   add    r2, r2, #OSi_SIZEOF_FUNCTIONCOST
456   str    r2, [ r1, #OSFunctionCostInfo.current ]
457 
458 _exit_ri:
459   //---- restore interrupt
460   msr    cpsr_c, r3
461 
462 _exit:
463   ldmfd  sp!, {r0-r3, lr}
464   bx     lr
465 }
466 #include <nitro/codereset.h>
467 
468 //================================================================================
469 //              STATISTICS
470 //================================================================================
471 /*---------------------------------------------------------------------------*
472   Name:         OS_InitStatistics
473 
474   Description:  initialize statistics buffer
475 
476   Arguments:    statBuf  pointer to statistics buffer
477                 size     size of statBuf
478 
479   Returns:      None
480  *---------------------------------------------------------------------------*/
481 #pragma profile off
OS_InitStatistics(void * statBuf,u32 size)482 void OS_InitStatistics(void *statBuf, u32 size)
483 {
484     OSFunctionCostStatisticsInfo *infoPtr = statBuf;
485     u32    *p;
486 
487     if (!infoPtr || size <= OSi_STATISTICS_LEAST_SIZE)
488     {
489         return;
490     }
491 
492     //---- buffersize
493     infoPtr->size = ((size - OSi_STATISTICS_SIZEOF_HEADERPART) / sizeof(OSFunctionCostStatistics))
494         * sizeof(OSFunctionCostStatistics) + OSi_STATISTICS_SIZEOF_HEADERPART;
495     infoPtr->limit = (OSFunctionCostStatistics *)((u32)infoPtr + infoPtr->size);
496 
497     p = (u32 *)infoPtr->array;
498     while ((u32)p < (u32)infoPtr->limit)
499     {
500         *p++ = 0;
501     }
502 
503     //---- for check overflowing buffer limit
504     *(u32 *)((OSFunctionCostStatistics *)p - 1) = OSi_FUNCTIONCOST_CHECKNUM_BUFFER;
505 }
506 
507 #pragma profile reset
508 
509 /*---------------------------------------------------------------------------*
510   Name:         OSi_SetStatistics
511 
512   Description:  modify result to statBuf
513 
514   Arguments:    statBuf    pointer to statistics buffer
515                 entry      OSFunctionCost pointer of entering function
516                 exit       OSFunctionCost pointer of exiting function
517 
518   Returns:      None
519  *---------------------------------------------------------------------------*/
520 #pragma profile off
OSi_SetStatistics(void * statBuf,OSFunctionCost * entry,OSFunctionCost * exit)521 static void OSi_SetStatistics(void *statBuf, OSFunctionCost *entry, OSFunctionCost *exit)
522 {
523     OSFunctionCostStatisticsInfo *infoPtr = statBuf;
524     OSFunctionCostStatistics *p = infoPtr->array;
525     u32     time;
526 
527     //---- calc cost
528     //    (variables are u32, so even if entry>exit, it's ok)
529     time = exit->exit.time - entry->entry.time;
530 
531 #ifdef OSi_FUNCTIONCOST_THREAD_INTERVAL
532     //---- consider for interval by switching thread
533     //     (maybe always time>interval)
534     time = (time > entry->entry.interval) ? (u32)(time - entry->entry.interval) : 0;
535 #endif
536 
537     while ((u32)p < (u32)infoPtr->limit)
538     {
539         if (!p->name)
540         {
541             p->name = entry->entry.name;
542             p->count = 1;
543             p->time = time;
544             break;
545         }
546 
547         if (p->name == entry->entry.name)
548         {
549             p->count++;
550             p->time += time;
551             break;
552         }
553         p++;
554     }
555 }
556 
557 #pragma profile reset
558 
559 /*---------------------------------------------------------------------------*
560   Name:         OS_CalcThreadStatistics
561 
562   Description:  calculate statistics to statBuf
563 
564   Arguments:    statBuf :  pointer to statistics buffer
565                 thread     thread to calculate.
566                            if current or no thread then specify NULL
567 
568   Returns:      None
569  *---------------------------------------------------------------------------*/
570 #pragma profile off
OS_CalcThreadStatistics(void * statBuf,OSThread * thread)571 void OS_CalcThreadStatistics(void *statBuf, OSThread *thread)
572 {
573     OSFunctionCostInfo *infoPtr;
574     OSFunctionCost *p, *array, *limit;
575 
576     if (!thread)
577     {
578         infoPtr = OSi_GetFunctionCostInfo();
579     }
580     else
581     {
582         infoPtr = (OSFunctionCostInfo *)(thread->profiler);
583     }
584     if (!infoPtr || !(limit = infoPtr->current))
585     {
586         return;
587     }
588 
589     p = array = (OSFunctionCost *)&(infoPtr->array);
590     while (p < limit)
591     {
592         u32     name = p->entry.name;
593 
594         if (name == OSi_FUNCTIONCOST_EXIT_TAG)
595         {
596             int     cnt = 0;
597             OSFunctionCost *bp = p - 1;
598 
599 
600 #if 0
601             //---- for debug
602             if (bp->entry.name == OSi_FUNCTIONCOST_EXIT_TAG)
603             {
604 #ifdef OSi_FUNCTIONCOST_THREAD_INTERVAL
605                 OS_TPrintf("----: %x %x\n", bp->entry.time, bp->entry.interval);
606 #else
607                 OS_TPrintf("----: %x\n", bp->entry.time);
608 #endif
609             }
610             else
611             {
612 #ifdef OSi_FUNCTIONCOST_THREAD_INTERVAL
613                 OS_TPrintf("%s: %x %x\n", bp->entry.name, bp->entry.time, bp->entry.interval);
614 #else
615                 OS_TPrintf("%s: %x\n", bp->entry.name, bp->entry.time);
616 #endif
617             }
618 #endif
619 
620 
621             while (bp >= array)
622             {
623                 if (bp->entry.name == OSi_FUNCTIONCOST_EXIT_TAG)
624                 {
625                     cnt++;
626                 }
627                 else
628                 {
629                     if (--cnt < 0)
630                     {
631                         OSi_SetStatistics(statBuf, bp, p);
632                         break;
633                     }
634                 }
635                 bp--;
636             }
637         }
638         else
639         {
640             if (!name)
641                 continue;
642         }
643         p++;
644     }
645 
646     //---- clear buffer
647     OSi_ClearThreadFunctionCostBuffer(thread);
648 }
649 
650 #pragma profile reset
651 
652 /*---------------------------------------------------------------------------*
653   Name:         OS_CheckStatisticsBuffer
654 
655   Description:  check if statistics buffer overflows the limit.
656 
657   Arguments:    None
658 
659   Returns:      FALSE if overflowed. TRUE if not
660  *---------------------------------------------------------------------------*/
661 #ifndef OS_NO_FUNCTIONCOST
662 #pragma profile off
OS_CheckStatisticsBuffer(void * statBuf)663 BOOL OS_CheckStatisticsBuffer(void *statBuf)
664 {
665     OSFunctionCostStatisticsInfo *infoPtr = statBuf;
666 
667     if (*(u32 *)(infoPtr->limit - 1) != OSi_FUNCTIONCOST_CHECKNUM_BUFFER)
668     {
669         //OS_TPrintf("OVER!\n");
670         return FALSE;
671     }
672 
673     return TRUE;
674 }
675 
676 #pragma profile reset
677 #endif
678 
679 //================================================================================
680 //              DUMP
681 //================================================================================
682 /*---------------------------------------------------------------------------*
683   Name:         OS_DumpStatistics
684 
685   Description:  dump statistics of functionCost
686 
687   Arguments:    statBuf  buffer for statistics
688 
689   Returns:      None
690  *---------------------------------------------------------------------------*/
691 #pragma profile off
OS_DumpStatistics(void * statBuf)692 void OS_DumpStatistics(void *statBuf)
693 {
694     OSFunctionCostStatisticsInfo *infoPtr = statBuf;
695     OSFunctionCostStatistics *p = infoPtr->array;
696     BOOL    displayed = FALSE;
697 
698 #ifdef SDK_NO_THREAD
699     return;
700 #endif
701 
702     OS_TPrintf("---- functionCost statistics\n");
703 
704     while ((u32)p < (u32)infoPtr->limit)
705     {
706         // not output buffer check number
707         if (p->name && (p->name != OSi_FUNCTIONCOST_CHECKNUM_BUFFER))
708         {
709             displayed = TRUE;
710             OS_TPrintf("%s: count %d, cost %lld\n", p->name, p->count, p->time);
711         }
712 
713         p++;
714     }
715 
716     if (!displayed)
717     {
718         OS_TPrintf("no data\n");
719     }
720 }
721 
722 #pragma profile reset
723 
724 
725 /*---------------------------------------------------------------------------*
726   Name:         OSi_CalcThreadInterval
727 
728   Description:  calculate interval from save context to load context
729                 for functionCost profiler.
730                 destroy r0-r3 registers
731 
732   Arguments:    saveThread     pointer to saving thread
733                 loadThread     pointer to loading thread
734 
735   Returns:      None
736  *---------------------------------------------------------------------------*/
737 #include <nitro/code32.h>
738 #pragma profile off
OSi_CalcThreadInterval(register OSThread * saveThread,register OSThread * loadThread)739 static asm void OSi_CalcThreadInterval( register OSThread* saveThread, register OSThread* loadThread )
740 {
741 #pragma unused( saveThread, loadThread )
742 #ifndef SDK_NO_THREAD
743 #ifdef OSi_FUNCTIONCOST_THREAD_INTERVAL
744 
745     stmfd     sp!, {lr}
746 
747     //==== about saving thread
748     //---- check if functionCost not available
749     cmp     r0, #0                                    // r0 = saving thread
750     beq     _skip_saveThread
751     ldr     r2, [ r0, #OSThread.profiler ]            // r2 = functionCostInfo
752     cmp     r2, #0
753     beq     _skip_saveThread
754 
755     //---- check if functionCost master enable
756     ldrh    r3, [ r2, #OSFunctionCostInfo.enable ]    // r3 = master enable
757     cmp     r3, #0
758     beq     _skip_saveThread
759 
760     //---- store current time as break time
761     stmfd  sp!, {r1-r3}
762     bl     OSi_GetTick_noProfile                      // r0 = currentTime
763     ldmfd  sp!, {r1-r3}
764     str     r0, [ r2, #OSFunctionCostInfo.breakTime ]
765 
766 _skip_saveThread:
767 
768     //==== about loading thread
769     //---- check if functionCost not available
770     cmp     r1, #0                                    // r1 = loadingThread
771     beq     _skip_loadThread
772     ldr     r2, [ r1, #OSThread.profiler ]            // r2 = functionCostInfo
773     cmp     r2, #0
774     beq     _skip_loadThread
775 
776     //---- check if functionCost master enable
777     ldrh    r3, [ r2, #OSFunctionCostInfo.enable ]    // r3 = master enable
778     cmp     r3, #0
779     beq     _skip_loadThread
780 
781     //---- get currentPtr of functionCost
782     ldr     r3, [ r2, #OSFunctionCostInfo.current ]   // r3 = currentPtr of trace
783     cmp     r3, #0
784     beq     _skip_loadThread
785 
786     sub     r1, r3, #OSi_SIZEOF_FUNCTIONCOST          // r1 = previous Ptr
787 
788     //---- check if buffer is below array
789     add     r0, r2, #OSFunctionCostInfo.array[0]      // r0 = array Ptr
790     cmp     r1, r0
791     bmi     _skip_loadThread
792 
793     //---- store current time as break time
794     stmfd  sp!, {r1-r3}
795     bl     OSi_GetTick_noProfile                      // r0 = currentTime
796     ldmfd  sp!, {r1-r3}
797     ldr     r3, [ r2, #OSFunctionCostInfo.breakTime ] // r3 = breakTime
798     sub     r3, r0, r3                                // r3 = currentTime - breakTime = interval
799 
800     ldr     r0, [ r1, #OSFunctionCost.entry.interval ]      // add interval
801     add     r0, r0, r3
802     str     r0, [ r1, #OSFunctionCost.entry.interval ]
803 
804 _skip_loadThread:
805 
806     ldmfd   sp!, {lr}
807 #endif // ifdef OSi_FUNCTIONCOST_THREAD_INTERVAL
808 
809     bx      lr
810 
811 #endif // ifndef SDK_NO_THREAD
812 }
813 #pragma profile reset
814 #include <nitro/codereset.h>
815 
816 
817 #endif // ifdef OS_NO_FUNCTIONCOST
818 #endif // defined(OS_PROFILE_AVAILABLE) && defined(OS_PROFILE_FUNCTION_COST)
819