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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [or1ksim/] [profiler.c] - Blame information for rev 1748

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

Line No. Rev Author Line
1 547 markom
/* profiler.c -- profiling utility
2 1748 jeremybenn
 
3 547 markom
   Copyright (C) 2001 Marko Mlinar, markom@opencores.org
4 1748 jeremybenn
   Copyright (C) 2008 Embecosm Limited
5 547 markom
 
6 1748 jeremybenn
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
7 547 markom
 
8 1748 jeremybenn
   This file is part of Or1ksim, the OpenRISC 1000 Architectural Simulator.
9 547 markom
 
10 1748 jeremybenn
   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 547 markom
 
15 1748 jeremybenn
   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 547 markom
 
20 1748 jeremybenn
   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 173 markom
/* Command line utility, that displays profiling information, generated
27 1748 jeremybenn
   by or1ksim. (use profile command interactively, when running or1ksim, or
28
   separate psim command).  */
29 173 markom
 
30 1308 phoenix
 
31 1748 jeremybenn
/* Autoconf and/or portability configuration */
32 1358 nogj
#include "config.h"
33 1748 jeremybenn
#include "port.h"
34 1358 nogj
 
35 1748 jeremybenn
/* Package includes */
36 632 ivang
#include "profiler.h"
37 940 markom
#include "sim-config.h"
38 1748 jeremybenn
#include "argtable2.h"
39 173 markom
 
40 1748 jeremybenn
/*! Maximum stack frames that can be profiled */
41
#define MAX_STACK  1024
42 173 markom
 
43 1748 jeremybenn
/*! 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 173 markom
 
52 1748 jeremybenn
/*! Global: data about functions */
53
struct func_struct  prof_func[MAX_FUNCS];
54 533 markom
 
55 1748 jeremybenn
/*! Global: total number of functions */
56
int  prof_nfuncs = 0;
57 173 markom
 
58 1748 jeremybenn
/*! Global: current cycles */
59
int  prof_cycles = 0;
60 173 markom
 
61 1748 jeremybenn
/*! Representation of the stack */
62
static struct stack_struct  stack[MAX_STACK];
63 533 markom
 
64 1748 jeremybenn
/*! Current depth */
65
static int  nstack = 0;
66 533 markom
 
67 1748 jeremybenn
/*! Max depth */
68
static int  maxstack = 0;
69 533 markom
 
70 1748 jeremybenn
/*! Number of total calls */
71
static int  ntotcalls = 0;
72 533 markom
 
73 1748 jeremybenn
/*! Number of covered calls */
74
static int  nfunccalls = 0;
75 533 markom
 
76 1748 jeremybenn
/*! 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 879 markom
static FILE *fprof = 0;
84
 
85 847 markom
 
86 1748 jeremybenn
/*---------------------------------------------------------------------------*/
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 879 markom
{
96 173 markom
  int line = 0;
97 940 markom
  int reopened = 0;
98 533 markom
 
99 1748 jeremybenn
  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 940 markom
  /* If we have reopened the file, we need to add end of "[outside functions]" */
206 1748 jeremybenn
  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 940 markom
 
222 1748 jeremybenn
          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 940 markom
    }
241 1748 jeremybenn
  else
242
    fclose (fprof);
243 940 markom
  return 0;
244 879 markom
}
245 173 markom
 
246 879 markom
/* Print out profiling data */
247 1748 jeremybenn
static void
248
prof_print ()
249 879 markom
{
250
  int i, j;
251
  if (cumulative)
252 997 markom
    PRINTF ("CUMULATIVE TIMES\n");
253 1748 jeremybenn
  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 997 markom
  PRINTF ("Total %i functions, %i cycles.\n", prof_nfuncs, prof_cycles);
279 1748 jeremybenn
  PRINTF ("Total function calls %i/%i (max depth %i).\n", nfunccalls,
280
          ntotcalls, maxstack);
281 879 markom
}
282
 
283
/* Set options */
284 1748 jeremybenn
void
285
prof_set (int _quiet, int _cumulative)
286 879 markom
{
287
  quiet = _quiet;
288
  cumulative = _cumulative;
289
}
290
 
291 1748 jeremybenn
/*---------------------------------------------------------------------------*/
292
/*! Parse the arguments for the profiling utility
293 879 markom
 
294 1748 jeremybenn
    Updated by Jeremy Bennett to use argtable2. Also has an option just to
295
    print help, for use with the CLI.
296 879 markom
 
297 1748 jeremybenn
    @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 173 markom
    }
347 879 markom
 
348 1748 jeremybenn
  /* Parse */
349
  nerrors = arg_parse (argc, argv, argtab);
350 879 markom
 
351 1748 jeremybenn
  /* 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 879 markom
  /* Now we have all data acquired. Print out. */
393
  prof_print ();
394 1748 jeremybenn
 
395
  arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
396 533 markom
  return 0;
397 1748 jeremybenn
 
398
}                               /* main_profiler() */

powered by: WebSVN 2.1.0

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