📄 sim-profile.c
字号:
} end = strtoul (chp + 1, NULL, 0); /* FIXME: Argument validation. */ if (cpu != NULL) sim_addr_range_add (PROFILE_RANGE (CPU_PROFILE_DATA (cpu)), start, end); else for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; ++cpu_nr) sim_addr_range_add (PROFILE_RANGE (CPU_PROFILE_DATA (STATE_CPU (sd, cpu_nr))), start, end); } else sim_io_eprintf (sd, "Profiling not compiled in, `--profile-range' ignored\n"); break; case OPTION_PROFILE_FUNCTION : if (WITH_PROFILE) { /*wip: need to compute function range given name*/ } else sim_io_eprintf (sd, "Profiling not compiled in, `--profile-function' ignored\n"); break;#endif /* SIM_HAVE_ADDR_RANGE */ } return SIM_RC_OK;}/* PC profiling support */#if WITH_PROFILE_PC_Pstatic voidprofile_pc_cleanup (SIM_DESC sd){ int n; for (n = 0; n < MAX_NR_PROCESSORS; n++) { sim_cpu *cpu = STATE_CPU (sd, n); PROFILE_DATA *data = CPU_PROFILE_DATA (cpu); if (PROFILE_PC_COUNT (data) != NULL) zfree (PROFILE_PC_COUNT (data)); PROFILE_PC_COUNT (data) = NULL; if (PROFILE_PC_EVENT (data) != NULL) sim_events_deschedule (sd, PROFILE_PC_EVENT (data)); PROFILE_PC_EVENT (data) = NULL; }}static voidprofile_pc_uninstall (SIM_DESC sd){ profile_pc_cleanup (sd);}static voidprofile_pc_event (SIM_DESC sd, void *data){ sim_cpu *cpu = (sim_cpu*) data; PROFILE_DATA *profile = CPU_PROFILE_DATA (cpu); address_word pc; unsigned i; switch (STATE_WATCHPOINTS (sd)->sizeof_pc) { case 2: pc = *(unsigned_2*)(STATE_WATCHPOINTS (sd)->pc) ; break; case 4: pc = *(unsigned_4*)(STATE_WATCHPOINTS (sd)->pc) ; break; case 8: pc = *(unsigned_8*)(STATE_WATCHPOINTS (sd)->pc) ; break; default: pc = 0; } i = (pc - PROFILE_PC_START (profile)) >> PROFILE_PC_SHIFT (profile); if (i < PROFILE_PC_NR_BUCKETS (profile)) PROFILE_PC_COUNT (profile) [i] += 1; /* Overflow? */ else PROFILE_PC_COUNT (profile) [PROFILE_PC_NR_BUCKETS (profile)] += 1; PROFILE_PC_EVENT (profile) = sim_events_schedule (sd, PROFILE_PC_FREQ (profile), profile_pc_event, cpu);}static SIM_RCprofile_pc_init (SIM_DESC sd){ int n; profile_pc_cleanup (sd); for (n = 0; n < MAX_NR_PROCESSORS; n++) { sim_cpu *cpu = STATE_CPU (sd, n); PROFILE_DATA *data = CPU_PROFILE_DATA (cpu); if (CPU_PROFILE_FLAGS (STATE_CPU (sd, n))[PROFILE_PC_IDX] && STATE_WATCHPOINTS (sd)->pc != NULL) { int bucket_size; /* fill in the frequency if not specified */ if (PROFILE_PC_FREQ (data) == 0) PROFILE_PC_FREQ (data) = 256; /* fill in the start/end if not specified */ if (PROFILE_PC_END (data) == 0) { PROFILE_PC_START (data) = STATE_TEXT_START (sd); PROFILE_PC_END (data) = STATE_TEXT_END (sd); } /* Compute the number of buckets if not specified. */ if (PROFILE_PC_NR_BUCKETS (data) == 0) { if (PROFILE_PC_BUCKET_SIZE (data) == 0) PROFILE_PC_NR_BUCKETS (data) = 16; else { if (PROFILE_PC_END (data) == 0) { /* nr_buckets = (full-address-range / 2) / (bucket_size / 2) */ PROFILE_PC_NR_BUCKETS (data) = ((1 << (STATE_WATCHPOINTS (sd)->sizeof_pc) * (8 - 1)) / (PROFILE_PC_BUCKET_SIZE (data) / 2)); } else { PROFILE_PC_NR_BUCKETS (data) = ((PROFILE_PC_END (data) - PROFILE_PC_START (data) + PROFILE_PC_BUCKET_SIZE (data) - 1) / PROFILE_PC_BUCKET_SIZE (data)); } } } /* Compute the bucket size if not specified. Ensure that it is rounded up to the next power of two */ if (PROFILE_PC_BUCKET_SIZE (data) == 0) { if (PROFILE_PC_END (data) == 0) /* bucket_size = (full-address-range / 2) / (nr_buckets / 2) */ bucket_size = ((1 << ((STATE_WATCHPOINTS (sd)->sizeof_pc * 8) - 1)) / (PROFILE_PC_NR_BUCKETS (data) / 2)); else bucket_size = ((PROFILE_PC_END (data) - PROFILE_PC_START (data) + PROFILE_PC_NR_BUCKETS (data) - 1) / PROFILE_PC_NR_BUCKETS (data)); PROFILE_PC_SHIFT (data) = 0; while (bucket_size > PROFILE_PC_BUCKET_SIZE (data)) { PROFILE_PC_SHIFT (data) += 1; } } /* Align the end address with bucket size */ if (PROFILE_PC_END (data) != 0) PROFILE_PC_END (data) = (PROFILE_PC_START (data) + (PROFILE_PC_BUCKET_SIZE (data) * PROFILE_PC_NR_BUCKETS (data))); /* create the relevant buffers */ PROFILE_PC_COUNT (data) = NZALLOC (unsigned, PROFILE_PC_NR_BUCKETS (data) + 1); PROFILE_PC_EVENT (data) = sim_events_schedule (sd, PROFILE_PC_FREQ (data), profile_pc_event, cpu); } } return SIM_RC_OK;}static voidprofile_print_pc (sim_cpu *cpu, int verbose){ SIM_DESC sd = CPU_STATE (cpu); PROFILE_DATA *profile = CPU_PROFILE_DATA (cpu); char comma_buf[20]; unsigned max_val; unsigned total; unsigned i; if (PROFILE_PC_COUNT (profile) == 0) return; sim_io_printf (sd, "Program Counter Statistics:\n\n"); /* First pass over data computes various things. */ max_val = 0; total = 0; for (i = 0; i <= PROFILE_PC_NR_BUCKETS (profile); ++i) { total += PROFILE_PC_COUNT (profile) [i]; if (PROFILE_PC_COUNT (profile) [i] > max_val) max_val = PROFILE_PC_COUNT (profile) [i]; } sim_io_printf (sd, " Total samples: %s\n", COMMAS (total)); sim_io_printf (sd, " Granularity: %s bytes per bucket\n", COMMAS (PROFILE_PC_BUCKET_SIZE (profile))); sim_io_printf (sd, " Size: %s buckets\n", COMMAS (PROFILE_PC_NR_BUCKETS (profile))); sim_io_printf (sd, " Frequency: %s cycles per sample\n", COMMAS (PROFILE_PC_FREQ (profile))); if (PROFILE_PC_END (profile) != 0) sim_io_printf (sd, " Range: 0x%lx 0x%lx\n", (long) PROFILE_PC_START (profile), (long) PROFILE_PC_END (profile)); if (verbose && max_val != 0) { /* Now we can print the histogram. */ sim_io_printf (sd, "\n"); for (i = 0; i <= PROFILE_PC_NR_BUCKETS (profile); ++i) { if (PROFILE_PC_COUNT (profile) [i] != 0) { sim_io_printf (sd, " "); if (i == PROFILE_PC_NR_BUCKETS (profile)) sim_io_printf (sd, "%10s:", "overflow"); else sim_io_printf (sd, "0x%08lx:", (long) (PROFILE_PC_START (profile) + (i * PROFILE_PC_BUCKET_SIZE (profile)))); sim_io_printf (sd, " %*s", max_val < 10000 ? 5 : 10, COMMAS (PROFILE_PC_COUNT (profile) [i])); sim_io_printf (sd, " %4.1f", (PROFILE_PC_COUNT (profile) [i] * 100.0) / total); sim_io_printf (sd, ": "); sim_profile_print_bar (sd, PROFILE_HISTOGRAM_WIDTH, PROFILE_PC_COUNT (profile) [i], max_val); sim_io_printf (sd, "\n"); } } } /* dump the histogram to the file "gmon.out" using BSD's gprof file format */ /* Since a profile data file is in the native format of the host on which the profile is being, endian issues are not considered in the code below. */ /* FIXME: Is this the best place for this code? */ { FILE *pf = fopen ("gmon.out", "wb"); if (pf == NULL) sim_io_eprintf (sd, "Failed to open \"gmon.out\" profile file\n"); else { int ok; /* FIXME: what if the target has a 64 bit PC? */ unsigned32 header[3]; unsigned loop; if (PROFILE_PC_END (profile) != 0) { header[0] = PROFILE_PC_START (profile); header[1] = PROFILE_PC_END (profile); } else { header[0] = 0; header[1] = 0; } /* size of sample buffer (+ header) */ header[2] = PROFILE_PC_NR_BUCKETS (profile) * 2 + sizeof (header); /* Header must be written out in target byte order. */ H2T (header[0]); H2T (header[1]); H2T (header[2]); ok = fwrite (&header, sizeof (header), 1, pf); for (loop = 0; ok && (loop < PROFILE_PC_NR_BUCKETS (profile)); loop++) { signed16 sample; if (PROFILE_PC_COUNT (profile) [loop] >= 0xffff) sample = 0xffff; else sample = PROFILE_PC_COUNT (profile) [loop]; ok = fwrite (&sample, sizeof (sample), 1, pf); } if (ok == 0) sim_io_eprintf (sd, "Failed to write to \"gmon.out\" profile file\n"); fclose(pf); } } sim_io_printf (sd, "\n");}#endif/* Summary printing support. */#if WITH_PROFILE_INSN_Pstatic SIM_RCprofile_insn_init (SIM_DESC sd){ int c; for (c = 0; c < MAX_NR_PROCESSORS; ++c) { sim_cpu *cpu = STATE_CPU (sd, c); if (CPU_MAX_INSNS (cpu) > 0) PROFILE_INSN_COUNT (CPU_PROFILE_DATA (cpu)) = NZALLOC (unsigned int, CPU_MAX_INSNS (cpu)); } return SIM_RC_OK;}static voidprofile_print_insn (sim_cpu *cpu, int verbose){ unsigned int i, n, total, max_val, max_name_len; SIM_DESC sd = CPU_STATE (cpu); PROFILE_DATA *data = CPU_PROFILE_DATA (cpu); char comma_buf[20]; /* If MAX_INSNS not set, insn profiling isn't supported. */ if (CPU_MAX_INSNS (cpu) == 0) return; sim_io_printf (sd, "Instruction Statistics");#ifdef SIM_HAVE_ADDR_RANGE if (PROFILE_RANGE (data)->ranges) sim_io_printf (sd, " (for selected address range(s))");#endif sim_io_printf (sd, "\n\n"); /* First pass over data computes various things. */ max_val = 0; total = 0; max_name_len = 0; for (i = 0; i < CPU_MAX_INSNS (cpu); ++i) { const char *name = (*CPU_INSN_NAME (cpu)) (cpu, i); if (name == NULL) continue; total += PROFILE_INSN_COUNT (data) [i]; if (PROFILE_INSN_COUNT (data) [i] > max_val) max_val = PROFILE_INSN_COUNT (data) [i]; n = strlen (name); if (n > max_name_len) max_name_len = n; } /* set the total insn count, in case client is being lazy */ if (! PROFILE_TOTAL_INSN_COUNT (data)) PROFILE_TOTAL_INSN_COUNT (data) = total; sim_io_printf (sd, " Total: %s insns\n", COMMAS (total)); if (verbose && max_val != 0) { /* Now we can print the histogram. */ sim_io_printf (sd, "\n"); for (i = 0; i < CPU_MAX_INSNS (cpu); ++i) { const char *name = (*CPU_INSN_NAME (cpu)) (cpu, i); if (name == NULL) continue; if (PROFILE_INSN_COUNT (data) [i] != 0) { sim_io_printf (sd, " %*s: %*s: ", max_name_len, name, max_val < 10000 ? 5 : 10, COMMAS (PROFILE_INSN_COUNT (data) [i])); sim_profile_print_bar (sd, PROFILE_HISTOGRAM_WIDTH, PROFILE_INSN_COUNT (data) [i], max_val); sim_io_printf (sd, "\n"); } } } sim_io_printf (sd, "\n");}#endif#if WITH_PROFILE_MEMORY_Pstatic voidprofile_print_memory (sim_cpu *cpu, int verbose){ unsigned int i, n; unsigned int total_read, total_write; unsigned int max_val, max_name_len; /* FIXME: Need to add smp support. */ SIM_DESC sd = CPU_STATE (cpu); PROFILE_DATA *data = CPU_PROFILE_DATA (cpu); char comma_buf[20]; sim_io_printf (sd, "Memory Access Statistics\n\n"); /* First pass over data computes various things. */ max_val = total_read = total_write = max_name_len = 0; for (i = 0; i < MODE_TARGET_MAX; ++i) { total_read += PROFILE_READ_COUNT (data) [i]; total_write += PROFILE_WRITE_COUNT (data) [i]; if (PROFILE_READ_COUNT (data) [i] > max_val) max_val = PROFILE_READ_COUNT (data) [i]; if (PROFILE_WRITE_COUNT (data) [i] > max_val) max_val = PROFILE_WRITE_COUNT (data) [i]; n = strlen (MODE_NAME (i)); if (n > max_name_len) max_name_len = n; } /* One could use PROFILE_LABEL_WIDTH here. I chose not to. */ sim_io_printf (sd, " Total read: %s accesses\n", COMMAS (total_read)); sim_io_printf (sd, " Total write: %s accesses\n", COMMAS (total_write)); if (verbose && max_val != 0) { /* FIXME: Need to separate instruction fetches from data fetches as the former swamps the latter. */ /* Now we can print the histogram. */ sim_io_printf (sd, "\n"); for (i = 0; i < MODE_TARGET_MAX; ++i) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -