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

Subversion Repositories or1k

[/] [or1k/] [tags/] [rel-0-3-0-rc1/] [or1ksim/] [profiler.c] - Diff between revs 1358 and 1748

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 1358 Rev 1748
Line 1... Line 1...
/* profiler.c -- profiling utility
/* profiler.c -- profiling utility
 
 
   Copyright (C) 2001 Marko Mlinar, markom@opencores.org
   Copyright (C) 2001 Marko Mlinar, markom@opencores.org
 
   Copyright (C) 2008 Embecosm Limited
 
 
This file is part of OpenRISC 1000 Architectural Simulator.
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
 
This program is free software; you can redistribute it and/or modify
   This file is part of Or1ksim, the OpenRISC 1000 Architectural Simulator.
it under the terms of the GNU General Public License as published by
 
the Free Software Foundation; either version 2 of the License, or
 
(at your option) any later version.
 
 
 
This program is distributed in the hope that it will be useful,
 
but WITHOUT ANY WARRANTY; without even the implied warranty of
 
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
GNU General Public License for more details.
 
 
 
You should have received a copy of the GNU General Public License
 
along with this program; if not, write to the Free Software
 
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
 
 
/* Command line utility, that displays profiling information, generated
   This program is free software; you can redistribute it and/or modify it
   by or1ksim. (use --profile option at command line, when running or1ksim.  */
   under the terms of the GNU General Public License as published by the Free
 
   Software Foundation; either version 3 of the License, or (at your option)
 
   any later version.
 
 
#include <stdio.h>
   This program is distributed in the hope that it will be useful, but WITHOUT
#include <string.h>
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 
   more details.
 
 
#include "config.h"
   You should have received a copy of the GNU General Public License along
 
   with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
#ifdef HAVE_INTTYPES_H
/* This program is commented throughout in a fashion suitable for processing
#include <inttypes.h>
   with Doxygen. */
#endif
 
 
/* Command line utility, that displays profiling information, generated
 
   by or1ksim. (use profile command interactively, when running or1ksim, or
 
   separate psim command).  */
 
 
 
 
 
/* Autoconf and/or portability configuration */
 
#include "config.h"
#include "port.h"
#include "port.h"
#include "arch.h"
 
 
/* Package includes */
#include "profiler.h"
#include "profiler.h"
#include "sim-config.h"
#include "sim-config.h"
 
#include "argtable2.h"
 
 
static struct stack_struct stack[MAX_STACK];
/*! Maximum stack frames that can be profiled */
 
#define MAX_STACK  1024
 
 
 
/*! Data structure representing information about a stack frame */
 
struct stack_struct
 
{
 
  unsigned int  addr;      /*!< Function address */
 
  unsigned int  cycles;    /*!< Cycles of func start; subfuncs added later */
 
  unsigned int  raddr;     /*!< Return address */
 
  char          name[33];  /*!< Name of the function */
 
};
 
 
 
/*! Global: data about functions */
struct func_struct prof_func[MAX_FUNCS];
struct func_struct prof_func[MAX_FUNCS];
 
 
/* Total number of functions */
/*! Global: total number of functions */
int prof_nfuncs = 0;
int prof_nfuncs = 0;
 
 
/* Current depth */
/*! Global: current cycles */
 
int  prof_cycles = 0;
 
 
 
/*! Representation of the stack */
 
static struct stack_struct  stack[MAX_STACK];
 
 
 
/*! Current depth */
static int nstack = 0;
static int nstack = 0;
 
 
/* Max depth */
/*! Max depth */
static int maxstack = 0;
static int maxstack = 0;
 
 
/* Number of total calls */
/*! Number of total calls */
static int ntotcalls = 0;
static int ntotcalls = 0;
 
 
/* Number of covered calls */
/*! Number of covered calls */
static int nfunccalls = 0;
static int nfunccalls = 0;
 
 
/* Current cycles */
/*! Whether we are in cumulative mode */
int prof_cycles = 0;
 
 
 
/* Whether we are in cumulative mode */
 
static int cumulative = 0;
static int cumulative = 0;
 
 
/* Whether we should not report warnings */
/*! Whether we should not report warnings */
static int quiet = 0;
static int quiet = 0;
 
 
/* File to read from */
/*! File to read from */
static FILE *fprof = 0;
static FILE *fprof = 0;
 
 
/* Print out command line help */
 
void prof_help ()
 
{
 
  PRINTF ("profiler [-c] [-q] -g [profile_file_name]\n");
 
  PRINTF ("\t-c\t--cumulative\t\tcumulative sum of cycles in functions\n");
 
  PRINTF ("\t-q\t--quiet\t\t\tsuppress messages\n");
 
  PRINTF ("\t-g\t--generate [profile_file_name]\n");
 
  PRINTF ("\t\t\t\t\toutput profiling results to\n");
 
  PRINTF ("\t\t\t\t\tstdout/profile_file_name\n");
 
}
 
 
 
/* Acquire data from profiler file */
/*---------------------------------------------------------------------------*/
int prof_acquire (char *fprofname)
/*! Acquire data from profiler file
 
 
 
  @param[in] fprofname   Data file to analyse
 
 
 
  @return  0 on success, return code otherwise                               */
 
/*---------------------------------------------------------------------------*/
 
int
 
prof_acquire (const char *fprofname)
{
{
  int line = 0;
  int line = 0;
  int reopened = 0;
  int reopened = 0;
 
 
  if (runtime.sim.fprof) {
  if (runtime.sim.fprof)
 
    {
    fprof = runtime.sim.fprof;
    fprof = runtime.sim.fprof;
    reopened = 1;
    reopened = 1;
    rewind (fprof);
    rewind (fprof);
  } else fprof = fopen (fprofname, "rt");
    }
 
  else
 
    fprof = fopen (fprofname, "rt");
 
 
  if (!fprof) {
  if (!fprof)
 
    {
    fprintf (stderr, "Cannot open profile file: %s\n", fprofname);
    fprintf (stderr, "Cannot open profile file: %s\n", fprofname);
    return 1;
    return 1;
  }
  }
 
 
  while (1) {
  while (1)
 
    {
    char dir = fgetc (fprof);
    char dir = fgetc (fprof);
    line++;
    line++;
    if (dir == '+') {
      if (dir == '+')
      if (fscanf (fprof, "%08X %08X %08X %s\n", &stack[nstack].cycles, &stack[nstack].raddr,
        {
                  &stack[nstack].addr, &stack[nstack].name[0]) != 4)
          if (fscanf
 
              (fprof, "%08X %08X %08X %s\n", &stack[nstack].cycles,
 
               &stack[nstack].raddr, &stack[nstack].addr,
 
               &stack[nstack].name[0]) != 4)
        fprintf (stderr, "Error reading line #%i\n", line);
        fprintf (stderr, "Error reading line #%i\n", line);
      else {
          else
 
            {
        prof_cycles = stack[nstack].cycles;
        prof_cycles = stack[nstack].cycles;
        nstack++;
        nstack++;
        if (nstack > maxstack)
        if (nstack > maxstack)
          maxstack = nstack;
          maxstack = nstack;
      }
      }
      ntotcalls++;
      ntotcalls++;
    } else if (dir == '-') {
        }
 
      else if (dir == '-')
 
        {
      struct stack_struct s;
      struct stack_struct s;
      if (fscanf (fprof, "%08X %08X\n", &s.cycles, &s.raddr) != 2)
      if (fscanf (fprof, "%08X %08X\n", &s.cycles, &s.raddr) != 2)
        fprintf (stderr, "Error reading line #%i\n", line);
        fprintf (stderr, "Error reading line #%i\n", line);
      else {
          else
 
            {
        int i;
        int i;
        prof_cycles = s.cycles;
        prof_cycles = s.cycles;
        for (i = nstack - 1; i >= 0; i--)
        for (i = nstack - 1; i >= 0; i--)
          if (stack[i].raddr == s.raddr) break;
                if (stack[i].raddr == s.raddr)
        if (i >= 0) {
                  break;
 
              if (i >= 0)
 
                {
          /* pop everything above current from stack,
          /* pop everything above current from stack,
             if more than one, something went wrong */
             if more than one, something went wrong */
          while (nstack > i) {
                  while (nstack > i)
 
                    {
            int j;
            int j;
            long time;
            long time;
            nstack--;
            nstack--;
            time = s.cycles - stack[nstack].cycles;
            time = s.cycles - stack[nstack].cycles;
            if (!quiet && time < 0) {
                      if (!quiet && time < 0)
              fprintf (stderr, "WARNING: Negative time at %s (return addr = %08X).\n", stack[i].name, stack[i].raddr);
                        {
 
                          fprintf (stderr,
 
                                   "WARNING: Negative time at %s (return addr = %08X).\n",
 
                                   stack[i].name, stack[i].raddr);
              time = 0;
              time = 0;
            }
            }
 
 
            /* Whether in normal mode, we must substract called function from execution time.  */
            /* Whether in normal mode, we must substract called function from execution time.  */
            if (!cumulative)
            if (!cumulative)
              for (j = 0; j < nstack; j++)
              for (j = 0; j < nstack; j++)
                stack[j].cycles += time;
                stack[j].cycles += time;
 
 
            if (!quiet && i != nstack)
            if (!quiet && i != nstack)
              fprintf (stderr, "WARNING: Missaligned return call for %s (%08X) (found %s @ %08X), closing.\n", stack[nstack].name, stack[nstack].raddr, stack[i].name, stack[i].raddr);
                        fprintf (stderr,
 
                                 "WARNING: Missaligned return call for %s (%08X) (found %s @ %08X), closing.\n",
 
                                 stack[nstack].name, stack[nstack].raddr,
 
                                 stack[i].name, stack[i].raddr);
 
 
            for (j = 0; j < prof_nfuncs; j++)
            for (j = 0; j < prof_nfuncs; j++)
              if (stack[nstack].addr == prof_func[j].addr) { /* function exists, append. */
                        if (stack[nstack].addr == prof_func[j].addr)
 
                          {     /* function exists, append. */
                prof_func[j].cum_cycles += time;
                prof_func[j].cum_cycles += time;
                prof_func[j].calls++;
                prof_func[j].calls++;
                nfunccalls++;
                nfunccalls++;
                break;
                break;
              }
              }
            if (j >= prof_nfuncs) { /* function does not yet exist, create new. */
                      if (j >= prof_nfuncs)
 
                        {       /* function does not yet exist, create new. */
              prof_func[prof_nfuncs].cum_cycles = time;
              prof_func[prof_nfuncs].cum_cycles = time;
              prof_func[prof_nfuncs].calls = 1;
              prof_func[prof_nfuncs].calls = 1;
              nfunccalls++;
              nfunccalls++;
              prof_func[prof_nfuncs].addr = stack[nstack].addr;
              prof_func[prof_nfuncs].addr = stack[nstack].addr;
              strcpy (prof_func[prof_nfuncs].name, stack[nstack].name);
                          strcpy (prof_func[prof_nfuncs].name,
 
                                  stack[nstack].name);
              prof_nfuncs++;
              prof_nfuncs++;
            }
            }
          }
          }
        } else if (!quiet) fprintf (stderr, "WARNING: Cannot find return call for (%08X), ignoring.\n", s.raddr);
 
      }
      }
    } else
              else if (!quiet)
 
                fprintf (stderr,
 
                         "WARNING: Cannot find return call for (%08X), ignoring.\n",
 
                         s.raddr);
 
            }
 
        }
 
      else
      break;
      break;
  }
  }
 
 
  /* If we have reopened the file, we need to add end of "[outside functions]" */
  /* If we have reopened the file, we need to add end of "[outside functions]" */
  if (reopened) {
  if (reopened)
 
    {
    prof_cycles = runtime.sim.cycles;
    prof_cycles = runtime.sim.cycles;
    /* pop everything above current from stack,
    /* pop everything above current from stack,
       if more than one, something went wrong */
       if more than one, something went wrong */
    while (nstack > 0) {
      while (nstack > 0)
 
        {
      int j;
      int j;
      long time;
      long time;
      nstack--;
      nstack--;
      time = runtime.sim.cycles - stack[nstack].cycles;
      time = runtime.sim.cycles - stack[nstack].cycles;
      /* Whether in normal mode, we must substract called function from execution time.  */
      /* Whether in normal mode, we must substract called function from execution time.  */
      if (!cumulative)
      if (!cumulative)
        for (j = 0; j < nstack; j++) stack[j].cycles += time;
            for (j = 0; j < nstack; j++)
 
              stack[j].cycles += time;
 
 
      for (j = 0; j < prof_nfuncs; j++)
      for (j = 0; j < prof_nfuncs; j++)
        if (stack[nstack].addr == prof_func[j].addr) { /* function exists, append. */
            if (stack[nstack].addr == prof_func[j].addr)
 
              {                 /* function exists, append. */
          prof_func[j].cum_cycles += time;
          prof_func[j].cum_cycles += time;
          prof_func[j].calls++;
          prof_func[j].calls++;
          nfunccalls++;
          nfunccalls++;
          break;
          break;
        }
        }
      if (j >= prof_nfuncs) { /* function does not yet exist, create new. */
          if (j >= prof_nfuncs)
 
            {                   /* function does not yet exist, create new. */
        prof_func[prof_nfuncs].cum_cycles = time;
        prof_func[prof_nfuncs].cum_cycles = time;
        prof_func[prof_nfuncs].calls = 1;
        prof_func[prof_nfuncs].calls = 1;
        nfunccalls++;
        nfunccalls++;
        prof_func[prof_nfuncs].addr = stack[nstack].addr;
        prof_func[prof_nfuncs].addr = stack[nstack].addr;
        strcpy (prof_func[prof_nfuncs].name, stack[nstack].name);
        strcpy (prof_func[prof_nfuncs].name, stack[nstack].name);
        prof_nfuncs++;
        prof_nfuncs++;
      }
      }
    }
    }
  } else fclose(fprof);
    }
 
  else
 
    fclose (fprof);
  return 0;
  return 0;
}
}
 
 
/* Print out profiling data */
/* Print out profiling data */
void prof_print ()
static void
 
prof_print ()
{
{
  int i, j;
  int i, j;
  if (cumulative)
  if (cumulative)
    PRINTF ("CUMULATIVE TIMES\n");
    PRINTF ("CUMULATIVE TIMES\n");
  PRINTF ("---------------------------------------------------------------------------\n");
  PRINTF
  PRINTF ("|function name            |addr    |# calls |avg cycles  |total cyles     |\n");
    ("---------------------------------------------------------------------------\n");
  PRINTF ("|-------------------------+--------+--------+------------+----------------|\n");
  PRINTF
  for (j = 0; j < prof_nfuncs; j++) {
    ("|function name            |addr    |# calls |avg cycles  |total cyles     |\n");
 
  PRINTF
 
    ("|-------------------------+--------+--------+------------+----------------|\n");
 
  for (j = 0; j < prof_nfuncs; j++)
 
    {
    int bestcyc = 0, besti = 0;
    int bestcyc = 0, besti = 0;
    for (i = 0; i < prof_nfuncs; i++)
    for (i = 0; i < prof_nfuncs; i++)
      if (prof_func[i].cum_cycles > bestcyc) {
        if (prof_func[i].cum_cycles > bestcyc)
 
          {
        bestcyc = prof_func[i].cum_cycles;
        bestcyc = prof_func[i].cum_cycles;
        besti = i;
        besti = i;
      }
      }
    i = besti;
    i = besti;
    PRINTF ("| %-24s|%08X|%8li|%12.1f|%11li,%3.0f%%|\n",
    PRINTF ("| %-24s|%08X|%8li|%12.1f|%11li,%3.0f%%|\n",
            prof_func[i].name, prof_func[i].addr, prof_func[i].calls, ((double)prof_func[i].cum_cycles / prof_func[i].calls), prof_func[i].cum_cycles, (100. * prof_func[i].cum_cycles / prof_cycles));
              prof_func[i].name, prof_func[i].addr, prof_func[i].calls,
 
              ((double) prof_func[i].cum_cycles / prof_func[i].calls),
 
              prof_func[i].cum_cycles,
 
              (100. * prof_func[i].cum_cycles / prof_cycles));
    prof_func[i].cum_cycles = -1;
    prof_func[i].cum_cycles = -1;
  }
  }
  PRINTF ("---------------------------------------------------------------------------\n");
  PRINTF
 
    ("---------------------------------------------------------------------------\n");
  PRINTF ("Total %i functions, %i cycles.\n", prof_nfuncs, prof_cycles);
  PRINTF ("Total %i functions, %i cycles.\n", prof_nfuncs, prof_cycles);
  PRINTF ("Total function calls %i/%i (max depth %i).\n", nfunccalls, ntotcalls, maxstack);
  PRINTF ("Total function calls %i/%i (max depth %i).\n", nfunccalls,
 
          ntotcalls, maxstack);
}
}
 
 
/* Set options */
/* Set options */
void prof_set (int _quiet, int _cumulative)
void
 
prof_set (int _quiet, int _cumulative)
{
{
  quiet = _quiet;
  quiet = _quiet;
  cumulative = _cumulative;
  cumulative = _cumulative;
}
}
 
 
int main_profiler (int argc, char *argv[]) {
/*---------------------------------------------------------------------------*/
  char fprofname[50] = "sim.profile";
/*! Parse the arguments for the profiling utility
 
 
  if (argc > 4 || argc < 2) {
    Updated by Jeremy Bennett to use argtable2. Also has an option just to
    prof_help ();
    print help, for use with the CLI.
    return 1;
 
 
    @param[in] argc       Number of command args
 
    @param[in] argv       Vector of the command args
 
    @param[in] just_help  If 1 (true), ignore argc & argv and just print out
 
                          the help message without parsing args
 
 
 
    @return  0 on success, 1 on failure                                      */
 
/*---------------------------------------------------------------------------*/
 
int
 
main_profiler (int argc, char *argv[], int just_help)
 
{
 
  struct arg_lit *vercop;
 
  struct arg_lit *help;
 
  struct arg_lit *cum_arg;
 
  struct arg_lit *quiet_arg;
 
  struct arg_file *gen_file;
 
  struct arg_end *end;
 
 
 
  void *argtab[6];
 
  int nerrors;
 
 
 
  /* Specify each argument, with fallback values */
 
  vercop = arg_lit0 ("v", "version", "version and copyright notice");
 
  help = arg_lit0 ("h", "help", "print this help message");
 
  cum_arg = arg_lit0 ("c", "cumulative",
 
                      "cumulative sum of cycles in functions");
 
  quiet_arg = arg_lit0 ("q", "quiet", "suppress messages");
 
  gen_file = arg_file0 ("g", "generate", "<file>",
 
                        "data file to analyse (default " "sim.profile)");
 
  gen_file->filename[0] = "sim.profile";
 
  end = arg_end (20);
 
 
 
  /* Set up the argument table */
 
  argtab[0] = vercop;
 
  argtab[1] = help;
 
  argtab[2] = cum_arg;
 
  argtab[3] = quiet_arg;
 
  argtab[4] = gen_file;
 
  argtab[5] = end;
 
 
 
  /* If we are just asked for a help message, then we don't parse the
 
     args. This is used to implement the help function from the CLI. */
 
  if (just_help)
 
    {
 
      printf ("profile");
 
      arg_print_syntax (stdout, argtab, "\n");
 
      arg_print_glossary (stdout, argtab, "  %-25s %s\n");
 
 
 
      arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
 
      return 0;
  }
  }
 
 
  argv++; argc--;
  /* Parse */
  while (argc > 0) {
  nerrors = arg_parse (argc, argv, argtab);
    if (!strcmp(argv[0], "-q") || !strcmp(argv[0], "--quiet")) {
 
      quiet = 1;
  /* Special case here is if help or version is specified, we ignore any other
      argv++; argc--;
     errors and just print the help or version information and then give up. */
    } else if (!strcmp(argv[0], "-c") || !strcmp(argv[0], "--cumulative")) {
  if (vercop->count > 0)
      cumulative = 1;
    {
      argv++; argc--;
      PRINTF ("OpenRISC 1000 Profiling Utility, version %s\n",
    } else if (strcmp(argv[0], "-g") && strcmp(argv[0], "--generate")) {
              PACKAGE_VERSION);
      prof_help ();
 
      return -1;
      arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
    } else {
      return 0;
      argv++; argc--;
 
      if (argv[0] && argv[0][0] != '-') {
 
        strcpy (&fprofname[0], argv[0]);
 
        argv++; argc--;
 
      }
      }
 
 
 
  if (help->count > 0)
 
    {
 
      printf ("Usage: %s ", argv[0]);
 
      arg_print_syntax (stdout, argtab, "\n");
 
      arg_print_glossary (stdout, argtab, "  %-25s %s\n");
 
 
 
      arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
 
      return 0;
    }
    }
 
 
 
  /* Deal with any errors */
 
  if (0 != nerrors)
 
    {
 
      arg_print_errors (stderr, end, "profile");
 
      fprintf (stderr, "Usage: %s ", argv[0]);
 
      arg_print_syntaxv (stderr, argtab, "\n");
 
 
 
      arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
 
      return 1;
  }
  }
 
 
  prof_acquire (fprofname);
  /* Cumulative result wanted? */
 
  cumulative = cum_arg->count;
 
 
 
  /* Suppress messages? */
 
  quiet = quiet_arg->count;
 
 
 
  /* Get the profile from the file */
 
  prof_acquire (gen_file->filename[0]);
 
 
  /* Now we have all data acquired. Print out. */
  /* Now we have all data acquired. Print out. */
  prof_print ();
  prof_print ();
 
 
 
  arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
  return 0;
  return 0;
}
 
 
}                               /* main_profiler() */
 
 
 No newline at end of file
 No newline at end of file

powered by: WebSVN 2.1.0

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