PS2SDK
PS2 Homebrew Libraries
prof.c
1 /*
2 # _____ ___ ____ ___ ____
3 # ____| | ____| | | |____|
4 # | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5 #-----------------------------------------------------------------------
6 # Copyright 2001-2004, ps2dev - http://www.ps2dev.org
7 # Licenced under Academic Free License version 2.0
8 # Review ps2sdk README & LICENSE files for further details.
9 */
10 
11 #include <stdlib.h>
12 #include <malloc.h>
13 #include <stdint.h>
14 #include <stdio.h>
15 #include <string.h>
16 
17 #define GMON_PROF_ON 0
18 #define GMON_PROF_BUSY 1
19 #define GMON_PROF_ERROR 2
20 #define GMON_PROF_OFF 3
21 
22 #define GMONVERSION 0x00051879
23 
24 #include <kernel.h>
25 #include <timer_alarm.h>
26 #include <ps2prof.h>
27 
29 struct gmonhdr
30 {
31  int lpc; /* lowest pc address */
32  int hpc; /* highest pc address */
33  int ncnt; /* size of samples + size of header */
34  int version; /* version number */
35  int profrate; /* profiling clock rate */
36  int resv[3]; /* reserved */
37 };
38 
40 struct rawarc
41 {
42  unsigned int frompc;
43  unsigned int selfpc;
44  unsigned int count;
45 };
46 
48 struct gmonparam
49 {
50  int state;
51  unsigned int lowpc;
52  unsigned int highpc;
53  unsigned int textsize;
54  unsigned int hashfraction;
55 
56  int narcs;
57  struct rawarc *arcs;
58 
59  int nsamples;
60  unsigned int *samples;
61 
62  int timerId;
63 
64  unsigned int pc;
65 };
66 
68 static struct gmonparam gp;
69 
71 #define HISTFRACTION 4
72 
74 #define SAMPLE_FREQ 1000
75 
77 extern int _ftext;
78 extern int _etext;
79 
82 __attribute__((__no_instrument_function__, __no_profile_instrument_function__))
83 static uint64_t timer_handler(int id, uint64_t scheduled_time, uint64_t actual_time, void *arg, void *pc_value)
84 {
85  struct gmonparam *current_gp = (struct gmonparam *)arg;
86 
87  unsigned int frompc = current_gp->pc;
88 
89  if (current_gp->state == GMON_PROF_ON) {
90  /* call might come from stack */
91  if (frompc >= current_gp->lowpc && frompc <= current_gp->highpc) {
92  int e = (frompc - current_gp->lowpc) / current_gp->hashfraction;
93  current_gp->samples[e]++;
94  }
95  }
96 
97 
98  current_gp->timerId = iSetTimerAlarm(USec2TimerBusClock(SAMPLE_FREQ), &timer_handler, arg);
99  return 0;
100 }
101 
109 __attribute__((__no_instrument_function__, __no_profile_instrument_function__))
110 void __gprof_init()
111 {
112  memset(&gp, '\0', sizeof(gp));
113  gp.state = GMON_PROF_ON;
114  gp.lowpc = (unsigned int)&_ftext;
115  gp.highpc = (unsigned int)&_etext;
116  gp.textsize = gp.highpc - gp.lowpc;
117  gp.hashfraction = HISTFRACTION;
118 
119  gp.narcs = (gp.textsize + gp.hashfraction - 1) / gp.hashfraction;
120  gp.arcs = (struct rawarc *)malloc(sizeof(struct rawarc) * gp.narcs);
121  if (gp.arcs == NULL) {
122  gp.state = GMON_PROF_ERROR;
123  return;
124  }
125 
126  gp.nsamples = (gp.textsize + gp.hashfraction - 1) / gp.hashfraction;
127  gp.samples = (unsigned int *)malloc(sizeof(unsigned int) * gp.nsamples);
128  if (gp.samples == NULL) {
129  free(gp.arcs);
130  gp.arcs = 0;
131  gp.state = GMON_PROF_ERROR;
132  return;
133  }
134 
135  memset((void *)gp.arcs, '\0', gp.narcs * (sizeof(struct rawarc)));
136  memset((void *)gp.samples, '\0', gp.nsamples * (sizeof(unsigned int)));
137 
138 
139  gp.state = GMON_PROF_ON;
140  gp.timerId = SetTimerAlarm(USec2TimerBusClock(SAMPLE_FREQ), &timer_handler, &gp);
141  if (gp.timerId < 0) {
142  free(gp.arcs);
143  free(gp.samples);
144  gp.arcs = 0;
145  gp.samples = 0;
146  gp.state = GMON_PROF_ERROR;
147  return;
148  }
149 }
150 
151 __attribute__((__no_instrument_function__, __no_profile_instrument_function__))
152 void gprof_start(void)
153 {
154  // There is already a profiling session running, let's stop it and ignore the result
155  if (gp.state == GMON_PROF_ON) {
156  gprof_stop(NULL, 0);
157  }
158  __gprof_init();
159 }
160 
161 __attribute__((__no_instrument_function__, __no_profile_instrument_function__))
162 void gprof_stop(const char *filename, int should_dump)
163 {
164  FILE *fp;
165  int i;
166  struct gmonhdr hdr;
167 
168  if (gp.state != GMON_PROF_ON) {
169  /* profiling was disabled anyway */
170  return;
171  }
172 
173  /* disable profiling before we make plenty of libc calls */
174  gp.state = GMON_PROF_OFF;
175 
176  ReleaseTimerAlarm(gp.timerId);
177 
178  if (should_dump) {
179  fp = fopen(filename, "wb");
180  hdr.lpc = gp.lowpc;
181  hdr.hpc = gp.highpc;
182  hdr.ncnt = sizeof(hdr) + (sizeof(unsigned int) * gp.nsamples);
183  hdr.version = GMONVERSION;
184  hdr.profrate = SAMPLE_FREQ;
185  hdr.resv[0] = 0;
186  hdr.resv[1] = 0;
187  hdr.resv[2] = 0;
188  fwrite(&hdr, 1, sizeof(hdr), fp);
189  fwrite(gp.samples, gp.nsamples, sizeof(unsigned int), fp);
190 
191  for (i = 0; i < gp.narcs; i++) {
192  if (gp.arcs[i].count > 0) {
193  fwrite(gp.arcs + i, sizeof(struct rawarc), 1, fp);
194  }
195  }
196 
197  fclose(fp);
198  }
199 
200  // free memory
201  free(gp.arcs);
202  free(gp.samples);
203 }
204 
209 __attribute__((__no_instrument_function__, __no_profile_instrument_function__))
210 void __gprof_cleanup()
211 {
212  gprof_stop("gmon.out", 1);
213 }
214 
224 __attribute__((__no_instrument_function__, __no_profile_instrument_function__))
225 void __mcount(unsigned int frompc, unsigned int selfpc)
226 {
227  int e;
228  struct rawarc *arc;
229 
230  if (gp.state != GMON_PROF_ON) {
231  /* returned off for some reason */
232  return;
233  }
234 
235  frompc = frompc & 0x0FFFFFFF;
236  selfpc = selfpc & 0x0FFFFFFF;
237 
238  /* call might come from stack */
239  if (frompc >= gp.lowpc && frompc <= gp.highpc) {
240  gp.pc = selfpc;
241  e = (frompc - gp.lowpc) / gp.hashfraction;
242  arc = gp.arcs + e;
243  arc->frompc = frompc;
244  arc->selfpc = selfpc;
245  arc->count++;
246  }
247 }
kernel.h
gmonhdr
Definition: prof.c:29
gmonparam
Definition: prof.c:48
__attribute__
typedef __attribute__
Definition: tlbfunc.c:60
stdio.h
rawarc
Definition: prof.c:40
stdlib.h