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