* sim-base.h (sim_state_base): Delete member `model'.
authorDoug Evans <dje@google.com>
Mon, 19 Jan 1998 21:11:00 +0000 (21:11 +0000)
committerDoug Evans <dje@google.com>
Mon, 19 Jan 1998 21:11:00 +0000 (21:11 +0000)
(sim_cpu_base): Add member `model'.
* sim-model.h (IMP_PROPERTIES): New type.
(MACH): New members imp_props, models.
(models): Delete decl.
* sim-model.c (set_model): Update.
* sim-profile.c (profile_print_model): Update.

sim/common/sim-profile.c

index f92c67380beb643a2ecd17383638559443a393fa..d386e4a29244be6d72456cffc2180a52b1dca0ba 100644 (file)
@@ -21,20 +21,39 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "sim-main.h"
 #include "sim-io.h"
 #include "sim-options.h"
+#include "sim-assert.h"
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#endif
 
 #define COMMAS(n) sim_add_commas (comma_buf, sizeof (comma_buf), (n))
 
 static MODULE_UNINSTALL_FN profile_uninstall;
 
+#if WITH_PROFILE_INSN_P || WITH_PROFILE_MEMORY_P || WITH_PROFILE_CORE_P || WITH_PROFILE_PC_P
 static void print_bar (SIM_DESC, unsigned int, unsigned int, unsigned int);
+#endif
 
 static DECLARE_OPTION_HANDLER (profile_option_handler);
 
-#define OPTION_PROFILE_INSN    (OPTION_START + 0)
-#define OPTION_PROFILE_MEMORY  (OPTION_START + 1)
-#define OPTION_PROFILE_MODEL   (OPTION_START + 2)
-#define OPTION_PROFILE_FILE    (OPTION_START + 3)
-#define OPTION_PROFILE_RANGE   (OPTION_START + 4)
+#define OPTION_PROFILE_INSN            (OPTION_START + 0)
+#define OPTION_PROFILE_MEMORY          (OPTION_START + 1)
+#define OPTION_PROFILE_MODEL           (OPTION_START + 2)
+#define OPTION_PROFILE_FILE            (OPTION_START + 3)
+#define OPTION_PROFILE_RANGE           (OPTION_START + 4)
+#define OPTION_PROFILE_CORE            (OPTION_START + 5)
+#define OPTION_PROFILE_PC              (OPTION_START + 6)
+#define OPTION_PROFILE_PC_RANGE                (OPTION_START + 7)
+#define OPTION_PROFILE_PC_GRANULARITY  (OPTION_START + 8)
 
 static const OPTION profile_options[] = {
   { {"profile", no_argument, NULL, 'p'},
@@ -46,28 +65,47 @@ static const OPTION profile_options[] = {
   { {"profile-memory", no_argument, NULL, OPTION_PROFILE_MEMORY},
       '\0', NULL, "Perform memory profiling",
       profile_option_handler },
+  { {"profile-core", no_argument, NULL, OPTION_PROFILE_CORE},
+      '\0', NULL, "Perform CORE profiling",
+      profile_option_handler },
   { {"profile-model", no_argument, NULL, OPTION_PROFILE_MODEL},
       '\0', NULL, "Perform model profiling",
       profile_option_handler },
+
   { {"profile-file", required_argument, NULL, OPTION_PROFILE_FILE},
       '\0', "FILE NAME", "Specify profile output file",
       profile_option_handler },
+
+  { {"profile-pc", no_argument, NULL, OPTION_PROFILE_PC},
+      '\0', NULL, "Perform PC profiling",
+      profile_option_handler },
   { {"profile-pc-frequency", required_argument, NULL, 'F'},
-      'F', "PC PROFILE FREQUENCY", "Turn on PC profiling at specified frequency",
+      'F', "PC PROFILE FREQUENCY", "Specified PC profiling frequency",
       profile_option_handler },
   { {"profile-pc-size", required_argument, NULL, 'S'},
       'S', "PC PROFILE SIZE", "Specify PC profiling size",
       profile_option_handler },
+  { {"profile-pc-granularity", required_argument, NULL, OPTION_PROFILE_PC_GRANULARITY},
+      '\0', "PC PROFILE GRANULARITY", "Specify PC profiling sample coverage",
+      profile_option_handler },
+  { {"profile-pc-range", required_argument, NULL, OPTION_PROFILE_PC_RANGE},
+      '\0', "BASE,BOUND", "Specify PC profiling address range",
+      profile_option_handler },
+
 #if 0 /*FIXME:wip*/
   { {"profile-range", required_argument, NULL, OPTION_PROFILE_RANGE},
       0, NULL, "Specify range of addresses to profile",
       profile_option_handler },
 #endif
+
   { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
 };
 
 static SIM_RC
-profile_option_handler (SIM_DESC sd, int opt, char *arg)
+profile_option_handler (SIM_DESC sd,
+                       int opt,
+                       char *arg,
+                       int is_command)
 {
   int i,n;
 
@@ -102,6 +140,15 @@ profile_option_handler (SIM_DESC sd, int opt, char *arg)
 #endif
       break;
 
+    case OPTION_PROFILE_CORE :
+#if WITH_PROFILE_CORE_P
+      for (n = 0; n < MAX_NR_PROCESSORS; ++n)
+       CPU_PROFILE_FLAGS (STATE_CPU (sd, n))[PROFILE_CORE_IDX] = 1;
+#else
+      sim_io_eprintf (sd, "CORE profiling not compiled in, `--profile-core' ignored\n");
+#endif
+      break;
+
     case OPTION_PROFILE_MODEL :
 #if WITH_PROFILE_MODEL_P
       for (n = 0; n < MAX_NR_PROCESSORS; ++n)
@@ -130,28 +177,100 @@ profile_option_handler (SIM_DESC sd, int opt, char *arg)
        }
       break;
 
+    case OPTION_PROFILE_PC:
+      if (WITH_PROFILE_PC_P)
+       {
+         for (n = 0; n < MAX_NR_PROCESSORS; ++n)
+           CPU_PROFILE_FLAGS (STATE_CPU (sd, n))[PROFILE_PC_IDX] = 1;
+       }
+      else
+       sim_io_eprintf (sd, "PC profiling not compiled in, `--profile-pc' ignored\n");
+      break;
+
     case 'F' :
-#if WITH_PROFILE_PC_P
-      /* FIXME: Validate arg.  */
-      i = atoi (arg);
-      for (n = 0; n < MAX_NR_PROCESSORS; ++n)
-       PROFILE_PC_FREQ (CPU_PROFILE_DATA (STATE_CPU (sd, n))) = i;
-#else
-      sim_io_eprintf (sd, "PC profiling not compiled in, `--profile-pc-frequency' ignored\n");
-#endif
+      if (WITH_PROFILE_PC_P)
+       {
+         /* FIXME: Validate arg.  */
+         i = atoi (arg);
+         for (n = 0; n < MAX_NR_PROCESSORS; ++n)
+           PROFILE_PC_FREQ (CPU_PROFILE_DATA (STATE_CPU (sd, n))) = i;
+         for (n = 0; n < MAX_NR_PROCESSORS; ++n)
+           CPU_PROFILE_FLAGS (STATE_CPU (sd, n))[PROFILE_PC_IDX] = 1;
+       }
+      else
+       sim_io_eprintf (sd, "PC profiling not compiled in, `--profile-pc-frequency' ignored\n");
       break;
 
     case 'S' :
-#if WITH_PROFILE_PC_P
-      /* FIXME: Validate arg.  */
-      i = atoi (arg);
-      for (n = 0; n < MAX_NR_PROCESSORS; ++n)
-       PROFILE_PC_SIZE (CPU_PROFILE_DATA (STATE_CPU (sd, n))) = i;
-#else
-      sim_io_eprintf (sd, "PC profiling not compiled in, `--profile-pc-size' ignored\n");
-#endif
+      if (WITH_PROFILE_PC_P)
+       {
+         /* FIXME: Validate arg.  */
+         i = atoi (arg);
+         for (n = 0; n < MAX_NR_PROCESSORS; ++n)
+           PROFILE_PC_NR_BUCKETS (CPU_PROFILE_DATA (STATE_CPU (sd, n))) = i;
+         for (n = 0; n < MAX_NR_PROCESSORS; ++n)
+           CPU_PROFILE_FLAGS (STATE_CPU (sd, n))[PROFILE_PC_IDX] = 1;
+       }
+      else
+       sim_io_eprintf (sd, "PC profiling not compiled in, `--profile-pc-size' ignored\n");
       break;
 
+    case OPTION_PROFILE_PC_GRANULARITY:
+      if (WITH_PROFILE_PC_P)
+       {
+         int shift;
+         i = atoi (arg);
+         /* check that the granularity is a power of two */
+         shift = 0;
+         while (i > (1 << shift))
+           {
+             shift += 1;
+           }
+         if (i != (1 << shift))
+           {
+             sim_io_eprintf (sd, "PC profiling granularity not a power of two\n");
+             return SIM_RC_FAIL;
+           }
+         if (shift == 0)
+           {
+             sim_io_eprintf (sd, "PC profiling granularity too small");
+             return SIM_RC_FAIL;
+           }
+         for (n = 0; n < MAX_NR_PROCESSORS; ++n)
+           PROFILE_PC_SHIFT (CPU_PROFILE_DATA (STATE_CPU (sd, n))) = shift;
+         for (n = 0; n < MAX_NR_PROCESSORS; ++n)
+           CPU_PROFILE_FLAGS (STATE_CPU (sd, n))[PROFILE_PC_IDX] = 1;
+       }
+      else
+       sim_io_eprintf (sd, "PC profiling not compiled in, `--profile-pc-granularity' ignored\n");
+      break;
+
+    case OPTION_PROFILE_PC_RANGE:
+      if (WITH_PROFILE_PC_P)
+       {
+         /* FIXME: Validate args */
+         char *chp = arg;
+         unsigned long base;
+         unsigned long bound;
+         base = strtoul (chp, &chp, 0);
+         if (*chp != ',')
+           {
+             sim_io_eprintf (sd, "--profile-pc-range missing BOUND argument\n");
+             return SIM_RC_FAIL;
+           }
+         bound = strtoul (chp + 1, NULL, 0);
+         for (n = 0; n < MAX_NR_PROCESSORS; ++n)
+           {
+             PROFILE_PC_START (CPU_PROFILE_DATA (STATE_CPU (sd, n))) = base;
+             PROFILE_PC_END (CPU_PROFILE_DATA (STATE_CPU (sd, n))) = bound;
+           }         
+         for (n = 0; n < MAX_NR_PROCESSORS; ++n)
+           CPU_PROFILE_FLAGS (STATE_CPU (sd, n))[PROFILE_PC_IDX] = 1;
+       }
+      else
+       sim_io_eprintf (sd, "PC profiling not compiled in, `--profile-pc-range' ignored\n");
+
+
 #if 0 /* FIXME:wip */
     case OPTION_PROFILE_RANGE :
       break;
@@ -161,33 +280,257 @@ profile_option_handler (SIM_DESC sd, int opt, char *arg)
   return SIM_RC_OK;
 }
 \f
-/* Install profiling support in the simulator.  */
+/* PC profiling support */
 
-SIM_RC
-profile_install (SIM_DESC sd)
+#if WITH_PROFILE_PC_P
+
+static void
+profile_pc_cleanup (SIM_DESC sd)
 {
-  int i;
+  int n;
+  for (n = 0; n < MAX_NR_PROCESSORS; n++)
+    {
+      sim_cpu *cpu = STATE_CPU (sd, n);
+      PROFILE_DATA *data = CPU_PROFILE_DATA (cpu);
+      if (PROFILE_PC_COUNT (data) != NULL)
+       zfree (PROFILE_PC_COUNT (data));
+      PROFILE_PC_COUNT (data) = NULL;
+      if (PROFILE_PC_EVENT (data) != NULL)
+       sim_events_deschedule (sd, PROFILE_PC_EVENT (data));
+      PROFILE_PC_EVENT (data) = NULL;
+    }
+}
 
-  sim_add_option_table (sd, profile_options);
-  for (i = 0; i < MAX_NR_PROCESSORS; ++i)
-    memset (CPU_PROFILE_DATA (STATE_CPU (sd, i)), 0,
-           sizeof (* CPU_PROFILE_DATA (STATE_CPU (sd, i))));
-  sim_module_add_uninstall_fn (sd, profile_uninstall);
+
+static void
+profile_pc_uninstall (SIM_DESC sd)
+{
+  profile_pc_cleanup (sd);
+}
+
+static void
+profile_pc_event (SIM_DESC sd,
+                 void *data)
+{
+  sim_cpu *cpu = (sim_cpu*) data;
+  PROFILE_DATA *profile = CPU_PROFILE_DATA (cpu);
+  address_word pc;
+  unsigned i;
+  switch (STATE_WATCHPOINTS (sd)->sizeof_pc)
+    {
+    case 2: pc = *(unsigned_2*)(STATE_WATCHPOINTS (sd)->pc) ; break;
+    case 4: pc = *(unsigned_4*)(STATE_WATCHPOINTS (sd)->pc) ; break;
+    case 8: pc = *(unsigned_8*)(STATE_WATCHPOINTS (sd)->pc) ; break;
+    default: pc = 0;
+    }
+  i = (pc - PROFILE_PC_START (profile)) >> PROFILE_PC_SHIFT (profile);
+  if (i < PROFILE_PC_NR_BUCKETS (profile))
+    PROFILE_PC_COUNT (profile) [i] += 1; /* Overflow? */
+  else
+    PROFILE_PC_COUNT (profile) [PROFILE_PC_NR_BUCKETS (profile)] += 1;
+  PROFILE_PC_EVENT (profile) = 
+    sim_events_schedule (sd, PROFILE_PC_FREQ (profile), profile_pc_event, cpu);
+}
+
+static SIM_RC
+profile_pc_init (SIM_DESC sd)
+{
+  int n;
+  profile_pc_cleanup (sd);
+  for (n = 0; n < MAX_NR_PROCESSORS; n++)
+    {
+      sim_cpu *cpu = STATE_CPU (sd, n);
+      PROFILE_DATA *data = CPU_PROFILE_DATA (cpu);
+      if (CPU_PROFILE_FLAGS (STATE_CPU (sd, n))[PROFILE_PC_IDX]
+         && STATE_WATCHPOINTS (sd)->pc != NULL)
+       {
+         int bucket_size;
+         /* fill in the frequency if not specified */
+         if (PROFILE_PC_FREQ (data) == 0)
+           PROFILE_PC_FREQ (data) = 256;
+         /* fill in the start/end if not specified */
+         if (PROFILE_PC_END (data) == 0)
+           {
+             PROFILE_PC_START (data) = STATE_TEXT_START (sd);
+             PROFILE_PC_END (data) = STATE_TEXT_END (sd);
+           }
+         /* Compute the number of buckets if not specified. */
+         if (PROFILE_PC_NR_BUCKETS (data) == 0)
+           {
+             if (PROFILE_PC_BUCKET_SIZE (data) == 0)
+               PROFILE_PC_NR_BUCKETS (data) = 16;
+             else
+               {
+                 if (PROFILE_PC_END (data) == 0)
+                   {
+                     /* nr_buckets = (full-address-range / 2) / (bucket_size / 2) */
+                     PROFILE_PC_NR_BUCKETS (data) =
+                       ((1 << (STATE_WATCHPOINTS (sd)->sizeof_pc) * (8 - 1))
+                        / (PROFILE_PC_BUCKET_SIZE (data) / 2));
+                   }
+                 else
+                   {
+                     PROFILE_PC_NR_BUCKETS (data) =
+                       ((PROFILE_PC_END (data)
+                         - PROFILE_PC_START (data)
+                         + PROFILE_PC_BUCKET_SIZE (data) - 1)
+                        / PROFILE_PC_BUCKET_SIZE (data));
+                   }
+               }
+           }
+         /* Compute the bucket size if not specified.  Ensure that it
+             is rounded up to the next power of two */
+         if (PROFILE_PC_BUCKET_SIZE (data) == 0)
+           {
+             if (PROFILE_PC_END (data) == 0)
+               /* bucket_size = (full-address-range / 2) / (nr_buckets / 2) */
+               bucket_size = ((1 << ((STATE_WATCHPOINTS (sd)->sizeof_pc * 8) - 1))
+                              / (PROFILE_PC_NR_BUCKETS (data) / 2));
+             else
+               bucket_size = ((PROFILE_PC_END (data)
+                               - PROFILE_PC_START (data)
+                               + PROFILE_PC_NR_BUCKETS (data) - 1)
+                              / PROFILE_PC_NR_BUCKETS (data));
+             PROFILE_PC_SHIFT (data) = 0;
+             while (bucket_size < PROFILE_PC_BUCKET_SIZE (data))
+               {
+                 PROFILE_PC_SHIFT (data) += 1;
+               }
+           }
+         /* Align the end address with bucket size */
+         if (PROFILE_PC_END (data) != 0)
+           PROFILE_PC_END (data) = (PROFILE_PC_START (data)
+                                    + (PROFILE_PC_BUCKET_SIZE (data)
+                                       * PROFILE_PC_NR_BUCKETS (data)));
+         /* create the relevant buffers */
+         PROFILE_PC_COUNT (data) =
+           NZALLOC (unsigned, PROFILE_PC_NR_BUCKETS (data) + 1);
+         PROFILE_PC_EVENT (data) =
+           sim_events_schedule (sd,
+                                PROFILE_PC_FREQ (data),
+                                profile_pc_event,
+                                cpu);
+       }
+    }
   return SIM_RC_OK;
 }
 
 static void
-profile_uninstall (SIM_DESC sd)
+profile_print_pc (sim_cpu *cpu, int verbose)
 {
-  int i;
+  SIM_DESC sd = CPU_STATE (cpu);
+  PROFILE_DATA *profile = CPU_PROFILE_DATA (cpu);
+  char comma_buf[20];
+  unsigned max_val;
+  unsigned total;
+  unsigned i;
 
-  for (i = 0; i < MAX_NR_PROCESSORS; ++i)
+  sim_io_printf (sd, "Program Counter Statistics:\n\n");
+
+  /* First pass over data computes various things.  */
+  max_val = 0;
+  total = 0;
+  for (i = 0; i <= PROFILE_PC_NR_BUCKETS (profile); ++i)
     {
-      PROFILE_DATA *data = CPU_PROFILE_DATA (STATE_CPU (sd, i));
-      if (PROFILE_FILE (data) != NULL)
-       fclose (PROFILE_FILE (data));
+      total += PROFILE_PC_COUNT (profile) [i];
+      if (PROFILE_PC_COUNT (profile) [i] > max_val)
+       max_val = PROFILE_PC_COUNT (profile) [i];
     }
+
+  sim_io_printf (sd, "  Total samples: %s\n",
+                COMMAS (total));
+  sim_io_printf (sd, "  Granularity: %s bytes per bucket\n",
+                COMMAS (PROFILE_PC_BUCKET_SIZE (profile)));
+  sim_io_printf (sd, "  Size: %s buckets\n",
+                COMMAS (PROFILE_PC_NR_BUCKETS (profile)));
+  sim_io_printf (sd, "  Frequency: %s cycles per sample\n",
+                COMMAS (PROFILE_PC_FREQ (profile)));
+
+  if (PROFILE_PC_END (profile) != 0)
+    sim_io_printf (sd, "  Range: 0x%lx 0x%lx\n",
+                  (long) PROFILE_PC_START (profile),
+                  (long) PROFILE_PC_END (profile));
+
+  if (verbose && max_val != 0)
+    {
+      /* Now we can print the histogram.  */
+      sim_io_printf (sd, "\n");
+      for (i = 0; i <= PROFILE_PC_NR_BUCKETS (profile); ++i)
+       {
+         if (PROFILE_PC_COUNT (profile) [i] != 0)
+           {
+             sim_io_printf (sd, "  ");
+             if (i == PROFILE_PC_NR_BUCKETS (profile))
+               sim_io_printf (sd, "%10s:", "overflow");
+             else
+               sim_io_printf (sd, "0x%08lx:",
+                              (long) (PROFILE_PC_START (profile)
+                                      + (i * PROFILE_PC_BUCKET_SIZE (profile))));
+             sim_io_printf (sd, " %*s",
+                            max_val < 10000 ? 5 : 10,
+                            COMMAS (PROFILE_PC_COUNT (profile) [i]));
+             sim_io_printf (sd, " %4.1f",
+                            (PROFILE_PC_COUNT (profile) [i] * 100.0) / total);
+             sim_io_printf (sd, ": ");
+             print_bar (sd, PROFILE_HISTOGRAM_WIDTH,
+                        PROFILE_PC_COUNT (profile) [i],
+                        max_val);
+             sim_io_printf (sd, "\n");
+           }
+       }
+    }
+
+  /* dump the histogram to the file "gmon.out" using BSD's gprof file
+     format */
+  /* Since a profile data file is in the native format of the host on
+     which the profile is being, endian issues are not considered in
+     the code below. */
+  /* FIXME: Is this the best place for this code? */
+  {
+    FILE *pf = fopen ("gmon.out", "wb");
+    
+    if (pf == NULL)
+      sim_io_eprintf (sd, "Failed to open \"gmon.out\" profile file\n");
+    else
+      {
+       int ok;
+       /* FIXME: what if the target has a 64 bit PC? */
+       unsigned32 header[3];
+       unsigned loop;
+       if (PROFILE_PC_END (profile) != 0)
+         {
+           header[0] = PROFILE_PC_START (profile);
+           header[1] = PROFILE_PC_END (profile);
+         }
+       else
+         {
+           header[0] = 0;
+           header[1] = 0;
+         }
+       /* size of sample buffer (+ header) */
+       header[2] = PROFILE_PC_NR_BUCKETS (profile) * 2 + sizeof (header);
+       ok = fwrite (&header, sizeof (header), 1, pf);
+       for (loop = 0;
+            ok && (loop < PROFILE_PC_NR_BUCKETS (profile));
+            loop++)
+         {
+           signed16 sample;
+           if (PROFILE_PC_COUNT (profile) [loop] >= 0xffff)
+             sample = 0xffff;
+           else
+             sample = PROFILE_PC_COUNT (profile) [loop];
+           ok = fwrite (&sample, sizeof (sample), 1, pf);
+         }
+       if (ok == 0)
+         sim_io_eprintf (sd, "Failed to write to \"gmon.out\" profile file\n");
+       fclose(pf);
+      }
+  }
+
+  sim_io_printf (sd, "\n");
 }
+
+#endif
 \f
 /* Summary printing support.  */
 
@@ -201,12 +544,16 @@ profile_print_insn (sim_cpu *cpu, int verbose)
   PROFILE_DATA *data = CPU_PROFILE_DATA (cpu);
   char comma_buf[20];
 
-  sim_io_printf (sd, "Instruction Statistics\n\n");
+  sim_io_printf (sd, "Instruction Statistics:\n\n");
 
   /* First pass over data computes various things.  */
-  max_val = total = max_name_len = 0;
-  for (i = 1; i < MAX_INSNS; ++i)
+  max_val = 0;
+  total = 0;
+  max_name_len = 0;
+  for (i = 0; i < MAX_INSNS; ++i)
     {
+      if (INSN_NAME (i) == NULL)
+       continue;
       total += PROFILE_INSN_COUNT (data) [i];
       if (PROFILE_INSN_COUNT (data) [i] > max_val)
        max_val = PROFILE_INSN_COUNT (data) [i];
@@ -214,6 +561,9 @@ profile_print_insn (sim_cpu *cpu, int verbose)
       if (n > max_name_len)
        max_name_len = n;
     }
+  /* set the total insn count, in case client is being lazy */
+  if (PROFILE_TOTAL_INSN_COUNT (data))
+    PROFILE_TOTAL_INSN_COUNT (data) = total;
 
   sim_io_printf (sd, "  Total: %s insns\n", COMMAS (total));
 
@@ -221,8 +571,10 @@ profile_print_insn (sim_cpu *cpu, int verbose)
     {
       /* Now we can print the histogram.  */
       sim_io_printf (sd, "\n");
-      for (i = 1; i < MAX_INSNS; ++i)
+      for (i = 0; i < MAX_INSNS; ++i)
        {
+         if (INSN_NAME (i) == NULL)
+           continue;
          if (PROFILE_INSN_COUNT (data) [i] != 0)
            {
              sim_io_printf (sd, "   %*s: %*s: ",
@@ -255,7 +607,7 @@ profile_print_memory (sim_cpu *cpu, int verbose)
   PROFILE_DATA *data = CPU_PROFILE_DATA (cpu);
   char comma_buf[20];
 
-  sim_io_printf (sd, "Memory Access Statistics\n\n");
+  sim_io_printf (sd, "Memory Access Statistics:\n\n");
 
   /* First pass over data computes various things.  */
   max_val = total_read = total_write = max_name_len = 0;
@@ -316,6 +668,76 @@ profile_print_memory (sim_cpu *cpu, int verbose)
 
 #endif
 
+#if WITH_PROFILE_CORE_P
+
+static void
+profile_print_core (sim_cpu *cpu, int verbose)
+{
+  unsigned int total;
+  unsigned int max_val;
+  /* FIXME: Need to add smp support.  */
+  SIM_DESC sd = CPU_STATE (cpu);
+  PROFILE_DATA *data = CPU_PROFILE_DATA (cpu);
+  char comma_buf[20];
+
+  sim_io_printf (sd, "CORE Statistics:\n\n");
+
+  /* First pass over data computes various things.  */
+  {
+    sim_core_maps map;
+    total = 0;
+    max_val = 0;
+    for (map = 0; map < nr_sim_core_maps; map++)
+      {
+       total += PROFILE_CORE_COUNT (data) [map];
+       if (PROFILE_CORE_COUNT (data) [map] > max_val)
+         max_val = PROFILE_CORE_COUNT (data) [map];
+      }
+  }
+
+  /* One could use PROFILE_LABEL_WIDTH here.  I chose not to.  */
+  sim_io_printf (sd, "  Total:  %s accesses\n",
+                COMMAS (total));
+
+  if (verbose && max_val != 0)
+    {
+      sim_core_maps map;
+      /* Now we can print the histogram.  */
+      sim_io_printf (sd, "\n");
+      for (map = 0; map < nr_sim_core_maps; map++)
+       {
+         if (PROFILE_CORE_COUNT (data) [map] != 0)
+           {
+             switch (map)
+               {
+               case sim_core_read_map:
+                 sim_io_printf (sd, "     read:");
+                 break;
+               case sim_core_write_map:
+                 sim_io_printf (sd, "    write:");
+                 break;
+               case sim_core_execute_map:
+                 sim_io_printf (sd, "     exec:");
+                 break;
+               case nr_sim_core_maps:
+                 ; /* ignore */
+               }
+             sim_io_printf (sd, "%*s: ",
+                            max_val < 10000 ? 5 : 10,
+                            COMMAS (PROFILE_CORE_COUNT (data) [map]));
+             print_bar (sd, PROFILE_HISTOGRAM_WIDTH,
+                        PROFILE_CORE_COUNT (data) [map],
+                        max_val);
+             sim_io_printf (sd, "\n");
+           }
+       }
+    }
+
+  sim_io_printf (sd, "\n");
+}
+
+#endif
+
 #if WITH_PROFILE_MODEL_P
 
 static void
@@ -330,7 +752,7 @@ profile_print_model (sim_cpu *cpu, int verbose)
   char comma_buf[20];
 
   sim_io_printf (sd, "Model %s Timing Information\n\n",
-                MODEL_NAME (STATE_MODEL (sd)));
+                MODEL_NAME (CPU_MODEL (cpu)));
   sim_io_printf (sd, "  %-*s %s\n",
                 PROFILE_LABEL_WIDTH, "Taken branches:",
                 COMMAS (PROFILE_MODEL_TAKEN_COUNT (data)));
@@ -351,6 +773,9 @@ profile_print_model (sim_cpu *cpu, int verbose)
 
 #endif
 
+
+#if WITH_PROFILE_INSN_P || WITH_PROFILE_MEMORY_P || WITH_PROFILE_CORE_P || WITH_PROFILE_PC_P
+
 static void
 print_bar (SIM_DESC sd, unsigned int width,
           unsigned int val, unsigned int max_val)
@@ -363,6 +788,8 @@ print_bar (SIM_DESC sd, unsigned int width,
     sim_io_printf (sd, "*");
 }
 
+#endif
+
 /* Print the simulator's execution speed for CPU.  */
 
 static void
@@ -370,7 +797,7 @@ profile_print_speed (sim_cpu *cpu)
 {
   SIM_DESC sd = CPU_STATE (cpu);
   PROFILE_DATA *data = CPU_PROFILE_DATA (cpu);
-  unsigned long milliseconds = PROFILE_EXEC_TIME (data);
+  unsigned long milliseconds = sim_events_elapsed_time (sd);
   unsigned long total = PROFILE_TOTAL_INSN_COUNT (data);
   char comma_buf[20];
 
@@ -455,6 +882,11 @@ profile_print (SIM_DESC sd, int verbose,
        profile_print_memory (cpu, verbose);
 #endif
 
+#if WITH_PROFILE_CORE_P
+      if (PROFILE_FLAGS (data) [PROFILE_CORE_IDX])
+       profile_print_core (cpu, verbose);
+#endif
+
 #if WITH_PROFILE_MODEL_P
       if (PROFILE_FLAGS (data) [PROFILE_MODEL_IDX])
        profile_print_model (cpu, verbose);
@@ -465,6 +897,11 @@ profile_print (SIM_DESC sd, int verbose,
        scache_print_profile (cpu, verbose);
 #endif
 
+#if WITH_PROFILE_PC_P
+      if (PROFILE_FLAGS (data) [PROFILE_PC_IDX])
+       profile_print_pc (cpu, verbose);
+#endif
+
       /* Print cpu-specific data before the execution speed.  */
       if (misc_cpu != NULL)
        (*misc_cpu) (cpu, verbose);
@@ -480,3 +917,45 @@ profile_print (SIM_DESC sd, int verbose,
   if (misc != NULL)
     (*misc) (sd, verbose);
 }
+\f
+/* Install profiling support in the simulator.  */
+
+SIM_RC
+profile_install (SIM_DESC sd)
+{
+  int i;
+
+  SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
+  sim_add_option_table (sd, profile_options);
+  for (i = 0; i < MAX_NR_PROCESSORS; ++i)
+    memset (CPU_PROFILE_DATA (STATE_CPU (sd, i)), 0,
+           sizeof (* CPU_PROFILE_DATA (STATE_CPU (sd, i))));
+#if WITH_PROFILE_PC_P
+  sim_module_add_uninstall_fn (sd, profile_pc_uninstall);
+  sim_module_add_init_fn (sd, profile_pc_init);
+#endif
+  sim_module_add_uninstall_fn (sd, profile_uninstall);
+  return SIM_RC_OK;
+}
+
+static void
+profile_uninstall (SIM_DESC sd)
+{
+  int i,j;
+
+  for (i = 0; i < MAX_NR_PROCESSORS; ++i)
+    {
+      PROFILE_DATA *data = CPU_PROFILE_DATA (STATE_CPU (sd, i));
+      if (PROFILE_FILE (data) != NULL)
+       {
+         /* If output from different cpus is going to the same file,
+            avoid closing the file twice.  */
+         for (j = 0; j < i; ++j)
+           if (PROFILE_FILE (CPU_PROFILE_DATA (STATE_CPU (sd, j)))
+               == PROFILE_FILE (data))
+             break;
+         if (i == j)
+           fclose (PROFILE_FILE (data));
+       }
+    }
+}