OSDN Git Service

e3d4ed307ad26aeb7fb594814f95a95b55f01bd3
[pf3gnuchains/pf3gnuchains4x.git] / sim / common / sim-profile.c
1 /* Default profiling support.
2    Copyright (C) 1996, 1997, 1998, 2000, 2001, 2007
3    Free Software Foundation, Inc.
4    Contributed by Cygnus Support.
5
6 This file is part of GDB, the GNU debugger.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation, Inc.,
20 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
21
22 #include "sim-main.h"
23 #include "sim-io.h"
24 #include "sim-options.h"
25 #include "sim-assert.h"
26
27 #ifdef HAVE_STDLIB_H
28 #include <stdlib.h>
29 #endif
30
31 #ifdef HAVE_STRING_H
32 #include <string.h>
33 #else
34 #ifdef HAVE_STRINGS_H
35 #include <strings.h>
36 #endif
37 #endif
38 #include <ctype.h>
39
40 #define COMMAS(n) sim_add_commas (comma_buf, sizeof (comma_buf), (n))
41
42 static MODULE_INIT_FN profile_init;
43 static MODULE_UNINSTALL_FN profile_uninstall;
44
45 static DECLARE_OPTION_HANDLER (profile_option_handler);
46
47 enum {
48   OPTION_PROFILE_INSN = OPTION_START,
49   OPTION_PROFILE_MEMORY,
50   OPTION_PROFILE_MODEL,
51   OPTION_PROFILE_FILE,
52   OPTION_PROFILE_CORE,
53   OPTION_PROFILE_CPU_FREQUENCY,
54   OPTION_PROFILE_PC,
55   OPTION_PROFILE_PC_RANGE,
56   OPTION_PROFILE_PC_GRANULARITY,
57   OPTION_PROFILE_RANGE,
58   OPTION_PROFILE_FUNCTION
59 };
60
61 static const OPTION profile_options[] = {
62   { {"profile", optional_argument, NULL, 'p'},
63       'p', "on|off", "Perform profiling",
64       profile_option_handler },
65   { {"profile-insn", optional_argument, NULL, OPTION_PROFILE_INSN},
66       '\0', "on|off", "Perform instruction profiling",
67       profile_option_handler },
68   { {"profile-memory", optional_argument, NULL, OPTION_PROFILE_MEMORY},
69       '\0', "on|off", "Perform memory profiling",
70       profile_option_handler },
71   { {"profile-core", optional_argument, NULL, OPTION_PROFILE_CORE},
72       '\0', "on|off", "Perform CORE profiling",
73       profile_option_handler },
74   { {"profile-model", optional_argument, NULL, OPTION_PROFILE_MODEL},
75       '\0', "on|off", "Perform model profiling",
76       profile_option_handler },
77   { {"profile-cpu-frequency", required_argument, NULL,
78      OPTION_PROFILE_CPU_FREQUENCY},
79       '\0', "CPU FREQUENCY", "Specify the speed of the simulated cpu clock",
80       profile_option_handler },
81
82   { {"profile-file", required_argument, NULL, OPTION_PROFILE_FILE},
83       '\0', "FILE NAME", "Specify profile output file",
84       profile_option_handler },
85
86   { {"profile-pc", optional_argument, NULL, OPTION_PROFILE_PC},
87       '\0', "on|off", "Perform PC profiling",
88       profile_option_handler },
89   { {"profile-pc-frequency", required_argument, NULL, 'F'},
90       'F', "PC PROFILE FREQUENCY", "Specified PC profiling frequency",
91       profile_option_handler },
92   { {"profile-pc-size", required_argument, NULL, 'S'},
93       'S', "PC PROFILE SIZE", "Specify PC profiling size",
94       profile_option_handler },
95   { {"profile-pc-granularity", required_argument, NULL, OPTION_PROFILE_PC_GRANULARITY},
96       '\0', "PC PROFILE GRANULARITY", "Specify PC profiling sample coverage",
97       profile_option_handler },
98   { {"profile-pc-range", required_argument, NULL, OPTION_PROFILE_PC_RANGE},
99       '\0', "BASE,BOUND", "Specify PC profiling address range",
100       profile_option_handler },
101
102 #ifdef SIM_HAVE_ADDR_RANGE
103   { {"profile-range", required_argument, NULL, OPTION_PROFILE_RANGE},
104       '\0', "START,END", "Specify range of addresses for instruction and model profiling",
105       profile_option_handler },
106 #if 0 /*wip*/
107   { {"profile-function", required_argument, NULL, OPTION_PROFILE_FUNCTION},
108       '\0', "FUNCTION", "Specify function to profile",
109       profile_option_handler },
110 #endif
111 #endif
112
113   { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
114 };
115
116 /* Set/reset the profile options indicated in MASK.  */
117
118 SIM_RC
119 set_profile_option_mask (SIM_DESC sd, const char *name, int mask, const char *arg)
120 {
121   int profile_nr;
122   int cpu_nr;
123   int profile_val = 1;
124
125   if (arg != NULL)
126     {
127       if (strcmp (arg, "yes") == 0
128           || strcmp (arg, "on") == 0
129           || strcmp (arg, "1") == 0)
130         profile_val = 1;
131       else if (strcmp (arg, "no") == 0
132                || strcmp (arg, "off") == 0
133                || strcmp (arg, "0") == 0)
134         profile_val = 0;
135       else
136         {
137           sim_io_eprintf (sd, "Argument `%s' for `--profile%s' invalid, one of `on', `off', `yes', `no' expected\n", arg, name);
138           return SIM_RC_FAIL;
139         }
140     }
141
142   /* update applicable profile bits */
143   for (profile_nr = 0; profile_nr < MAX_PROFILE_VALUES; ++profile_nr)
144     {
145       if ((mask & (1 << profile_nr)) == 0)
146         continue;
147
148 #if 0 /* see sim-trace.c, set flags in STATE here if/when there are any */
149       /* Set non-cpu specific values.  */
150       switch (profile_nr)
151         {
152         case ??? :
153           break;
154         }
155 #endif
156
157       /* Set cpu values.  */
158       for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++)
159         {
160           CPU_PROFILE_FLAGS (STATE_CPU (sd, cpu_nr))[profile_nr] = profile_val;
161         }
162     }
163
164   /* Re-compute the cpu profile summary.  */
165   if (profile_val)
166     {
167       for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++)
168         CPU_PROFILE_DATA (STATE_CPU (sd, cpu_nr))->profile_any_p = 1;
169     }
170   else
171     {
172       for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++)
173         {
174           CPU_PROFILE_DATA (STATE_CPU (sd, cpu_nr))->profile_any_p = 0;
175           for (profile_nr = 0; profile_nr < MAX_PROFILE_VALUES; ++profile_nr)
176             {
177               if (CPU_PROFILE_FLAGS (STATE_CPU (sd, cpu_nr))[profile_nr])
178                 {
179                   CPU_PROFILE_DATA (STATE_CPU (sd, cpu_nr))->profile_any_p = 1;
180                   break;
181                 }
182             }
183         }
184     }  
185
186   return SIM_RC_OK;
187 }
188
189 /* Set one profile option based on its IDX value.
190    Not static as cgen-scache.c uses it.  */
191
192 SIM_RC
193 sim_profile_set_option (SIM_DESC sd, const char *name, int idx, const char *arg)
194 {
195   return set_profile_option_mask (sd, name, 1 << idx, arg);
196 }
197
198 static SIM_RC
199 parse_frequency (SIM_DESC sd, const char *arg, unsigned long *freq)
200 {
201   const char *ch;
202   /* First, parse a decimal number.  */
203   *freq = 0;
204   ch = arg;
205   if (isdigit (*arg))
206     {
207       for (/**/; *ch != '\0'; ++ch)
208         {
209           if (! isdigit (*ch))
210             break;
211           *freq = *freq * 10 + (*ch - '0');
212         }
213
214       /* Accept KHz, MHz or Hz as a suffix.  */
215       if (tolower (*ch) == 'm')
216         {
217           *freq *= 1000000;
218           ++ch;
219         }
220       else if (tolower (*ch) == 'k')
221         {
222           *freq *= 1000;
223           ++ch;
224         }
225
226       if (tolower (*ch) == 'h')
227         {
228           ++ch;
229           if (tolower (*ch) == 'z')
230             ++ch;
231         }
232     }
233
234   if (*ch != '\0')
235     {
236       sim_io_eprintf (sd, "Invalid argument for --profile-cpu-frequency: %s\n",
237                       arg);
238       *freq = 0;
239       return SIM_RC_FAIL;
240     }
241
242   return SIM_RC_OK;
243 }
244
245 static SIM_RC
246 profile_option_handler (SIM_DESC sd,
247                         sim_cpu *cpu,
248                         int opt,
249                         char *arg,
250                         int is_command)
251 {
252   int cpu_nr;
253
254   /* FIXME: Need to handle `cpu' arg.  */
255
256   switch (opt)
257     {
258     case 'p' :
259       if (! WITH_PROFILE)
260         sim_io_eprintf (sd, "Profiling not compiled in, `-p' ignored\n");
261       else
262         return set_profile_option_mask (sd, "profile", PROFILE_USEFUL_MASK,
263                                         arg);
264       break;
265
266     case OPTION_PROFILE_INSN :
267       if (WITH_PROFILE_INSN_P)
268         return sim_profile_set_option (sd, "-insn", PROFILE_INSN_IDX, arg);
269       else
270         sim_io_eprintf (sd, "Instruction profiling not compiled in, `--profile-insn' ignored\n");
271       break;
272
273     case OPTION_PROFILE_MEMORY :
274       if (WITH_PROFILE_MEMORY_P)
275         return sim_profile_set_option (sd, "-memory", PROFILE_MEMORY_IDX, arg);
276       else
277         sim_io_eprintf (sd, "Memory profiling not compiled in, `--profile-memory' ignored\n");
278       break;
279
280     case OPTION_PROFILE_CORE :
281       if (WITH_PROFILE_CORE_P)
282         return sim_profile_set_option (sd, "-core", PROFILE_CORE_IDX, arg);
283       else
284         sim_io_eprintf (sd, "CORE profiling not compiled in, `--profile-core' ignored\n");
285       break;
286
287     case OPTION_PROFILE_MODEL :
288       if (WITH_PROFILE_MODEL_P)
289         return sim_profile_set_option (sd, "-model", PROFILE_MODEL_IDX, arg);
290       else
291         sim_io_eprintf (sd, "Model profiling not compiled in, `--profile-model' ignored\n");
292       break;
293
294     case OPTION_PROFILE_CPU_FREQUENCY :
295       {
296         unsigned long val;
297         SIM_RC rc = parse_frequency (sd, arg, &val);
298         if (rc == SIM_RC_OK)
299           {
300             for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; ++cpu_nr)
301               PROFILE_CPU_FREQ (CPU_PROFILE_DATA (STATE_CPU (sd,cpu_nr))) = val;
302           }
303         return rc;
304       }
305
306     case OPTION_PROFILE_FILE :
307       /* FIXME: Might want this to apply to pc profiling only,
308          or have two profile file options.  */
309       if (! WITH_PROFILE)
310         sim_io_eprintf (sd, "Profiling not compiled in, `--profile-file' ignored\n");
311       else
312         {
313           FILE *f = fopen (arg, "w");
314
315           if (f == NULL)
316             {
317               sim_io_eprintf (sd, "Unable to open profile output file `%s'\n", arg);
318               return SIM_RC_FAIL;
319             }
320           for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; ++cpu_nr)
321             PROFILE_FILE (CPU_PROFILE_DATA (STATE_CPU (sd, cpu_nr))) = f;
322         }
323       break;
324
325     case OPTION_PROFILE_PC:
326       if (WITH_PROFILE_PC_P)
327         return sim_profile_set_option (sd, "-pc", PROFILE_PC_IDX, arg);
328       else
329         sim_io_eprintf (sd, "PC profiling not compiled in, `--profile-pc' ignored\n");
330       break;
331
332     case 'F' :
333       if (WITH_PROFILE_PC_P)
334         {
335           /* FIXME: Validate arg.  */
336           int val = atoi (arg);
337           for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; ++cpu_nr)
338             PROFILE_PC_FREQ (CPU_PROFILE_DATA (STATE_CPU (sd, cpu_nr))) = val;
339           for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; ++cpu_nr)
340             CPU_PROFILE_FLAGS (STATE_CPU (sd, cpu_nr))[PROFILE_PC_IDX] = 1;
341         }
342       else
343         sim_io_eprintf (sd, "PC profiling not compiled in, `--profile-pc-frequency' ignored\n");
344       break;
345
346     case 'S' :
347       if (WITH_PROFILE_PC_P)
348         {
349           /* FIXME: Validate arg.  */
350           int val = atoi (arg);
351           for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; ++cpu_nr)
352             PROFILE_PC_NR_BUCKETS (CPU_PROFILE_DATA (STATE_CPU (sd, cpu_nr))) = val;
353           for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; ++cpu_nr)
354             CPU_PROFILE_FLAGS (STATE_CPU (sd, cpu_nr))[PROFILE_PC_IDX] = 1;
355         }
356       else
357         sim_io_eprintf (sd, "PC profiling not compiled in, `--profile-pc-size' ignored\n");
358       break;
359
360     case OPTION_PROFILE_PC_GRANULARITY:
361       if (WITH_PROFILE_PC_P)
362         {
363           int shift;
364           int val = atoi (arg);
365           /* check that the granularity is a power of two */
366           shift = 0;
367           while (val > (1 << shift))
368             {
369               shift += 1;
370             }
371           if (val != (1 << shift))
372             {
373               sim_io_eprintf (sd, "PC profiling granularity not a power of two\n");
374               return SIM_RC_FAIL;
375             }
376           if (shift == 0)
377             {
378               sim_io_eprintf (sd, "PC profiling granularity too small");
379               return SIM_RC_FAIL;
380             }
381           for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; ++cpu_nr)
382             PROFILE_PC_SHIFT (CPU_PROFILE_DATA (STATE_CPU (sd, cpu_nr))) = shift;
383           for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; ++cpu_nr)
384             CPU_PROFILE_FLAGS (STATE_CPU (sd, cpu_nr))[PROFILE_PC_IDX] = 1;
385         }
386       else
387         sim_io_eprintf (sd, "PC profiling not compiled in, `--profile-pc-granularity' ignored\n");
388       break;
389
390     case OPTION_PROFILE_PC_RANGE:
391       if (WITH_PROFILE_PC_P)
392         {
393           /* FIXME: Validate args */
394           char *chp = arg;
395           unsigned long base;
396           unsigned long bound;
397           base = strtoul (chp, &chp, 0);
398           if (*chp != ',')
399             {
400               sim_io_eprintf (sd, "--profile-pc-range missing BOUND argument\n");
401               return SIM_RC_FAIL;
402             }
403           bound = strtoul (chp + 1, NULL, 0);
404           for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; ++cpu_nr)
405             {
406               PROFILE_PC_START (CPU_PROFILE_DATA (STATE_CPU (sd, cpu_nr))) = base;
407               PROFILE_PC_END (CPU_PROFILE_DATA (STATE_CPU (sd, cpu_nr))) = bound;
408             }         
409           for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; ++cpu_nr)
410             CPU_PROFILE_FLAGS (STATE_CPU (sd, cpu_nr))[PROFILE_PC_IDX] = 1;
411         }
412       else
413         sim_io_eprintf (sd, "PC profiling not compiled in, `--profile-pc-range' ignored\n");
414       break;
415
416 #ifdef SIM_HAVE_ADDR_RANGE
417     case OPTION_PROFILE_RANGE :
418       if (WITH_PROFILE)
419         {
420           char *chp = arg;
421           unsigned long start,end;
422           start = strtoul (chp, &chp, 0);
423           if (*chp != ',')
424             {
425               sim_io_eprintf (sd, "--profile-range missing END argument\n");
426               return SIM_RC_FAIL;
427             }
428           end = strtoul (chp + 1, NULL, 0);
429           /* FIXME: Argument validation.  */
430           if (cpu != NULL)
431             sim_addr_range_add (PROFILE_RANGE (CPU_PROFILE_DATA (cpu)),
432                                 start, end);
433           else
434             for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; ++cpu_nr)
435               sim_addr_range_add (PROFILE_RANGE (CPU_PROFILE_DATA (STATE_CPU (sd, cpu_nr))),
436                                   start, end);
437         }
438       else
439         sim_io_eprintf (sd, "Profiling not compiled in, `--profile-range' ignored\n");
440       break;
441
442     case OPTION_PROFILE_FUNCTION :
443       if (WITH_PROFILE)
444         {
445           /*wip: need to compute function range given name*/
446         }
447       else
448         sim_io_eprintf (sd, "Profiling not compiled in, `--profile-function' ignored\n");
449       break;
450 #endif /* SIM_HAVE_ADDR_RANGE */
451     }
452
453   return SIM_RC_OK;
454 }
455 \f
456 /* PC profiling support */
457
458 #if WITH_PROFILE_PC_P
459
460 static void
461 profile_pc_cleanup (SIM_DESC sd)
462 {
463   int n;
464   for (n = 0; n < MAX_NR_PROCESSORS; n++)
465     {
466       sim_cpu *cpu = STATE_CPU (sd, n);
467       PROFILE_DATA *data = CPU_PROFILE_DATA (cpu);
468       if (PROFILE_PC_COUNT (data) != NULL)
469         zfree (PROFILE_PC_COUNT (data));
470       PROFILE_PC_COUNT (data) = NULL;
471       if (PROFILE_PC_EVENT (data) != NULL)
472         sim_events_deschedule (sd, PROFILE_PC_EVENT (data));
473       PROFILE_PC_EVENT (data) = NULL;
474     }
475 }
476
477
478 static void
479 profile_pc_uninstall (SIM_DESC sd)
480 {
481   profile_pc_cleanup (sd);
482 }
483
484 static void
485 profile_pc_event (SIM_DESC sd,
486                   void *data)
487 {
488   sim_cpu *cpu = (sim_cpu*) data;
489   PROFILE_DATA *profile = CPU_PROFILE_DATA (cpu);
490   address_word pc;
491   unsigned i;
492   switch (STATE_WATCHPOINTS (sd)->sizeof_pc)
493     {
494     case 2: pc = *(unsigned_2*)(STATE_WATCHPOINTS (sd)->pc) ; break;
495     case 4: pc = *(unsigned_4*)(STATE_WATCHPOINTS (sd)->pc) ; break;
496     case 8: pc = *(unsigned_8*)(STATE_WATCHPOINTS (sd)->pc) ; break;
497     default: pc = 0;
498     }
499   i = (pc - PROFILE_PC_START (profile)) >> PROFILE_PC_SHIFT (profile);
500   if (i < PROFILE_PC_NR_BUCKETS (profile))
501     PROFILE_PC_COUNT (profile) [i] += 1; /* Overflow? */
502   else
503     PROFILE_PC_COUNT (profile) [PROFILE_PC_NR_BUCKETS (profile)] += 1;
504   PROFILE_PC_EVENT (profile) = 
505     sim_events_schedule (sd, PROFILE_PC_FREQ (profile), profile_pc_event, cpu);
506 }
507
508 static SIM_RC
509 profile_pc_init (SIM_DESC sd)
510 {
511   int n;
512   profile_pc_cleanup (sd);
513   for (n = 0; n < MAX_NR_PROCESSORS; n++)
514     {
515       sim_cpu *cpu = STATE_CPU (sd, n);
516       PROFILE_DATA *data = CPU_PROFILE_DATA (cpu);
517       if (CPU_PROFILE_FLAGS (STATE_CPU (sd, n))[PROFILE_PC_IDX]
518           && STATE_WATCHPOINTS (sd)->pc != NULL)
519         {
520           int bucket_size;
521           /* fill in the frequency if not specified */
522           if (PROFILE_PC_FREQ (data) == 0)
523             PROFILE_PC_FREQ (data) = 257;
524           /* fill in the start/end if not specified */
525           if (PROFILE_PC_END (data) == 0)
526             {
527               PROFILE_PC_START (data) = STATE_TEXT_START (sd);
528               PROFILE_PC_END (data) = STATE_TEXT_END (sd);
529             }
530           /* Compute the number of buckets if not specified. */
531           if (PROFILE_PC_NR_BUCKETS (data) == 0)
532             {
533               if (PROFILE_PC_BUCKET_SIZE (data) == 0)
534                 PROFILE_PC_NR_BUCKETS (data) = 16;
535               else
536                 {
537                   if (PROFILE_PC_END (data) == 0)
538                     {
539                       /* nr_buckets = (full-address-range / 2) / (bucket_size / 2) */
540                       PROFILE_PC_NR_BUCKETS (data) =
541                         ((1 << (STATE_WATCHPOINTS (sd)->sizeof_pc) * (8 - 1))
542                          / (PROFILE_PC_BUCKET_SIZE (data) / 2));
543                     }
544                   else
545                     {
546                       PROFILE_PC_NR_BUCKETS (data) =
547                         ((PROFILE_PC_END (data)
548                           - PROFILE_PC_START (data)
549                           + PROFILE_PC_BUCKET_SIZE (data) - 1)
550                          / PROFILE_PC_BUCKET_SIZE (data));
551                     }
552                 }
553             }
554           /* Compute the bucket size if not specified.  Ensure that it
555              is rounded up to the next power of two */
556           if (PROFILE_PC_BUCKET_SIZE (data) == 0)
557             {
558               if (PROFILE_PC_END (data) == 0)
559                 /* bucket_size = (full-address-range / 2) / (nr_buckets / 2) */
560                 bucket_size = ((1 << ((STATE_WATCHPOINTS (sd)->sizeof_pc * 8) - 1))
561                                / (PROFILE_PC_NR_BUCKETS (data) / 2));
562               else
563                 bucket_size = ((PROFILE_PC_END (data)
564                                 - PROFILE_PC_START (data)
565                                 + PROFILE_PC_NR_BUCKETS (data) - 1)
566                                / PROFILE_PC_NR_BUCKETS (data));
567               PROFILE_PC_SHIFT (data) = 0;
568               while (bucket_size > PROFILE_PC_BUCKET_SIZE (data))
569                 {
570                   PROFILE_PC_SHIFT (data) += 1;
571                 }
572             }
573           /* Align the end address with bucket size */
574           if (PROFILE_PC_END (data) != 0)
575             PROFILE_PC_END (data) = (PROFILE_PC_START (data)
576                                      + (PROFILE_PC_BUCKET_SIZE (data)
577                                         * PROFILE_PC_NR_BUCKETS (data)));
578           /* create the relevant buffers */
579           PROFILE_PC_COUNT (data) =
580             NZALLOC (unsigned, PROFILE_PC_NR_BUCKETS (data) + 1);
581           PROFILE_PC_EVENT (data) =
582             sim_events_schedule (sd,
583                                  PROFILE_PC_FREQ (data),
584                                  profile_pc_event,
585                                  cpu);
586         }
587     }
588   return SIM_RC_OK;
589 }
590
591 static void
592 profile_print_pc (sim_cpu *cpu, int verbose)
593 {
594   SIM_DESC sd = CPU_STATE (cpu);
595   PROFILE_DATA *profile = CPU_PROFILE_DATA (cpu);
596   char comma_buf[20];
597   unsigned max_val;
598   unsigned total;
599   unsigned i;
600
601   if (PROFILE_PC_COUNT (profile) == 0)
602     return;
603
604   sim_io_printf (sd, "Program Counter Statistics:\n\n");
605
606   /* First pass over data computes various things.  */
607   max_val = 0;
608   total = 0;
609   for (i = 0; i <= PROFILE_PC_NR_BUCKETS (profile); ++i)
610     {
611       total += PROFILE_PC_COUNT (profile) [i];
612       if (PROFILE_PC_COUNT (profile) [i] > max_val)
613         max_val = PROFILE_PC_COUNT (profile) [i];
614     }
615
616   sim_io_printf (sd, "  Total samples: %s\n",
617                  COMMAS (total));
618   sim_io_printf (sd, "  Granularity: %s bytes per bucket\n",
619                  COMMAS (PROFILE_PC_BUCKET_SIZE (profile)));
620   sim_io_printf (sd, "  Size: %s buckets\n",
621                  COMMAS (PROFILE_PC_NR_BUCKETS (profile)));
622   sim_io_printf (sd, "  Frequency: %s cycles per sample\n",
623                  COMMAS (PROFILE_PC_FREQ (profile)));
624
625   if (PROFILE_PC_END (profile) != 0)
626     sim_io_printf (sd, "  Range: 0x%lx 0x%lx\n",
627                    (long) PROFILE_PC_START (profile),
628                    (long) PROFILE_PC_END (profile));
629
630   if (verbose && max_val != 0)
631     {
632       /* Now we can print the histogram.  */
633       sim_io_printf (sd, "\n");
634       for (i = 0; i <= PROFILE_PC_NR_BUCKETS (profile); ++i)
635         {
636           if (PROFILE_PC_COUNT (profile) [i] != 0)
637             {
638               sim_io_printf (sd, "  ");
639               if (i == PROFILE_PC_NR_BUCKETS (profile))
640                 sim_io_printf (sd, "%10s:", "overflow");
641               else
642                 sim_io_printf (sd, "0x%08lx:",
643                                (long) (PROFILE_PC_START (profile)
644                                        + (i * PROFILE_PC_BUCKET_SIZE (profile))));
645               sim_io_printf (sd, " %*s",
646                              max_val < 10000 ? 5 : 10,
647                              COMMAS (PROFILE_PC_COUNT (profile) [i]));
648               sim_io_printf (sd, " %4.1f",
649                              (PROFILE_PC_COUNT (profile) [i] * 100.0) / total);
650               sim_io_printf (sd, ": ");
651               sim_profile_print_bar (sd, PROFILE_HISTOGRAM_WIDTH,
652                                      PROFILE_PC_COUNT (profile) [i],
653                                      max_val);
654               sim_io_printf (sd, "\n");
655             }
656         }
657     }
658
659   /* dump the histogram to the file "gmon.out" using BSD's gprof file
660      format */
661   /* Since a profile data file is in the native format of the host on
662      which the profile is being, endian issues are not considered in
663      the code below. */
664   /* FIXME: Is this the best place for this code? */
665   {
666     FILE *pf = fopen ("gmon.out", "wb");
667     
668     if (pf == NULL)
669       sim_io_eprintf (sd, "Failed to open \"gmon.out\" profile file\n");
670     else
671       {
672         int ok;
673         /* FIXME: what if the target has a 64 bit PC? */
674         unsigned32 header[3];
675         unsigned loop;
676         if (PROFILE_PC_END (profile) != 0)
677           {
678             header[0] = PROFILE_PC_START (profile);
679             header[1] = PROFILE_PC_END (profile);
680           }
681         else
682           {
683             header[0] = 0;
684             header[1] = 0;
685           }
686         /* size of sample buffer (+ header) */
687         header[2] = PROFILE_PC_NR_BUCKETS (profile) * 2 + sizeof (header);
688
689         /* Header must be written out in target byte order.  */
690         H2T (header[0]);
691         H2T (header[1]);
692         H2T (header[2]);
693
694         ok = fwrite (&header, sizeof (header), 1, pf);
695         for (loop = 0;
696              ok && (loop < PROFILE_PC_NR_BUCKETS (profile));
697              loop++)
698           {
699             signed16 sample;
700             if (PROFILE_PC_COUNT (profile) [loop] >= 0xffff)
701               sample = 0xffff;
702             else
703               sample = PROFILE_PC_COUNT (profile) [loop];
704             H2T (sample);
705             ok = fwrite (&sample, sizeof (sample), 1, pf);
706           }
707         if (ok == 0)
708           sim_io_eprintf (sd, "Failed to write to \"gmon.out\" profile file\n");
709         fclose(pf);
710       }
711   }
712
713   sim_io_printf (sd, "\n");
714 }
715
716 #endif
717 \f
718 /* Summary printing support.  */
719
720 #if WITH_PROFILE_INSN_P
721
722 static SIM_RC
723 profile_insn_init (SIM_DESC sd)
724 {
725   int c;
726
727   for (c = 0; c < MAX_NR_PROCESSORS; ++c)
728     {
729       sim_cpu *cpu = STATE_CPU (sd, c);
730
731       if (CPU_MAX_INSNS (cpu) > 0)
732         PROFILE_INSN_COUNT (CPU_PROFILE_DATA (cpu)) = NZALLOC (unsigned int, CPU_MAX_INSNS (cpu));
733     }
734
735   return SIM_RC_OK;
736 }
737
738 static void
739 profile_print_insn (sim_cpu *cpu, int verbose)
740 {
741   unsigned int i, n, total, max_val, max_name_len;
742   SIM_DESC sd = CPU_STATE (cpu);
743   PROFILE_DATA *data = CPU_PROFILE_DATA (cpu);
744   char comma_buf[20];
745
746   /* If MAX_INSNS not set, insn profiling isn't supported.  */
747   if (CPU_MAX_INSNS (cpu) == 0)
748     return;
749
750   sim_io_printf (sd, "Instruction Statistics");
751 #ifdef SIM_HAVE_ADDR_RANGE
752   if (PROFILE_RANGE (data)->ranges)
753     sim_io_printf (sd, " (for selected address range(s))");
754 #endif
755   sim_io_printf (sd, "\n\n");
756
757   /* First pass over data computes various things.  */
758   max_val = 0;
759   total = 0;
760   max_name_len = 0;
761   for (i = 0; i < CPU_MAX_INSNS (cpu); ++i)
762     {
763       const char *name = (*CPU_INSN_NAME (cpu)) (cpu, i);
764
765       if (name == NULL)
766         continue;
767       total += PROFILE_INSN_COUNT (data) [i];
768       if (PROFILE_INSN_COUNT (data) [i] > max_val)
769         max_val = PROFILE_INSN_COUNT (data) [i];
770       n = strlen (name);
771       if (n > max_name_len)
772         max_name_len = n;
773     }
774   /* set the total insn count, in case client is being lazy */
775   if (! PROFILE_TOTAL_INSN_COUNT (data))
776     PROFILE_TOTAL_INSN_COUNT (data) = total;
777
778   sim_io_printf (sd, "  Total: %s insns\n", COMMAS (total));
779
780   if (verbose && max_val != 0)
781     {
782       /* Now we can print the histogram.  */
783       sim_io_printf (sd, "\n");
784       for (i = 0; i < CPU_MAX_INSNS (cpu); ++i)
785         {
786           const char *name = (*CPU_INSN_NAME (cpu)) (cpu, i);
787
788           if (name == NULL)
789             continue;
790           if (PROFILE_INSN_COUNT (data) [i] != 0)
791             {
792               sim_io_printf (sd, "   %*s: %*s: ",
793                              max_name_len, name,
794                              max_val < 10000 ? 5 : 10,
795                              COMMAS (PROFILE_INSN_COUNT (data) [i]));
796               sim_profile_print_bar (sd, PROFILE_HISTOGRAM_WIDTH,
797                                      PROFILE_INSN_COUNT (data) [i],
798                                      max_val);
799               sim_io_printf (sd, "\n");
800             }
801         }
802     }
803
804   sim_io_printf (sd, "\n");
805 }
806
807 #endif
808
809 #if WITH_PROFILE_MEMORY_P
810
811 static void
812 profile_print_memory (sim_cpu *cpu, int verbose)
813 {
814   unsigned int i, n;
815   unsigned int total_read, total_write;
816   unsigned int max_val, max_name_len;
817   /* FIXME: Need to add smp support.  */
818   SIM_DESC sd = CPU_STATE (cpu);
819   PROFILE_DATA *data = CPU_PROFILE_DATA (cpu);
820   char comma_buf[20];
821
822   sim_io_printf (sd, "Memory Access Statistics\n\n");
823
824   /* First pass over data computes various things.  */
825   max_val = total_read = total_write = max_name_len = 0;
826   for (i = 0; i < MODE_TARGET_MAX; ++i)
827     {
828       total_read += PROFILE_READ_COUNT (data) [i];
829       total_write += PROFILE_WRITE_COUNT (data) [i];
830       if (PROFILE_READ_COUNT (data) [i] > max_val)
831         max_val = PROFILE_READ_COUNT (data) [i];
832       if (PROFILE_WRITE_COUNT (data) [i] > max_val)
833         max_val = PROFILE_WRITE_COUNT (data) [i];
834       n = strlen (MODE_NAME (i));
835       if (n > max_name_len)
836         max_name_len = n;
837     }
838
839   /* One could use PROFILE_LABEL_WIDTH here.  I chose not to.  */
840   sim_io_printf (sd, "  Total read:  %s accesses\n",
841                  COMMAS (total_read));
842   sim_io_printf (sd, "  Total write: %s accesses\n",
843                  COMMAS (total_write));
844
845   if (verbose && max_val != 0)
846     {
847       /* FIXME: Need to separate instruction fetches from data fetches
848          as the former swamps the latter.  */
849       /* Now we can print the histogram.  */
850       sim_io_printf (sd, "\n");
851       for (i = 0; i < MODE_TARGET_MAX; ++i)
852         {
853           if (PROFILE_READ_COUNT (data) [i] != 0)
854             {
855               sim_io_printf (sd, "   %*s read:  %*s: ",
856                              max_name_len, MODE_NAME (i),
857                              max_val < 10000 ? 5 : 10,
858                              COMMAS (PROFILE_READ_COUNT (data) [i]));
859               sim_profile_print_bar (sd, PROFILE_HISTOGRAM_WIDTH,
860                                      PROFILE_READ_COUNT (data) [i],
861                                      max_val);
862               sim_io_printf (sd, "\n");
863             }
864           if (PROFILE_WRITE_COUNT (data) [i] != 0)
865             {
866               sim_io_printf (sd, "   %*s write: %*s: ",
867                              max_name_len, MODE_NAME (i),
868                              max_val < 10000 ? 5 : 10,
869                              COMMAS (PROFILE_WRITE_COUNT (data) [i]));
870               sim_profile_print_bar (sd, PROFILE_HISTOGRAM_WIDTH,
871                                      PROFILE_WRITE_COUNT (data) [i],
872                                      max_val);
873               sim_io_printf (sd, "\n");
874             }
875         }
876     }
877
878   sim_io_printf (sd, "\n");
879 }
880
881 #endif
882
883 #if WITH_PROFILE_CORE_P
884
885 static void
886 profile_print_core (sim_cpu *cpu, int verbose)
887 {
888   unsigned int total;
889   unsigned int max_val;
890   /* FIXME: Need to add smp support.  */
891   SIM_DESC sd = CPU_STATE (cpu);
892   PROFILE_DATA *data = CPU_PROFILE_DATA (cpu);
893   char comma_buf[20];
894
895   sim_io_printf (sd, "CORE Statistics\n\n");
896
897   /* First pass over data computes various things.  */
898   {
899     unsigned map;
900     total = 0;
901     max_val = 0;
902     for (map = 0; map < nr_maps; map++)
903       {
904         total += PROFILE_CORE_COUNT (data) [map];
905         if (PROFILE_CORE_COUNT (data) [map] > max_val)
906           max_val = PROFILE_CORE_COUNT (data) [map];
907       }
908   }
909
910   /* One could use PROFILE_LABEL_WIDTH here.  I chose not to.  */
911   sim_io_printf (sd, "  Total:  %s accesses\n",
912                  COMMAS (total));
913
914   if (verbose && max_val != 0)
915     {
916       unsigned map;
917       /* Now we can print the histogram.  */
918       sim_io_printf (sd, "\n");
919       for (map = 0; map < nr_maps; map++)
920         {
921           if (PROFILE_CORE_COUNT (data) [map] != 0)
922             {
923               sim_io_printf (sd, "%10s:", map_to_str (map));
924               sim_io_printf (sd, "%*s: ",
925                              max_val < 10000 ? 5 : 10,
926                              COMMAS (PROFILE_CORE_COUNT (data) [map]));
927               sim_profile_print_bar (sd, PROFILE_HISTOGRAM_WIDTH,
928                                      PROFILE_CORE_COUNT (data) [map],
929                                      max_val);
930               sim_io_printf (sd, "\n");
931             }
932         }
933     }
934
935   sim_io_printf (sd, "\n");
936 }
937
938 #endif
939
940 #if WITH_PROFILE_MODEL_P
941
942 static void
943 profile_print_model (sim_cpu *cpu, int verbose)
944 {
945   SIM_DESC sd = CPU_STATE (cpu);
946   PROFILE_DATA *data = CPU_PROFILE_DATA (cpu);
947   unsigned long cti_stall_cycles = PROFILE_MODEL_CTI_STALL_CYCLES (data);
948   unsigned long load_stall_cycles = PROFILE_MODEL_LOAD_STALL_CYCLES (data);
949   unsigned long total_cycles = PROFILE_MODEL_TOTAL_CYCLES (data);
950   char comma_buf[20];
951
952   sim_io_printf (sd, "Model %s Timing Information",
953                  MODEL_NAME (CPU_MODEL (cpu)));
954 #ifdef SIM_HAVE_ADDR_RANGE
955   if (PROFILE_RANGE (data)->ranges)
956     sim_io_printf (sd, " (for selected address range(s))");
957 #endif
958   sim_io_printf (sd, "\n\n");
959   sim_io_printf (sd, "  %-*s %s\n",
960                  PROFILE_LABEL_WIDTH, "Taken branches:",
961                  COMMAS (PROFILE_MODEL_TAKEN_COUNT (data)));
962   sim_io_printf (sd, "  %-*s %s\n",
963                  PROFILE_LABEL_WIDTH, "Untaken branches:",
964                  COMMAS (PROFILE_MODEL_UNTAKEN_COUNT (data)));
965   sim_io_printf (sd, "  %-*s %s\n",
966                  PROFILE_LABEL_WIDTH, "Cycles stalled due to branches:",
967                  COMMAS (cti_stall_cycles));
968   sim_io_printf (sd, "  %-*s %s\n",
969                  PROFILE_LABEL_WIDTH, "Cycles stalled due to loads:",
970                  COMMAS (load_stall_cycles));
971   sim_io_printf (sd, "  %-*s %s\n",
972                  PROFILE_LABEL_WIDTH, "Total cycles (*approximate*):",
973                  COMMAS (total_cycles));
974   sim_io_printf (sd, "\n");
975 }
976
977 #endif
978
979 void
980 sim_profile_print_bar (SIM_DESC sd, unsigned int width,
981                        unsigned int val, unsigned int max_val)
982 {
983   unsigned int i, count;
984
985   count = ((double) val / (double) max_val) * (double) width;
986
987   for (i = 0; i < count; ++i)
988     sim_io_printf (sd, "*");
989 }
990
991 /* Print the simulator's execution speed for CPU.  */
992
993 static void
994 profile_print_speed (sim_cpu *cpu)
995 {
996   SIM_DESC sd = CPU_STATE (cpu);
997   PROFILE_DATA *data = CPU_PROFILE_DATA (cpu);
998   unsigned long milliseconds = sim_events_elapsed_time (sd);
999   unsigned long total = PROFILE_TOTAL_INSN_COUNT (data);
1000   double clock;
1001   double secs;
1002   char comma_buf[20];
1003
1004   sim_io_printf (sd, "Simulator Execution Speed\n\n");
1005
1006   if (total != 0)
1007     sim_io_printf (sd, "  Total instructions:      %s\n", COMMAS (total));
1008
1009   if (milliseconds < 1000)
1010     sim_io_printf (sd, "  Total execution time:    < 1 second\n\n");
1011   else
1012     {
1013       /* The printing of the time rounded to 2 decimal places makes the speed
1014          calculation seem incorrect [even though it is correct].  So round
1015          MILLISECONDS first. This can marginally affect the result, but it's
1016          better that the user not perceive there's a math error.  */
1017       secs = (double) milliseconds / 1000;
1018       secs = ((double) (unsigned long) (secs * 100 + .5)) / 100;
1019       sim_io_printf (sd, "  Total execution time   : %.2f seconds\n", secs);
1020       /* Don't confuse things with data that isn't useful.
1021          If we ran for less than 2 seconds, only use the data if we
1022          executed more than 100,000 insns.  */
1023       if (secs >= 2 || total >= 100000)
1024         sim_io_printf (sd, "  Simulator speed:         %s insns/second\n",
1025                        COMMAS ((unsigned long) ((double) total / secs)));
1026     }
1027
1028   /* Print simulated execution time if the cpu frequency has been specified.  */
1029   clock = PROFILE_CPU_FREQ (data);
1030   if (clock != 0)
1031     {
1032       if (clock >= 1000000)
1033         sim_io_printf (sd, "  Simulated cpu frequency: %.2f MHz\n",
1034                        clock / 1000000);
1035       else
1036         sim_io_printf (sd, "  Simulated cpu frequency: %.2f Hz\n", clock);
1037
1038 #if WITH_PROFILE_MODEL_P
1039       if (PROFILE_FLAGS (data) [PROFILE_MODEL_IDX])
1040         {
1041           /* The printing of the time rounded to 2 decimal places makes the
1042              speed calculation seem incorrect [even though it is correct].
1043              So round    SECS first. This can marginally affect the result,
1044              but it's    better that the user not perceive there's a math
1045              error.  */
1046           secs = PROFILE_MODEL_TOTAL_CYCLES (data) / clock;
1047           secs = ((double) (unsigned long) (secs * 100 + .5)) / 100;
1048           sim_io_printf (sd, "  Simulated execution time: %.2f seconds\n",
1049                          secs);
1050         }
1051 #endif /* WITH_PROFILE_MODEL_P */
1052     }
1053 }
1054
1055 /* Print selected address ranges.  */
1056
1057 static void
1058 profile_print_addr_ranges (sim_cpu *cpu)
1059 {
1060   ADDR_SUBRANGE *asr = PROFILE_RANGE (CPU_PROFILE_DATA (cpu))->ranges;
1061   SIM_DESC sd = CPU_STATE (cpu);
1062
1063   if (asr)
1064     {
1065       sim_io_printf (sd, "Selected address ranges\n\n");
1066       while (asr != NULL)
1067         {
1068           sim_io_printf (sd, "  0x%lx - 0x%lx\n",
1069                          (long) asr->start, (long) asr->end);
1070           asr = asr->next;
1071         }
1072       sim_io_printf (sd, "\n");
1073     }
1074 }
1075
1076 /* Top level function to print all summary profile information.
1077    It is [currently] intended that all such data is printed by this function.
1078    I'd rather keep it all in one place for now.  To that end, MISC_CPU and
1079    MISC are callbacks used to print any miscellaneous data.
1080
1081    One might want to add a user option that allows printing by type or by cpu
1082    (i.e. print all insn data for each cpu first, or print data cpu by cpu).
1083    This may be a case of featuritis so it's currently left out.
1084
1085    Note that results are indented two spaces to distinguish them from
1086    section titles.  */
1087
1088 static void
1089 profile_info (SIM_DESC sd, int verbose)
1090 {
1091   int i,c;
1092   int print_title_p = 0;
1093
1094   /* Only print the title if some data has been collected.  */
1095   /* ??? Why don't we just exit if no data collected?  */
1096   /* FIXME: If the number of processors can be selected on the command line,
1097      then MAX_NR_PROCESSORS will need to take an argument of `sd'.  */
1098
1099   for (c = 0; c < MAX_NR_PROCESSORS; ++c)
1100     {
1101       sim_cpu *cpu = STATE_CPU (sd, c);
1102       PROFILE_DATA *data = CPU_PROFILE_DATA (cpu);
1103
1104       for (i = 0; i < MAX_PROFILE_VALUES; ++i)
1105         if (PROFILE_FLAGS (data) [i])
1106           print_title_p = 1;
1107       /* One could break out early if print_title_p is set.  */
1108     }
1109   if (print_title_p)
1110     sim_io_printf (sd, "Summary profiling results:\n\n");
1111
1112   /* Loop, cpu by cpu, printing results.  */
1113
1114   for (c = 0; c < MAX_NR_PROCESSORS; ++c)
1115     {
1116       sim_cpu *cpu = STATE_CPU (sd, c);
1117       PROFILE_DATA *data = CPU_PROFILE_DATA (cpu);
1118
1119       if (MAX_NR_PROCESSORS > 1
1120           && (0
1121 #if WITH_PROFILE_INSN_P
1122               || PROFILE_FLAGS (data) [PROFILE_INSN_IDX]
1123 #endif
1124 #if WITH_PROFILE_MEMORY_P
1125               || PROFILE_FLAGS (data) [PROFILE_MEMORY_IDX]
1126 #endif
1127 #if WITH_PROFILE_CORE_P
1128               || PROFILE_FLAGS (data) [PROFILE_CORE_IDX]
1129 #endif
1130 #if WITH_PROFILE_MODEL_P
1131               || PROFILE_FLAGS (data) [PROFILE_MODEL_IDX]
1132 #endif
1133 #if WITH_PROFILE_SCACHE_P && WITH_SCACHE
1134               || PROFILE_FLAGS (data) [PROFILE_SCACHE_IDX]
1135 #endif
1136 #if WITH_PROFILE_PC_P
1137               || PROFILE_FLAGS (data) [PROFILE_PC_IDX]
1138 #endif
1139               ))
1140         {
1141           sim_io_printf (sd, "CPU %d\n\n", c);
1142         }
1143
1144 #ifdef SIM_HAVE_ADDR_RANGE
1145       if (print_title_p
1146           && (PROFILE_INSN_P (cpu)
1147               || PROFILE_MODEL_P (cpu)))
1148         profile_print_addr_ranges (cpu);
1149 #endif
1150
1151 #if WITH_PROFILE_INSN_P
1152       if (PROFILE_FLAGS (data) [PROFILE_INSN_IDX])
1153         profile_print_insn (cpu, verbose);
1154 #endif
1155
1156 #if WITH_PROFILE_MEMORY_P
1157       if (PROFILE_FLAGS (data) [PROFILE_MEMORY_IDX])
1158         profile_print_memory (cpu, verbose);
1159 #endif
1160
1161 #if WITH_PROFILE_CORE_P
1162       if (PROFILE_FLAGS (data) [PROFILE_CORE_IDX])
1163         profile_print_core (cpu, verbose);
1164 #endif
1165
1166 #if WITH_PROFILE_MODEL_P
1167       if (PROFILE_FLAGS (data) [PROFILE_MODEL_IDX])
1168         profile_print_model (cpu, verbose);
1169 #endif
1170
1171 #if WITH_PROFILE_SCACHE_P && WITH_SCACHE
1172       if (PROFILE_FLAGS (data) [PROFILE_SCACHE_IDX])
1173         scache_print_profile (cpu, verbose);
1174 #endif
1175
1176 #if WITH_PROFILE_PC_P
1177       if (PROFILE_FLAGS (data) [PROFILE_PC_IDX])
1178         profile_print_pc (cpu, verbose);
1179 #endif
1180
1181       /* Print cpu-specific data before the execution speed.  */
1182       if (PROFILE_INFO_CPU_CALLBACK (data) != NULL)
1183         PROFILE_INFO_CPU_CALLBACK (data) (cpu, verbose);
1184
1185       /* Always try to print execution time and speed.  */
1186       if (verbose
1187           || PROFILE_FLAGS (data) [PROFILE_INSN_IDX])
1188         profile_print_speed (cpu);
1189     }
1190
1191   /* Finally print non-cpu specific miscellaneous data.  */
1192   if (STATE_PROFILE_INFO_CALLBACK (sd))
1193     STATE_PROFILE_INFO_CALLBACK (sd) (sd, verbose);
1194
1195 }
1196 \f
1197 /* Install profiling support in the simulator.  */
1198
1199 SIM_RC
1200 profile_install (SIM_DESC sd)
1201 {
1202   int i;
1203
1204   SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
1205   sim_add_option_table (sd, NULL, profile_options);
1206   for (i = 0; i < MAX_NR_PROCESSORS; ++i)
1207     memset (CPU_PROFILE_DATA (STATE_CPU (sd, i)), 0,
1208             sizeof (* CPU_PROFILE_DATA (STATE_CPU (sd, i))));
1209 #if WITH_PROFILE_INSN_P
1210   sim_module_add_init_fn (sd, profile_insn_init);
1211 #endif
1212 #if WITH_PROFILE_PC_P
1213   sim_module_add_uninstall_fn (sd, profile_pc_uninstall);
1214   sim_module_add_init_fn (sd, profile_pc_init);
1215 #endif
1216   sim_module_add_init_fn (sd, profile_init);
1217   sim_module_add_uninstall_fn (sd, profile_uninstall);
1218   sim_module_add_info_fn (sd, profile_info);
1219   return SIM_RC_OK;
1220 }
1221
1222 static SIM_RC
1223 profile_init (SIM_DESC sd)
1224 {
1225 #ifdef SIM_HAVE_ADDR_RANGE
1226   /* Check if a range has been specified without specifying what to
1227      collect.  */
1228   {
1229     int i;
1230
1231     for (i = 0; i < MAX_NR_PROCESSORS; ++i)
1232       {
1233         sim_cpu *cpu = STATE_CPU (sd, i);
1234
1235         if (ADDR_RANGE_RANGES (PROFILE_RANGE (CPU_PROFILE_DATA (cpu)))
1236             && ! (PROFILE_INSN_P (cpu)
1237                   || PROFILE_MODEL_P (cpu)))
1238           {
1239             sim_io_eprintf_cpu (cpu, "Profiling address range specified without --profile-insn or --profile-model.\n");
1240             sim_io_eprintf_cpu (cpu, "Address range ignored.\n");
1241             sim_addr_range_delete (PROFILE_RANGE (CPU_PROFILE_DATA (cpu)),
1242                                    0, ~ (address_word) 0);
1243           }
1244       }
1245   }
1246 #endif
1247
1248   return SIM_RC_OK;
1249 }
1250
1251 static void
1252 profile_uninstall (SIM_DESC sd)
1253 {
1254   int i,j;
1255
1256   for (i = 0; i < MAX_NR_PROCESSORS; ++i)
1257     {
1258       sim_cpu *cpu = STATE_CPU (sd, i);
1259       PROFILE_DATA *data = CPU_PROFILE_DATA (cpu);
1260
1261       if (PROFILE_FILE (data) != NULL)
1262         {
1263           /* If output from different cpus is going to the same file,
1264              avoid closing the file twice.  */
1265           for (j = 0; j < i; ++j)
1266             if (PROFILE_FILE (CPU_PROFILE_DATA (STATE_CPU (sd, j)))
1267                 == PROFILE_FILE (data))
1268               break;
1269           if (i == j)
1270             fclose (PROFILE_FILE (data));
1271         }
1272
1273       if (PROFILE_INSN_COUNT (data) != NULL)
1274         zfree (PROFILE_INSN_COUNT (data));
1275     }
1276 }