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