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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [or1ksim/] [profiler.c] - Blame information for rev 464

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

Line No. Rev Author Line
1 19 jeremybenn
/* profiler.c -- profiling utility
2
 
3
   Copyright (C) 2001 Marko Mlinar, markom@opencores.org
4
   Copyright (C) 2008 Embecosm Limited
5
 
6
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
7
 
8
   This file is part of Or1ksim, the OpenRISC 1000 Architectural Simulator.
9
 
10
   This program is free software; you can redistribute it and/or modify it
11
   under the terms of the GNU General Public License as published by the Free
12
   Software Foundation; either version 3 of the License, or (at your option)
13
   any later version.
14
 
15
   This program is distributed in the hope that it will be useful, but WITHOUT
16
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
18
   more details.
19
 
20
   You should have received a copy of the GNU General Public License along
21
   with this program.  If not, see <http://www.gnu.org/licenses/>.  */
22
 
23
/* This program is commented throughout in a fashion suitable for processing
24
   with Doxygen. */
25
 
26
/* Command line utility, that displays profiling information, generated
27
   by or1ksim. (use profile command interactively, when running or1ksim, or
28
   separate psim command).  */
29
 
30 100 julius
#define PROF_DEBUG 0
31 19 jeremybenn
 
32
/* Autoconf and/or portability configuration */
33
#include "config.h"
34
#include "port.h"
35
 
36
/* Package includes */
37
#include "profiler.h"
38
#include "sim-config.h"
39
#include "argtable2.h"
40
 
41
/*! Maximum stack frames that can be profiled */
42 100 julius
#define MAX_STACK  262144
43 19 jeremybenn
 
44
/*! Data structure representing information about a stack frame */
45
struct stack_struct
46
{
47
  unsigned int  addr;      /*!< Function address */
48
  unsigned int  cycles;    /*!< Cycles of func start; subfuncs added later */
49
  unsigned int  raddr;     /*!< Return address */
50
  char          name[33];  /*!< Name of the function */
51
};
52
 
53
/*! Global: data about functions */
54
struct func_struct  prof_func[MAX_FUNCS];
55
 
56
/*! Global: total number of functions */
57
int  prof_nfuncs = 0;
58
 
59
/*! Global: current cycles */
60
int  prof_cycles = 0;
61
 
62
/*! Representation of the stack */
63
static struct stack_struct  stack[MAX_STACK];
64
 
65
/*! Current depth */
66
static int  nstack = 0;
67
 
68
/*! Max depth */
69
static int  maxstack = 0;
70
 
71
/*! Number of total calls */
72
static int  ntotcalls = 0;
73
 
74
/*! Number of covered calls */
75
static int  nfunccalls = 0;
76
 
77
/*! Whether we are in cumulative mode */
78
static int  cumulative = 0;
79
 
80
/*! Whether we should not report warnings */
81
static int  quiet = 0;
82
 
83
/*! File to read from */
84
static FILE *fprof = 0;
85
 
86
 
87
/*---------------------------------------------------------------------------*/
88
/*! Acquire data from profiler file
89
 
90
  @param[in] fprofname   Data file to analyse
91
 
92
  @return  0 on success, return code otherwise                               */
93
/*---------------------------------------------------------------------------*/
94
int
95
prof_acquire (const char *fprofname)
96
{
97
  int line = 0;
98
  int reopened = 0;
99
 
100
  if (runtime.sim.fprof)
101
    {
102
      fprof = runtime.sim.fprof;
103
      reopened = 1;
104 100 julius
      if (PROF_DEBUG) printf("reopened=1\n");
105 19 jeremybenn
      rewind (fprof);
106
    }
107
  else
108
    fprof = fopen (fprofname, "rt");
109
 
110
  if (!fprof)
111
    {
112
      fprintf (stderr, "Cannot open profile file: %s\n", fprofname);
113
      return 1;
114
    }
115 100 julius
  int ctr =0;
116 19 jeremybenn
  while (1)
117
    {
118 100 julius
      if (PROF_DEBUG) printf("%d ",ctr++);
119 19 jeremybenn
      char dir = fgetc (fprof);
120
      line++;
121
      if (dir == '+')
122
        {
123
          if (fscanf
124
              (fprof, "%08X %08X %08X %s\n", &stack[nstack].cycles,
125
               &stack[nstack].raddr, &stack[nstack].addr,
126
               &stack[nstack].name[0]) != 4)
127
            fprintf (stderr, "Error reading line #%i\n", line);
128
          else
129
            {
130
              prof_cycles = stack[nstack].cycles;
131
              nstack++;
132 100 julius
              if (PROF_DEBUG) printf("+ 0x%.8x nstack %d\n",stack[nstack-1].raddr, nstack);
133 19 jeremybenn
              if (nstack > maxstack)
134
                maxstack = nstack;
135
            }
136
          ntotcalls++;
137
        }
138
      else if (dir == '-')
139
        {
140
          struct stack_struct s;
141
          if (fscanf (fprof, "%08X %08X\n", &s.cycles, &s.raddr) != 2)
142
            fprintf (stderr, "Error reading line #%i\n", line);
143
          else
144
            {
145
              int i;
146
              prof_cycles = s.cycles;
147 100 julius
              if (PROF_DEBUG) printf("- 0x%.8x nstack %d\n",s.raddr ,nstack);
148 19 jeremybenn
              for (i = nstack - 1; i >= 0; i--)
149
                if (stack[i].raddr == s.raddr)
150
                  break;
151
              if (i >= 0)
152
                {
153
                  /* pop everything above current from stack,
154
                     if more than one, something went wrong */
155
                  while (nstack > i)
156
                    {
157
                      int j;
158
                      long time;
159
                      nstack--;
160
                      time = s.cycles - stack[nstack].cycles;
161
                      if (!quiet && time < 0)
162
                        {
163
                          fprintf (stderr,
164
                                   "WARNING: Negative time at %s (return addr = %08X).\n",
165
                                   stack[i].name, stack[i].raddr);
166
                          time = 0;
167
                        }
168
 
169
                      /* Whether in normal mode, we must substract called function from execution time.  */
170
                      if (!cumulative)
171
                        for (j = 0; j < nstack; j++)
172
                          stack[j].cycles += time;
173
 
174
                      if (!quiet && i != nstack)
175
                        fprintf (stderr,
176
                                 "WARNING: Missaligned return call for %s (%08X) (found %s @ %08X), closing.\n",
177
                                 stack[nstack].name, stack[nstack].raddr,
178
                                 stack[i].name, stack[i].raddr);
179
 
180
                      for (j = 0; j < prof_nfuncs; j++)
181
                        if (stack[nstack].addr == prof_func[j].addr)
182
                          {     /* function exists, append. */
183
                            prof_func[j].cum_cycles += time;
184
                            prof_func[j].calls++;
185
                            nfunccalls++;
186
                            break;
187
                          }
188
                      if (j >= prof_nfuncs)
189
                        {       /* function does not yet exist, create new. */
190
                          prof_func[prof_nfuncs].cum_cycles = time;
191
                          prof_func[prof_nfuncs].calls = 1;
192
                          nfunccalls++;
193
                          prof_func[prof_nfuncs].addr = stack[nstack].addr;
194
                          strcpy (prof_func[prof_nfuncs].name,
195
                                  stack[nstack].name);
196
                          prof_nfuncs++;
197
                        }
198
                    }
199
                }
200
              else if (!quiet)
201
                fprintf (stderr,
202
                         "WARNING: Cannot find return call for (%08X), ignoring.\n",
203
                         s.raddr);
204
            }
205
        }
206
      else
207
        break;
208
    }
209
 
210
  /* If we have reopened the file, we need to add end of "[outside functions]" */
211
  if (reopened)
212 100 julius
    {
213 19 jeremybenn
      prof_cycles = runtime.sim.cycles;
214
      /* pop everything above current from stack,
215
         if more than one, something went wrong */
216
      while (nstack > 0)
217
        {
218
          int j;
219
          long time;
220
          nstack--;
221
          time = runtime.sim.cycles - stack[nstack].cycles;
222
          /* Whether in normal mode, we must substract called function from execution time.  */
223
          if (!cumulative)
224
            for (j = 0; j < nstack; j++)
225
              stack[j].cycles += time;
226
 
227
          for (j = 0; j < prof_nfuncs; j++)
228
            if (stack[nstack].addr == prof_func[j].addr)
229
              {                 /* function exists, append. */
230
                prof_func[j].cum_cycles += time;
231
                prof_func[j].calls++;
232
                nfunccalls++;
233
                break;
234
              }
235
          if (j >= prof_nfuncs)
236
            {                   /* function does not yet exist, create new. */
237
              prof_func[prof_nfuncs].cum_cycles = time;
238
              prof_func[prof_nfuncs].calls = 1;
239
              nfunccalls++;
240
              prof_func[prof_nfuncs].addr = stack[nstack].addr;
241
              strcpy (prof_func[prof_nfuncs].name, stack[nstack].name);
242
              prof_nfuncs++;
243
            }
244
        }
245
    }
246
  else
247
    fclose (fprof);
248
  return 0;
249
}
250
 
251
/* Print out profiling data */
252
static void
253
prof_print ()
254
{
255
  int i, j;
256
  if (cumulative)
257
    PRINTF ("CUMULATIVE TIMES\n");
258
  PRINTF
259
    ("---------------------------------------------------------------------------\n");
260
  PRINTF
261
    ("|function name            |addr    |# calls |avg cycles  |total cyles     |\n");
262
  PRINTF
263
    ("|-------------------------+--------+--------+------------+----------------|\n");
264
  for (j = 0; j < prof_nfuncs; j++)
265
    {
266
      int bestcyc = 0, besti = 0;
267
      for (i = 0; i < prof_nfuncs; i++)
268
        if (prof_func[i].cum_cycles > bestcyc)
269
          {
270
            bestcyc = prof_func[i].cum_cycles;
271
            besti = i;
272
          }
273
      i = besti;
274
      PRINTF ("| %-24s|%08X|%8li|%12.1f|%11li,%3.0f%%|\n",
275
              prof_func[i].name, prof_func[i].addr, prof_func[i].calls,
276
              ((double) prof_func[i].cum_cycles / prof_func[i].calls),
277
              prof_func[i].cum_cycles,
278
              (100. * prof_func[i].cum_cycles / prof_cycles));
279
      prof_func[i].cum_cycles = -1;
280
    }
281
  PRINTF
282
    ("---------------------------------------------------------------------------\n");
283
  PRINTF ("Total %i functions, %i cycles.\n", prof_nfuncs, prof_cycles);
284
  PRINTF ("Total function calls %i/%i (max depth %i).\n", nfunccalls,
285
          ntotcalls, maxstack);
286
}
287
 
288
/* Set options */
289
void
290
prof_set (int _quiet, int _cumulative)
291
{
292
  quiet = _quiet;
293
  cumulative = _cumulative;
294
}
295
 
296
/*---------------------------------------------------------------------------*/
297
/*! Parse the arguments for the profiling utility
298
 
299
    Updated by Jeremy Bennett to use argtable2. Also has an option just to
300
    print help, for use with the CLI.
301
 
302
    @param[in] argc       Number of command args
303
    @param[in] argv       Vector of the command args
304
    @param[in] just_help  If 1 (true), ignore argc & argv and just print out
305
                          the help message without parsing args
306
 
307
    @return  0 on success, 1 on failure                                      */
308
/*---------------------------------------------------------------------------*/
309
int
310
main_profiler (int argc, char *argv[], int just_help)
311
{
312
  struct arg_lit *vercop;
313
  struct arg_lit *help;
314
  struct arg_lit *cum_arg;
315
  struct arg_lit *quiet_arg;
316
  struct arg_file *gen_file;
317
  struct arg_end *end;
318
 
319
  void *argtab[6];
320
  int nerrors;
321
 
322
  /* Specify each argument, with fallback values */
323
  vercop = arg_lit0 ("v", "version", "version and copyright notice");
324
  help = arg_lit0 ("h", "help", "print this help message");
325
  cum_arg = arg_lit0 ("c", "cumulative",
326
                      "cumulative sum of cycles in functions");
327
  quiet_arg = arg_lit0 ("q", "quiet", "suppress messages");
328
  gen_file = arg_file0 ("g", "generate", "<file>",
329
                        "data file to analyse (default " "sim.profile)");
330
  gen_file->filename[0] = "sim.profile";
331
  end = arg_end (20);
332
 
333
  /* Set up the argument table */
334
  argtab[0] = vercop;
335
  argtab[1] = help;
336
  argtab[2] = cum_arg;
337
  argtab[3] = quiet_arg;
338
  argtab[4] = gen_file;
339
  argtab[5] = end;
340
 
341
  /* If we are just asked for a help message, then we don't parse the
342
     args. This is used to implement the help function from the CLI. */
343
  if (just_help)
344
    {
345
      printf ("profile");
346
      arg_print_syntax (stdout, argtab, "\n");
347
      arg_print_glossary (stdout, argtab, "  %-25s %s\n");
348
 
349
      arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
350
      return 0;
351
    }
352
 
353
  /* Parse */
354
  nerrors = arg_parse (argc, argv, argtab);
355
 
356
  /* Special case here is if help or version is specified, we ignore any other
357
     errors and just print the help or version information and then give up. */
358
  if (vercop->count > 0)
359
    {
360
      PRINTF ("OpenRISC 1000 Profiling Utility, version %s\n",
361
              PACKAGE_VERSION);
362
 
363
      arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
364
      return 0;
365
    }
366
 
367
  if (help->count > 0)
368
    {
369
      printf ("Usage: %s ", argv[0]);
370
      arg_print_syntax (stdout, argtab, "\n");
371
      arg_print_glossary (stdout, argtab, "  %-25s %s\n");
372
 
373
      arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
374
      return 0;
375
    }
376
 
377
  /* Deal with any errors */
378
  if (0 != nerrors)
379
    {
380
      arg_print_errors (stderr, end, "profile");
381
      fprintf (stderr, "Usage: %s ", argv[0]);
382
      arg_print_syntaxv (stderr, argtab, "\n");
383
 
384
      arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
385
      return 1;
386
    }
387
 
388
  /* Cumulative result wanted? */
389
  cumulative = cum_arg->count;
390
 
391
  /* Suppress messages? */
392
  quiet = quiet_arg->count;
393
 
394
  /* Get the profile from the file */
395
  prof_acquire (gen_file->filename[0]);
396
 
397
  /* Now we have all data acquired. Print out. */
398
  prof_print ();
399
 
400
  arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
401
  return 0;
402
 
403
}                               /* main_profiler() */

powered by: WebSVN 2.1.0

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