1 /*
2 Language Independent Runtime Library
3
4 Copyright 1983-2003 by Green Hills Software,Inc.
5
6 This program is the property of Green Hills Software, Inc,
7 its contents are proprietary information and no part of it
8 is to be disclosed to anyone except employees of Green Hills
9 Software, Inc., or as agreed in writing signed by the President
10 of Green Hills Software, Inc.
11 */
12
13 /*
14 * Target Driven Timer-Based Profiling Framework:
15 * - This file provides sample implementations of a timer-interrupt driven
16 * profiler using the debug server supported MANPROF system call.
17 * - To use timer-based profiling:
18 * 1) provide implementations of the following low-level macros for your
19 * board (see ppc_manprf.h, arm_manprf.h for examples) :
20 * TICKS_PER_SEC
21 * TIMER_INIT
22 * GET_EPC
23 * CLEAR_TIMER_INTERRUPT
24 * ENABLE_TIMER_INTERRUPT
25 * 2) rebuild ind_manprf.o(libsys.a).
26 * 3) relink your standalone application using the -timer_profile driver
27 * option (or "-u __ghs_manprf_timer_handler" linker option).
28 * 4) enable profiling in MULTI before running your application.
29 */
30 #if defined(EMBEDDED) && defined(__ELF)
31
32 #include "indsyscl.h"
33 #include "indos.h"
34 #include "ind_exit.h"
35 #include <stdint.h>
36
37 #if defined(__THUMB) && !defined(__THUMB2_AWARE)
38 /* This module should not be compiled in Thumb mode */
39 #pragma ghs nothumb
40 #endif /* __THUMB */
41
42 /* extern prototypes (needed by ppc_manprf.h) */
43 #if defined(__ppc)
44 #if defined(__SPE__) || defined(__ppc440) || defined(__ppc440ep) || \
45 defined(__ppc440gx) || defined(__ppc440gr)
46 /* Force the interrupt handler to be 16-byte aligned. */
47 #pragma alignfunc(16)
48 #endif
49 #endif
50 __interrupt void __ghs_manprf_timer_handler(void);
51
52 /* Pull in the low-level (asm) macro implementations */
53 #if defined(__ppc)
54 #include "ppc_manprf.h"
55 #elif defined(__mips)
56 #include "mip_manprf.h"
57 #elif defined(__ARM)
58 #include "arm_manprf.h"
59 #elif defined(__ColdFire)
60 #include "coldfire_manprf.h"
61 #elif defined(__ADSPBLACKFIN__)
62 #include "bf_manprf.h"
63 #else
64 /* you will need to implement the following items
65 * for your processor / board. see ppc_manprf.h
66 * and arm_manprf.h for examples */
67 #define NO_BUILD_MANPRF 1
68 #endif
69
70 #if !defined(NO_BUILD_MANPRF)
71
72 static void __ghs_manprf_end(void);
73
74 /* FREQUENCY: number of times per second the PC is sampled.
75 * default: 60 Hz. you may adjust this as necessary. */
76 #define FREQUENCY 60
77 /* PROFBUFSIZE: number of samples the static PC sample buffer holds.
78 * default: 120 samples. you may adjust this as necessary according
79 * to your memory resources and/or frequency at which you want to
80 * send the profiling information to the debug server. */
81 #define PROFBUFSIZE 120
82
83 #if __PTR_BIT == 64
84 typedef uint64_t address;
85 #else
86 typedef uint32_t address;
87 #endif
88 /* timer_value: number of cycles between timer interrupts. */
89 static int timer_value = 1;
90 /* PC Sample Buffer:
91 * sample_count: number of used entries in profile_buffer PC sample buffer */
92 static int sample_count = 0;
93 /* profile_buffer: PC sample static buffer */
94 static address profile_buffer[PROFBUFSIZE];
95
96
97 /***************************************************************************
98 * __ghs_manprf_init() is called from __ghs_ind_crt1() when this module
99 * is linked into the program.
100 * - registers an 'at exit' callback
101 * - compute the value to use in the counter/compare or decrementer
102 * - initialize the timer
103 * - initialize profiling
104 * - enable the timer interrupt
105 ***************************************************************************/
106 #pragma ghs startnoinline
__ghs_manprf_init(void)107 void __ghs_manprf_init(void)
108 {
109 /* Request that this variable be allocated to a register so only
110 * the register case need be handled by asm macros */
111 register unsigned int counter;
112 /* register with low level _exit() */
113 static struct __GHS_AT_EXIT gae;
114 if (!gae.func) {
115 gae.func = __ghs_manprf_end;
116 __ghs_at_exit(&gae);
117 }
118 /* Calculate clock cycle delay required to produce a timer interrupt at
119 * specified frequency in Hz. */
120 counter = timer_value = TICKS_PER_SEC() / FREQUENCY;
121 /* Set initial count and compare values (or decrementer) */
122 TIMER_INIT(counter);
123 /* Call SYSCALL_MANPROF with buf=NULL, cnt=frequency of sample rate,
124 * to initialize sample frequency. */
125 __ghs_syscall(SYSCALL_MANPROF, NULL, FREQUENCY);
126 /* Enable the timer interrupt. */
127 ENABLE_TIMER_INTERRUPT();
128 }
129 #pragma ghs endnoinline
130
131 /***************************************************************************
132 * flush_buffer() sends the PC sample buffer to the debug server using
133 * system call emulation.
134 * - invoke SYSCALL_MANPROF to send the PC samples to the debug server.
135 * - clear the PC sample buffer.
136 ***************************************************************************/
flush_buffer(void)137 static void flush_buffer(void)
138 {
139 /* send profile count data to debug server using syscall emulation */
140 __ghs_syscall(SYSCALL_MANPROF, profile_buffer, sample_count);
141 /* clear the PC sample buffer */
142 sample_count = 0;
143 }
144
145 /***************************************************************************
146 * __ghs_manprf_end() sends any remaining PC samples at program termination.
147 ***************************************************************************/
__ghs_manprf_end(void)148 static void __ghs_manprf_end(void)
149 {
150 if (sample_count > 0) flush_buffer();
151 }
152
153 /***************************************************************************
154 * __ghs_manprf_timer_handler() is the timer interrupt handler.
155 * you should include code that jumps to this handler from within the
156 * appropriate interrupt vector entry.
157 * - collect PC samples
158 * - when buffer is full, send data to the debug server using system call
159 * emulation.
160 * - reset the timer interrupt.
161 ***************************************************************************/
162 #if defined(__ppc)
163 #if defined(__SPE__) || defined(__ppc440) || defined(__ppc440ep) || \
164 defined(__ppc440gx) || defined(__ppc440gr)
165 /* Force the interrupt handler to be 16-byte aligned. */
166 #pragma alignfunc(16)
167 #endif
168 #endif
__ghs_manprf_timer_handler(void)169 __interrupt void __ghs_manprf_timer_handler(void)
170 {
171 /* General Notes:
172 * Your target may or may not have separate vectors per each
173 * interrupt. Here we assume that the timer is the only interrupt
174 * handled by this ISR.
175 * Normally during an ISR, you may want to re-enable interrupts after
176 * saving critical state. Here, we do not re-enable interrupts
177 * (until return).
178 */
179
180 /* make sure this gets into a register so that only
181 * the register case need be handled by (asm) macros */
182 register unsigned int counter;
183 /* sample the current program counter */
184 profile_buffer[sample_count++] = GET_EPC();
185 /* if we have filled the PC sample buffer, send its contents to the
186 * debug server */
187 if (sample_count >= PROFBUFSIZE) flush_buffer();
188 /* reset the decrementer/counter so that the timer interrupt fires
189 * at the desired time interval */
190 counter = timer_value;
191 /* re-initialize the timer (or decrementer) */
192 TIMER_INIT(counter);
193 /* clear the timer interrupt so it can fire again */
194 CLEAR_TIMER_INTERRUPT();
195 }
196
197 #endif /* !defined(NO_BUILD_MANPRF) */
198
199 #endif /* EMBEDDED && __ELF */
200