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

Subversion Repositories or1k

[/] [or1k/] [tags/] [nog_patch_62/] [or1ksim/] [profiler.c] - Diff between revs 1449 and 1765

Only display areas with differences | Details | Blame | View Log

Rev 1449 Rev 1765
/* profiler.c -- profiling utility
/* profiler.c -- profiling utility
   Copyright (C) 2001 Marko Mlinar, markom@opencores.org
   Copyright (C) 2001 Marko Mlinar, markom@opencores.org
 
 
This file is part of OpenRISC 1000 Architectural Simulator.
This file is part of OpenRISC 1000 Architectural Simulator.
 
 
This program is free software; you can redistribute it and/or modify
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
(at your option) any later version.
 
 
This program is distributed in the hope that it will be useful,
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
GNU General Public License for more details.
 
 
You should have received a copy of the GNU General Public License
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
 
/* Command line utility, that displays profiling information, generated
/* Command line utility, that displays profiling information, generated
   by or1ksim. (use --profile option at command line, when running or1ksim.  */
   by or1ksim. (use --profile option at command line, when running or1ksim.  */
 
 
#include <stdio.h>
#include <stdio.h>
#include <string.h>
#include <string.h>
 
 
#include "config.h"
#include "config.h"
 
 
#ifdef HAVE_INTTYPES_H
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#include <inttypes.h>
#endif
#endif
 
 
#include "port.h"
#include "port.h"
#include "arch.h"
#include "arch.h"
#include "profiler.h"
#include "profiler.h"
#include "sim-config.h"
#include "sim-config.h"
 
 
static struct stack_struct stack[MAX_STACK];
static struct stack_struct stack[MAX_STACK];
 
 
struct func_struct prof_func[MAX_FUNCS];
struct func_struct prof_func[MAX_FUNCS];
 
 
/* Total number of functions */
/* Total number of functions */
int prof_nfuncs = 0;
int prof_nfuncs = 0;
 
 
/* Current depth */
/* 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 */
/* Current cycles */
int prof_cycles = 0;
int prof_cycles = 0;
 
 
/* Whether we are in cumulative mode */
/* 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 */
/* Print out command line help */
void prof_help ()
void prof_help ()
{
{
  PRINTF ("profiler [-c] [-q] -g [profile_file_name]\n");
  PRINTF ("profiler [-c] [-q] -g [profile_file_name]\n");
  PRINTF ("\t-c\t--cumulative\t\tcumulative sum of cycles in functions\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-q\t--quiet\t\t\tsuppress messages\n");
  PRINTF ("\t-g\t--generate [profile_file_name]\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\toutput profiling results to\n");
  PRINTF ("\t\t\t\t\tstdout/profile_file_name\n");
  PRINTF ("\t\t\t\t\tstdout/profile_file_name\n");
}
}
 
 
/* Acquire data from profiler file */
/* Acquire data from profiler file */
int prof_acquire (char *fprofname)
int prof_acquire (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,
      if (fscanf (fprof, "%08X %08X %08X %s\n", &stack[nstack].cycles, &stack[nstack].raddr,
                  &stack[nstack].addr, &stack[nstack].name[0]) != 4)
                  &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) break;
        if (i >= 0) {
        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 if (!quiet) fprintf (stderr, "WARNING: Cannot find return call for (%08X), ignoring.\n", s.raddr);
      }
      }
    } else
    } 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 ()
void prof_print ()
{
{
  int i, j;
  int i, j;
  if (cumulative)
  if (cumulative)
    PRINTF ("CUMULATIVE TIMES\n");
    PRINTF ("CUMULATIVE TIMES\n");
  PRINTF ("---------------------------------------------------------------------------\n");
  PRINTF ("---------------------------------------------------------------------------\n");
  PRINTF ("|function name            |addr    |# calls |avg cycles  |total cyles     |\n");
  PRINTF ("|function name            |addr    |# calls |avg cycles  |total cyles     |\n");
  PRINTF ("|-------------------------+--------+--------+------------+----------------|\n");
  PRINTF ("|-------------------------+--------+--------+------------+----------------|\n");
  for (j = 0; j < prof_nfuncs; j++) {
  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[]) {
int main_profiler (int argc, char *argv[]) {
  char fprofname[50] = "sim.profile";
  char fprofname[50] = "sim.profile";
 
 
  if (argc > 4 || argc < 2) {
  if (argc > 4 || argc < 2) {
    prof_help ();
    prof_help ();
    return 1;
    return 1;
  }
  }
 
 
  argv++; argc--;
  argv++; argc--;
  while (argc > 0) {
  while (argc > 0) {
    if (!strcmp(argv[0], "-q") || !strcmp(argv[0], "--quiet")) {
    if (!strcmp(argv[0], "-q") || !strcmp(argv[0], "--quiet")) {
      quiet = 1;
      quiet = 1;
      argv++; argc--;
      argv++; argc--;
    } else if (!strcmp(argv[0], "-c") || !strcmp(argv[0], "--cumulative")) {
    } else if (!strcmp(argv[0], "-c") || !strcmp(argv[0], "--cumulative")) {
      cumulative = 1;
      cumulative = 1;
      argv++; argc--;
      argv++; argc--;
    } else if (strcmp(argv[0], "-g") && strcmp(argv[0], "--generate")) {
    } else if (strcmp(argv[0], "-g") && strcmp(argv[0], "--generate")) {
      prof_help ();
      prof_help ();
      return -1;
      return -1;
    } else {
    } else {
      argv++; argc--;
      argv++; argc--;
      if (argv[0] && argv[0][0] != '-') {
      if (argv[0] && argv[0][0] != '-') {
        strcpy (&fprofname[0], argv[0]);
        strcpy (&fprofname[0], argv[0]);
        argv++; argc--;
        argv++; argc--;
      }
      }
    }
    }
  }
  }
 
 
  prof_acquire (fprofname);
  prof_acquire (fprofname);
 
 
  /* Now we have all data acquired. Print out. */
  /* Now we have all data acquired. Print out. */
  prof_print ();
  prof_print ();
  return 0;
  return 0;
}
}
 
 

powered by: WebSVN 2.1.0

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