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

Subversion Repositories openrisc

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

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

powered by: WebSVN 2.1.0

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