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