sim: move profile init to dynamic modules.c
[deliverable/binutils-gdb.git] / sim / common / sim-profile.c
CommitLineData
c906108c 1/* Default profiling support.
3666a048 2 Copyright (C) 1996-2021 Free Software Foundation, Inc.
c906108c
SS
3 Contributed by Cygnus Support.
4
5This file is part of GDB, the GNU debugger.
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
4744ac1b
JB
9the Free Software Foundation; either version 3 of the License, or
10(at your option) any later version.
c906108c
SS
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
4744ac1b
JB
17You should have received a copy of the GNU General Public License
18along with this program. If not, see <http://www.gnu.org/licenses/>. */
c906108c 19
6df01ab8
MF
20/* This must come before any other includes. */
21#include "defs.h"
22
c906108c
SS
23#include "sim-main.h"
24#include "sim-io.h"
25#include "sim-options.h"
26#include "sim-assert.h"
27
c906108c 28#include <stdlib.h>
c906108c 29#include <string.h>
09032128 30#include <ctype.h>
c906108c 31
5be229c0
MF
32#if !WITH_PROFILE_PC_P
33static 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
c906108c
SS
42#define COMMAS(n) sim_add_commas (comma_buf, sizeof (comma_buf), (n))
43
44static MODULE_INIT_FN profile_init;
45static MODULE_UNINSTALL_FN profile_uninstall;
46
47static DECLARE_OPTION_HANDLER (profile_option_handler);
48
49enum {
50 OPTION_PROFILE_INSN = OPTION_START,
51 OPTION_PROFILE_MEMORY,
52 OPTION_PROFILE_MODEL,
53 OPTION_PROFILE_FILE,
54 OPTION_PROFILE_CORE,
09032128 55 OPTION_PROFILE_CPU_FREQUENCY,
c906108c
SS
56 OPTION_PROFILE_PC,
57 OPTION_PROFILE_PC_RANGE,
58 OPTION_PROFILE_PC_GRANULARITY,
59 OPTION_PROFILE_RANGE,
60 OPTION_PROFILE_FUNCTION
61};
62
63static const OPTION profile_options[] = {
64 { {"profile", optional_argument, NULL, 'p'},
65 'p', "on|off", "Perform profiling",
21cf617c 66 profile_option_handler, NULL },
c906108c
SS
67 { {"profile-insn", optional_argument, NULL, OPTION_PROFILE_INSN},
68 '\0', "on|off", "Perform instruction profiling",
21cf617c 69 profile_option_handler, NULL },
c906108c
SS
70 { {"profile-memory", optional_argument, NULL, OPTION_PROFILE_MEMORY},
71 '\0', "on|off", "Perform memory profiling",
21cf617c 72 profile_option_handler, NULL },
c906108c
SS
73 { {"profile-core", optional_argument, NULL, OPTION_PROFILE_CORE},
74 '\0', "on|off", "Perform CORE profiling",
21cf617c 75 profile_option_handler, NULL },
c906108c
SS
76 { {"profile-model", optional_argument, NULL, OPTION_PROFILE_MODEL},
77 '\0', "on|off", "Perform model profiling",
21cf617c 78 profile_option_handler, NULL },
09032128
DB
79 { {"profile-cpu-frequency", required_argument, NULL,
80 OPTION_PROFILE_CPU_FREQUENCY},
81 '\0', "CPU FREQUENCY", "Specify the speed of the simulated cpu clock",
21cf617c 82 profile_option_handler, NULL },
c906108c
SS
83
84 { {"profile-file", required_argument, NULL, OPTION_PROFILE_FILE},
85 '\0', "FILE NAME", "Specify profile output file",
21cf617c 86 profile_option_handler, NULL },
c906108c
SS
87
88 { {"profile-pc", optional_argument, NULL, OPTION_PROFILE_PC},
89 '\0', "on|off", "Perform PC profiling",
21cf617c 90 profile_option_handler, NULL },
c906108c
SS
91 { {"profile-pc-frequency", required_argument, NULL, 'F'},
92 'F', "PC PROFILE FREQUENCY", "Specified PC profiling frequency",
21cf617c 93 profile_option_handler, NULL },
c906108c
SS
94 { {"profile-pc-size", required_argument, NULL, 'S'},
95 'S', "PC PROFILE SIZE", "Specify PC profiling size",
21cf617c 96 profile_option_handler, NULL },
c906108c
SS
97 { {"profile-pc-granularity", required_argument, NULL, OPTION_PROFILE_PC_GRANULARITY},
98 '\0', "PC PROFILE GRANULARITY", "Specify PC profiling sample coverage",
21cf617c 99 profile_option_handler, NULL },
c906108c
SS
100 { {"profile-pc-range", required_argument, NULL, OPTION_PROFILE_PC_RANGE},
101 '\0', "BASE,BOUND", "Specify PC profiling address range",
21cf617c 102 profile_option_handler, NULL },
c906108c
SS
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",
21cf617c 107 profile_option_handler, NULL },
c906108c
SS
108#if 0 /*wip*/
109 { {"profile-function", required_argument, NULL, OPTION_PROFILE_FUNCTION},
110 '\0', "FUNCTION", "Specify function to profile",
21cf617c 111 profile_option_handler, NULL },
c906108c
SS
112#endif
113#endif
114
21cf617c 115 { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL, NULL }
c906108c
SS
116};
117
118/* Set/reset the profile options indicated in MASK. */
119
ed9a39eb 120SIM_RC
c906108c
SS
121set_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 }
028f6515 186 }
c906108c
SS
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
194SIM_RC
195sim_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
09032128
DB
200static SIM_RC
201parse_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
c906108c
SS
247static SIM_RC
248profile_option_handler (SIM_DESC sd,
249 sim_cpu *cpu,
250 int opt,
251 char *arg,
252 int is_command)
253{
cdc2a5c3 254 int cpu_nr;
c906108c
SS
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
09032128
DB
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
c906108c
SS
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;
028f6515 410 }
c906108c
SS
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
0d3d2c71
MF
458/* Profiling output hooks. */
459
f08708cb 460static void ATTRIBUTE_PRINTF (3, 0)
0d3d2c71
MF
461profile_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
f0c4dc40 472ATTRIBUTE_PRINTF (3, 4)
0d3d2c71
MF
473static void
474profile_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
c906108c
SS
483/* PC profiling support */
484
485#if WITH_PROFILE_PC_P
486
487static void
488profile_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)
d79fe0d6 496 free (PROFILE_PC_COUNT (data));
c906108c
SS
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
505static void
506profile_pc_uninstall (SIM_DESC sd)
507{
508 profile_pc_cleanup (sd);
509}
510
511static void
512profile_pc_event (SIM_DESC sd,
513 void *data)
514{
515 sim_cpu *cpu = (sim_cpu*) data;
516 PROFILE_DATA *profile = CPU_PROFILE_DATA (cpu);
596f8827 517 address_word pc = sim_pc_get (cpu);
c906108c 518 unsigned i;
c906108c
SS
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;
028f6515 524 PROFILE_PC_EVENT (profile) =
c906108c
SS
525 sim_events_schedule (sd, PROFILE_PC_FREQ (profile), profile_pc_event, cpu);
526}
527
528static SIM_RC
529profile_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);
596f8827 537 if (CPU_PROFILE_FLAGS (STATE_CPU (sd, n))[PROFILE_PC_IDX])
c906108c
SS
538 {
539 int bucket_size;
540 /* fill in the frequency if not specified */
541 if (PROFILE_PC_FREQ (data) == 0)
41ec9f20 542 PROFILE_PC_FREQ (data) = 257;
c906108c
SS
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) =
18d4b488 560 ((1ULL << sizeof (sim_cia) * (8 - 1))
c906108c
SS
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) */
18d4b488 579 bucket_size = ((1ULL << ((sizeof (sim_cia) * 8) - 1))
c906108c
SS
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;
c43ad8eb 587 while (bucket_size > PROFILE_PC_BUCKET_SIZE (data))
c906108c
SS
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
610static void
611profile_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
0d3d2c71 623 profile_printf (sd, cpu, "Program Counter Statistics:\n\n");
c906108c
SS
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
0d3d2c71
MF
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)));
c906108c
SS
643
644 if (PROFILE_PC_END (profile) != 0)
0d3d2c71
MF
645 profile_printf (sd, cpu, " Range: 0x%lx 0x%lx\n",
646 (long) PROFILE_PC_START (profile),
c906108c
SS
647 (long) PROFILE_PC_END (profile));
648
649 if (verbose && max_val != 0)
650 {
651 /* Now we can print the histogram. */
0d3d2c71 652 profile_printf (sd, cpu, "\n");
c906108c
SS
653 for (i = 0; i <= PROFILE_PC_NR_BUCKETS (profile); ++i)
654 {
655 if (PROFILE_PC_COUNT (profile) [i] != 0)
656 {
0d3d2c71 657 profile_printf (sd, cpu, " ");
c906108c 658 if (i == PROFILE_PC_NR_BUCKETS (profile))
0d3d2c71 659 profile_printf (sd, cpu, "%10s:", "overflow");
c906108c 660 else
0d3d2c71
MF
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,
c906108c
SS
671 PROFILE_PC_COUNT (profile) [i],
672 max_val);
0d3d2c71 673 profile_printf (sd, cpu, "\n");
c906108c
SS
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");
028f6515 686
c906108c
SS
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);
c43ad8eb
BE
707
708 /* Header must be written out in target byte order. */
709 H2T (header[0]);
710 H2T (header[1]);
711 H2T (header[2]);
712
c906108c
SS
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];
41ec9f20 723 H2T (sample);
c906108c
SS
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");
34b47c38 728 fclose (pf);
c906108c
SS
729 }
730 }
731
0d3d2c71 732 profile_printf (sd, cpu, "\n");
c906108c
SS
733}
734
735#endif
736\f
737/* Summary printing support. */
738
739#if WITH_PROFILE_INSN_P
740
741static SIM_RC
742profile_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
757static void
758profile_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
0d3d2c71 769 profile_printf (sd, cpu, "Instruction Statistics");
c906108c
SS
770#ifdef SIM_HAVE_ADDR_RANGE
771 if (PROFILE_RANGE (data)->ranges)
0d3d2c71 772 profile_printf (sd, cpu, " (for selected address range(s))");
c906108c 773#endif
0d3d2c71 774 profile_printf (sd, cpu, "\n\n");
c906108c
SS
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
0d3d2c71 797 profile_printf (sd, cpu, " Total: %s insns\n", COMMAS (total));
c906108c
SS
798
799 if (verbose && max_val != 0)
800 {
801 /* Now we can print the histogram. */
0d3d2c71 802 profile_printf (sd, cpu, "\n");
c906108c
SS
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 {
0d3d2c71
MF
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,
c906108c
SS
816 PROFILE_INSN_COUNT (data) [i],
817 max_val);
0d3d2c71 818 profile_printf (sd, cpu, "\n");
c906108c
SS
819 }
820 }
821 }
822
0d3d2c71 823 profile_printf (sd, cpu, "\n");
c906108c
SS
824}
825
826#endif
827
828#if WITH_PROFILE_MEMORY_P
829
830static void
831profile_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
0d3d2c71 841 profile_printf (sd, cpu, "Memory Access Statistics\n\n");
c906108c
SS
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. */
0d3d2c71
MF
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));
c906108c
SS
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. */
0d3d2c71 869 profile_printf (sd, cpu, "\n");
c906108c
SS
870 for (i = 0; i < MODE_TARGET_MAX; ++i)
871 {
872 if (PROFILE_READ_COUNT (data) [i] != 0)
873 {
0d3d2c71
MF
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,
c906108c
SS
879 PROFILE_READ_COUNT (data) [i],
880 max_val);
0d3d2c71 881 profile_printf (sd, cpu, "\n");
c906108c
SS
882 }
883 if (PROFILE_WRITE_COUNT (data) [i] != 0)
884 {
0d3d2c71
MF
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,
c906108c
SS
890 PROFILE_WRITE_COUNT (data) [i],
891 max_val);
0d3d2c71 892 profile_printf (sd, cpu, "\n");
c906108c
SS
893 }
894 }
895 }
896
0d3d2c71 897 profile_printf (sd, cpu, "\n");
c906108c
SS
898}
899
900#endif
901
902#if WITH_PROFILE_CORE_P
903
904static void
905profile_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
0d3d2c71 914 profile_printf (sd, cpu, "CORE Statistics\n\n");
c906108c
SS
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. */
0d3d2c71
MF
930 profile_printf (sd, cpu, " Total: %s accesses\n",
931 COMMAS (total));
c906108c
SS
932
933 if (verbose && max_val != 0)
934 {
935 unsigned map;
936 /* Now we can print the histogram. */
0d3d2c71 937 profile_printf (sd, cpu, "\n");
c906108c
SS
938 for (map = 0; map < nr_maps; map++)
939 {
940 if (PROFILE_CORE_COUNT (data) [map] != 0)
941 {
0d3d2c71
MF
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,
c906108c
SS
947 PROFILE_CORE_COUNT (data) [map],
948 max_val);
0d3d2c71 949 profile_printf (sd, cpu, "\n");
c906108c
SS
950 }
951 }
952 }
953
0d3d2c71 954 profile_printf (sd, cpu, "\n");
c906108c
SS
955}
956
957#endif
958
959#if WITH_PROFILE_MODEL_P
960
961static void
962profile_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
0d3d2c71
MF
971 profile_printf (sd, cpu, "Model %s Timing Information",
972 MODEL_NAME (CPU_MODEL (cpu)));
c906108c
SS
973#ifdef SIM_HAVE_ADDR_RANGE
974 if (PROFILE_RANGE (data)->ranges)
0d3d2c71 975 profile_printf (sd, cpu, " (for selected address range(s))");
c906108c 976#endif
0d3d2c71
MF
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");
c906108c
SS
994}
995
996#endif
997
998void
0d3d2c71 999sim_profile_print_bar (SIM_DESC sd, sim_cpu *cpu, unsigned int width,
c906108c
SS
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)
0d3d2c71 1007 profile_printf (sd, cpu, "*");
c906108c
SS
1008}
1009
1010/* Print the simulator's execution speed for CPU. */
1011
1012static void
1013profile_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);
09032128
DB
1019 double clock;
1020 double secs;
c906108c
SS
1021 char comma_buf[20];
1022
0d3d2c71 1023 profile_printf (sd, cpu, "Simulator Execution Speed\n\n");
c906108c
SS
1024
1025 if (total != 0)
0d3d2c71 1026 profile_printf (sd, cpu, " Total instructions: %s\n", COMMAS (total));
c906108c
SS
1027
1028 if (milliseconds < 1000)
0d3d2c71 1029 profile_printf (sd, cpu, " Total execution time: < 1 second\n\n");
c906108c
SS
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. */
09032128 1036 secs = (double) milliseconds / 1000;
c906108c 1037 secs = ((double) (unsigned long) (secs * 100 + .5)) / 100;
0d3d2c71 1038 profile_printf (sd, cpu, " Total execution time : %.2f seconds\n", secs);
c906108c
SS
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)
0d3d2c71
MF
1043 profile_printf (sd, cpu, " Simulator speed: %s insns/second\n",
1044 COMMAS ((unsigned long) ((double) total / secs)));
c906108c 1045 }
09032128 1046
09032128
DB
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)
0d3d2c71
MF
1052 profile_printf (sd, cpu, " Simulated cpu frequency: %.2f MHz\n",
1053 clock / 1000000);
09032128 1054 else
0d3d2c71 1055 profile_printf (sd, cpu, " Simulated cpu frequency: %.2f Hz\n", clock);
09032128 1056
80dbae7a 1057#if WITH_PROFILE_MODEL_P
09032128
DB
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;
0d3d2c71
MF
1067 profile_printf (sd, cpu, " Simulated execution time: %.2f seconds\n",
1068 secs);
09032128 1069 }
09032128 1070#endif /* WITH_PROFILE_MODEL_P */
80dbae7a 1071 }
c906108c
SS
1072}
1073
739dfd28 1074#ifdef SIM_HAVE_ADDR_RANGE
c906108c
SS
1075/* Print selected address ranges. */
1076
1077static void
1078profile_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 {
0d3d2c71 1085 profile_printf (sd, cpu, "Selected address ranges\n\n");
c906108c
SS
1086 while (asr != NULL)
1087 {
0d3d2c71
MF
1088 profile_printf (sd, cpu, " 0x%lx - 0x%lx\n",
1089 (long) asr->start, (long) asr->end);
c906108c
SS
1090 asr = asr->next;
1091 }
0d3d2c71 1092 profile_printf (sd, cpu, "\n");
c906108c
SS
1093 }
1094}
739dfd28 1095#endif
c906108c
SS
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
1109static void
1110profile_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
f1a81b37 1120 for (c = 0; c < MAX_NR_PROCESSORS && !print_title_p; ++c)
c906108c
SS
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])
0d3d2c71
MF
1127 {
1128 profile_printf (sd, cpu, "Summary profiling results:\n\n");
1129 print_title_p = 1;
f1a81b37 1130 break;
0d3d2c71 1131 }
c906108c 1132 }
c906108c
SS
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
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 {
0d3d2c71 1163 profile_printf (sd, cpu, "CPU %d\n\n", c);
c906108c
SS
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
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
953fac64
MF
1219/* Provide a prototype to silence -Wmissing-prototypes. */
1220SIM_RC sim_install_profile (SIM_DESC sd);
c906108c 1221
953fac64 1222/* Install profiling support in the simulator. */
c906108c 1223SIM_RC
953fac64 1224sim_install_profile (SIM_DESC sd)
c906108c
SS
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
1246static SIM_RC
1247profile_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
1275static void
1276profile_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)
d79fe0d6 1298 free (PROFILE_INSN_COUNT (data));
c906108c
SS
1299 }
1300}
This page took 1.039053 seconds and 4 git commands to generate.