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