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