OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [newlib-1.17.0/] [newlib/] [libc/] [machine/] [spu/] [spu-gmon.c] - Blame information for rev 407

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 148 jeremybenn
/*
2
(C) Copyright IBM Corp. 2008
3
 
4
All rights reserved.
5
 
6
Redistribution and use in source and binary forms, with or without
7
modification, are permitted provided that the following conditions are met:
8
 
9
* Redistributions of source code must retain the above copyright notice,
10
this list of conditions and the following disclaimer.
11
* Redistributions in binary form must reproduce the above copyright
12
notice, this list of conditions and the following disclaimer in the
13
documentation and/or other materials provided with the distribution.
14
* Neither the name of IBM nor the names of its contributors may be
15
used to endorse or promote products derived from this software without
16
specific prior written permission.
17
 
18
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
POSSIBILITY OF SUCH DAMAGE.
29
 
30
Author: Ken Werner <ken.werner@de.ibm.com>
31
*/
32
 
33
#include <stdio.h>
34
#include <stdlib.h>
35
#include <string.h>
36
#include <unistd.h>
37
#include <sys/types.h>
38
#include <sys/stat.h>
39
#include <sys/uio.h>
40
#include <fcntl.h>
41
#include <ea.h>
42
#include <spu_intrinsics.h>
43
#include <spu_mfcio.h>
44
#include <spu_timer.h>
45
#include <limits.h>
46
 
47
/* Magic cookie.  */
48
#define GMON_MAGIC_COOKIE "gmon"
49
 
50
/* Version number.  */
51
#define GMON_VERSION 1
52
 
53
/* Fraction of text space to allocate for histogram counters.  */
54
#define HISTFRACTION 4
55
 
56
/* Histogram counter type.  */
57
#define HISTCOUNTER unsigned short
58
 
59
/* Fraction of text space to allocate for "from" hash buckets. HASHFRACTION is
60
   based on the minimum number of bytes of separation between two subroutine
61
   call points in the object code.  */
62
#define HASHFRACTION 4
63
 
64
/* Percent of text space to allocate for tostructs with a minimum.  */
65
#define ARCDENSITY 3
66
 
67
/* Minimal amount of arcs.  */
68
#define MINARCS 50
69
 
70
/* Rounding macros.  */
71
#define ROUNDDOWN(x,y) (((x)/(y))*(y))
72
#define ROUNDUP(x,y)   ((((x)+(y)-1)/(y))*(y))
73
 
74
/* Sampling rate in Hertz.  */
75
#define SAMPLE_INTERVAL 100
76
 
77
/* Tag definitions for the gmon.out sub headers.  */
78
#define GMON_TAG_TIME_HIST 0
79
#define GMON_TAG_CG_ARC 1
80
 
81
struct tostruct
82
{
83
  uintptr_t selfpc;
84
  long count;
85
  unsigned short link;
86
};
87
 
88
struct gmon_hdr
89
{
90
  char cookie[4];
91
  int32_t version;
92
  char spare[3 * 4];
93
};
94
 
95
struct gmon_hist_hdr
96
{
97
  uintptr_t low_pc;
98
  uintptr_t high_pc;
99
  int32_t hist_size;
100
  int32_t prof_rate;
101
  char dimen[15];
102
  char dimen_abbrev;
103
} __attribute__ ((packed));
104
 
105
struct rawarc
106
{
107
  uintptr_t raw_frompc;
108
  uintptr_t raw_selfpc;
109
  long raw_count;
110
} __attribute__ ((packed));
111
 
112
/* start and end of the text section */
113
extern char _start;
114
extern char _etext;
115
 
116
/* froms are indexing tos */
117
static __ea unsigned short *froms;
118
static __ea struct tostruct *tos = 0;
119
static long tolimit = 0;
120
static uintptr_t s_lowpc = 0;
121
static uintptr_t s_highpc = 0;
122
static unsigned long s_textsize = 0;
123
 
124
static int fd;
125
static int hist_size;
126
static int timer_id;
127
 
128
void
129
__sample (int id)
130
{
131
  unsigned int pc;
132
  unsigned int pc_backup;
133
  off_t offset;
134
  unsigned short val;
135
 
136
  if (id != timer_id)
137
    return;
138
 
139
  /* Fetch program counter.  */
140
  pc = spu_read_srr0 () & ~3;
141
  pc_backup = pc;
142
  if (pc < s_lowpc || pc > s_highpc)
143
    return;
144
  pc -= (uintptr_t) & _start;
145
  offset = pc / HISTFRACTION * sizeof (HISTCOUNTER) + sizeof (struct gmon_hdr)
146
             + 1 + sizeof (struct gmon_hist_hdr);
147
 
148
  /* Read, increment and write the counter.  */
149
  if (pread (fd, &val, 2, offset) != 2)
150
    {
151
      perror ("can't read the histogram");
152
      return;
153
    }
154
  if (val < USHRT_MAX)
155
    ++val;
156
  if (pwrite (fd, &val, 2, offset) != 2)
157
    {
158
      perror ("can't write the histogram");
159
    }
160
}
161
 
162
static void
163
write_histogram (int fd)
164
{
165
  struct gmon_hist_hdr hist_hdr;
166
  u_char tag = GMON_TAG_TIME_HIST;
167
  hist_hdr.low_pc = s_lowpc;
168
  hist_hdr.high_pc = s_highpc;
169
  hist_hdr.hist_size = hist_size / sizeof (HISTCOUNTER); /* Amount of bins.  */
170
  hist_hdr.prof_rate = 100; /* Hertz.  */
171
  strncpy (hist_hdr.dimen, "seconds", sizeof (hist_hdr.dimen));
172
  hist_hdr.dimen_abbrev = 's';
173
  struct iovec iov[2] = {
174
    {&tag, sizeof (tag)},
175
    {&hist_hdr, sizeof (struct gmon_hist_hdr)}
176
  };
177
  if (writev (fd, iov, 2) != sizeof (struct gmon_hist_hdr) + sizeof (tag))
178
    perror ("can't write the histogram header");
179
 
180
  /* Skip the already written histogram data.  */
181
  lseek (fd, hist_size, SEEK_CUR);
182
}
183
 
184
static void
185
write_callgraph (int fd)
186
{
187
  int fromindex, endfrom;
188
  uintptr_t frompc;
189
  int toindex;
190
  struct rawarc rawarc;
191
  u_char tag = GMON_TAG_CG_ARC;
192
  endfrom = s_textsize / (HASHFRACTION * sizeof (*froms));
193
  for (fromindex = 0; fromindex < endfrom; ++fromindex)
194
    {
195
      if (froms[fromindex])
196
        {
197
          frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof (*froms));
198
          for (toindex = froms[fromindex]; toindex != 0;
199
               toindex = tos[toindex].link)
200
            {
201
              rawarc.raw_frompc = frompc;
202
              rawarc.raw_selfpc = tos[toindex].selfpc;
203
              rawarc.raw_count = tos[toindex].count;
204
              struct iovec iov[2] = {
205
                {&tag, sizeof (tag)},
206
                {&rawarc, sizeof (struct rawarc)}
207
              };
208
              if (writev (fd, iov, 2) != sizeof (tag) + sizeof (struct rawarc))
209
                perror ("can't write the callgraph");
210
            }
211
        }
212
    }
213
}
214
 
215
void
216
__mcleanup (void)
217
{
218
  struct gmon_hdr ghdr;
219
 
220
  /* Disable sampling.  */
221
  spu_timer_stop (timer_id);
222
  spu_timer_free (timer_id);
223
  spu_clock_stop ();
224
 
225
  /* Jump to the beginning of the gmon.out file.  */
226
  if (lseek (fd, 0, SEEK_SET) == -1)
227
    {
228
      perror ("Cannot seek to the beginning of the gmon.out file.");
229
      close (fd);
230
      return;
231
    }
232
 
233
  /* Write the gmon.out header.  */
234
  memset (&ghdr, '\0', sizeof (struct gmon_hdr));
235
  memcpy (&ghdr.cookie[0], GMON_MAGIC_COOKIE, sizeof (ghdr.cookie));
236
  ghdr.version = GMON_VERSION;
237
  if (write (fd, &ghdr, sizeof (struct gmon_hdr)) == -1)
238
    {
239
      perror ("Cannot write the gmon header to the gmon.out file.");
240
      close (fd);
241
      return;
242
    }
243
 
244
  /* Write the sampling buffer (histogram).  */
245
  write_histogram (fd);
246
 
247
  /* Write the call graph.  */
248
  write_callgraph (fd);
249
 
250
  close (fd);
251
}
252
 
253
void
254
__monstartup (void)
255
{
256
  s_lowpc =
257
    ROUNDDOWN ((uintptr_t) & _start, HISTFRACTION * sizeof (HISTCOUNTER));
258
  s_highpc =
259
    ROUNDUP ((uintptr_t) & _etext, HISTFRACTION * sizeof (HISTCOUNTER));
260
  s_textsize = s_highpc - s_lowpc;
261
 
262
  hist_size = s_textsize / HISTFRACTION * sizeof (HISTCOUNTER);
263
 
264
  /* Allocate froms.  */
265
  froms = malloc_ea (s_textsize / HASHFRACTION);
266
  if (froms == NULL)
267
    {
268
      fprintf (stderr, "Cannot allocate ea memory for the froms array.\n");
269
      return;
270
    }
271
  memset_ea (froms, 0, s_textsize / HASHFRACTION);
272
 
273
  /* Determine tolimit.  */
274
  tolimit = s_textsize * ARCDENSITY / 100;
275
  if (tolimit < MINARCS)
276
    tolimit = MINARCS;
277
 
278
  /* Allocate tos. */
279
  tos = malloc_ea (tolimit * sizeof (struct tostruct));
280
  if (tos == NULL)
281
    {
282
      fprintf (stderr, "Cannot allocate ea memory for the tos array.\n");
283
      return;
284
    }
285
  memset_ea (tos, 0, tolimit * sizeof (struct tostruct));
286
 
287
  /* Open the gmon.out file.  */
288
  fd = open ("gmon.out", O_RDWR | O_CREAT | O_TRUNC, 0644);
289
  if (fd == -1)
290
    {
291
      perror ("can't open gmon.out file");
292
      return;
293
    }
294
  /* Truncate the file up to the size where the histogram fits in.  */
295
  if (ftruncate (fd,
296
       sizeof (struct gmon_hdr) + 1 + sizeof (struct gmon_hist_hdr) + hist_size) ==
297
       -1)
298
    perror ("can't truncate the gmon.out file");
299
 
300
  /* Start the histogram sampler.  */
301
  spu_slih_register (MFC_DECREMENTER_EVENT, spu_clock_slih);
302
  timer_id = spu_timer_alloc (spu_timebase () / SAMPLE_INTERVAL,
303
                              __sample);
304
  spu_clock_start ();
305
  spu_timer_start (timer_id);
306
 
307
  atexit (__mcleanup);
308
}
309
 
310
void
311
__mcount_internal (uintptr_t frompc, uintptr_t selfpc)
312
{
313
  /* sefpc: the address of the function just entered.  */
314
  /* frompc: the caller of the function just entered.  */
315
  unsigned int mach_stat;
316
  __ea unsigned short *frompcindex;
317
  unsigned short toindex;
318
  __ea struct tostruct *top;
319
  __ea struct tostruct *prevtop;
320
 
321
  /* Save current state and disable interrupts.  */
322
  mach_stat = spu_readch(SPU_RdMachStat);
323
  spu_idisable ();
324
 
325
  /* Sanity checks.  */
326
  if (frompc < s_lowpc || frompc > s_highpc)
327
    goto done;
328
  frompc -= s_lowpc;
329
  if (frompc > s_textsize)
330
    goto done;
331
 
332
  /* frompc indexes into the froms array the value at that position indexes
333
     into the tos array.  */
334
  frompcindex = &froms[(frompc) / (HASHFRACTION * sizeof (*froms))];
335
  toindex = *frompcindex;
336
  if (toindex == 0)
337
    {
338
      /* First time traversing this arc link of tos[0] incremented.  */
339
      toindex = ++tos[0].link;
340
      /* Sanity check.  */
341
      if (toindex >= tolimit)
342
        {
343
          --tos[0].link;
344
          goto done;
345
        }
346
      /* Save the index into the froms array for the next time we traverse this arc.  */
347
      *frompcindex = toindex;
348
      top = &tos[toindex];
349
      /* Sets the address of the function just entered.  */
350
      top->selfpc = selfpc;
351
      top->count = 1;
352
      top->link = 0;
353
      goto done;
354
    }
355
 
356
  /* toindex points to a tostruct */
357
  top = &tos[toindex];
358
  if (top->selfpc == selfpc)
359
    {
360
      /* The arc is at front of the chain. This is the most common case.  */
361
      top->count++;
362
      goto done;
363
    }
364
 
365
  /* top->selfpc != selfpc
366
     The pc we have got is not the pc we already stored (i.e. multiple function
367
     calls to the same fuction within a function. The arc is not at front of
368
     the chain.  */
369
  for (;;)
370
    {
371
      if (top->link == 0)
372
        {
373
          /* We are at the end of the chain and selfpc was not found. Thus we create
374
             a new tostruct and link it to the head of the chain.  */
375
          toindex = ++tos[0].link;
376
          /* Sanity check.  */
377
          if (toindex >= tolimit)
378
            {
379
              --tos[0].link;
380
              goto done;
381
            }
382
          top = &tos[toindex];
383
          top->selfpc = selfpc;
384
          top->count = 1;
385
          /* Link back to the old tos entry.  */
386
          top->link = *frompcindex;
387
          /* Store a link to the new top in the froms array which makes the
388
             current tos head of the chain.  */
389
          *frompcindex = toindex;
390
          goto done;
391
        }
392
      else
393
        {
394
          /* Otherwise check the next arc on the chain.  */
395
          prevtop = top;
396
          top = &tos[top->link];
397
          if (top->selfpc == selfpc)
398
            {
399
              /* selfpc matches; increment its count.  */
400
              top->count++;
401
              /* Move it to the head of the chain.  */
402
              /* Save previous tos index.  */
403
              toindex = prevtop->link;
404
              /* Link the former to to the current tos.  */
405
              prevtop->link = top->link;
406
              /* Link back to the old tos entry.  */
407
              top->link = *frompcindex;
408
              /* Store a link to the new top in the froms array which makes the
409
                 current tos head of the chain.  */
410
              *frompcindex = toindex;
411
              goto done;
412
            }
413
        }
414
    }
415
done:
416
  /* Enable interrupts if necessary.  */
417
  if (__builtin_expect (mach_stat & 1, 0))
418
    spu_ienable ();
419
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.