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