2 * Histogram related operations.
15 /* declarations of automatically generated functions to output blurbs: */
16 extern void flat_blurb PARAMS((FILE *fp));
18 bfd_vma s_lowpc; /* lowest address in .text */
19 bfd_vma s_highpc = 0; /* highest address in .text */
20 bfd_vma lowpc, highpc; /* same, but expressed in UNITs */
21 int hist_num_bins = 0; /* number of histogram samples */
22 int *hist_sample = 0; /* histogram samples (shorts in the file!) */
24 char hist_dimension[sizeof(((struct gmon_hist_hdr*)0)->dimen) + 1] =
26 char hist_dimension_abbrev = 's';
28 static double accum_time; /* accumulated time so far for print_line() */
29 static double total_time; /* total time for all routines */
31 * Table of SI prefixes for powers of 10 (used to automatically
32 * scale some of the values in the flat profile).
38 {'T', 1e-12}, /* tera */
39 {'G', 1e-09}, /* giga */
40 {'M', 1e-06}, /* mega */
41 {'K', 1e-03}, /* kilo */
43 {'m', 1e+03}, /* milli */
44 {'u', 1e+06}, /* micro */
45 {'n', 1e+09}, /* nano */
46 {'p', 1e+12}, /* pico */
47 {'f', 1e+15}, /* femto */
48 {'a', 1e+18}, /* ato */
52 * Read the histogram from file IFP. FILENAME is the name of IFP and
53 * is provided for formatting error messages only.
56 DEFUN(hist_read_rec, (ifp, filename), FILE *ifp AND const char *filename)
58 struct gmon_hist_hdr hdr;
59 bfd_vma n_lowpc, n_highpc;
60 int i, ncnt, profrate;
63 if (fread(&hdr, sizeof(hdr), 1, ifp) != 1) {
64 fprintf(stderr, "%s: %s: unexpected end of file\n",
69 n_lowpc = (bfd_vma) get_vma(core_bfd, (bfd_byte *) hdr.low_pc);
70 n_highpc = (bfd_vma) get_vma(core_bfd, (bfd_byte *) hdr.high_pc);
71 ncnt = bfd_get_32(core_bfd, (bfd_byte *) hdr.hist_size);
72 profrate = bfd_get_32(core_bfd, (bfd_byte *) hdr.prof_rate);
73 strncpy(hist_dimension, hdr.dimen, sizeof(hdr.dimen));
74 hist_dimension[sizeof(hdr.dimen)] = '\0';
75 hist_dimension_abbrev = hdr.dimen_abbrev;
79 /* this is the first histogram record: */
83 lowpc = (bfd_vma) n_lowpc / sizeof(UNIT);
84 highpc = (bfd_vma) n_highpc / sizeof(UNIT);
90 printf("[hist_read_rec] n_lowpc 0x%lx n_highpc 0x%lx ncnt %d\n",
91 n_lowpc, n_highpc, ncnt);
92 printf("[hist_read_rec] s_lowpc 0x%lx s_highpc 0x%lx nsamples %d\n",
93 s_lowpc, s_highpc, hist_num_bins);
94 printf("[hist_read_rec] lowpc 0x%lx highpc 0x%lx\n",
97 if (n_lowpc != s_lowpc || n_highpc != s_highpc
98 || ncnt != hist_num_bins || hz != profrate)
100 fprintf(stderr, "%s: `%s' is incompatible with first gmon file\n",
106 hist_sample = (int*)xmalloc(hist_num_bins * sizeof(hist_sample[0]));
107 memset(hist_sample, 0, hist_num_bins * sizeof(hist_sample[0]));
110 for (i = 0; i < hist_num_bins; ++i) {
111 if (fread(&count[0], sizeof(count), 1, ifp) != 1) {
113 "%s: %s: unexpected EOF after reading %d of %d samples\n",
114 whoami, filename, i, hist_num_bins);
117 hist_sample[i] += bfd_get_16(core_bfd, (bfd_byte*) &count[0]);
119 } /* hist_read_rec */
123 * Write execution histogram to file OFP. FILENAME is the name
124 * of OFP and is provided for formatting error-messages only.
127 DEFUN(hist_write_hist, (ofp, filename), FILE *ofp AND const char *filename)
129 struct gmon_hist_hdr hdr;
136 tag = GMON_TAG_TIME_HIST;
137 put_vma(core_bfd, s_lowpc, (bfd_byte*) hdr.low_pc);
138 put_vma(core_bfd, s_highpc, (bfd_byte*) hdr.high_pc);
139 bfd_put_32(core_bfd, hist_num_bins, (bfd_byte*) hdr.hist_size);
140 bfd_put_32(core_bfd, hz, (bfd_byte*) hdr.prof_rate);
141 strncpy(hdr.dimen, hist_dimension, sizeof(hdr.dimen));
142 hdr.dimen_abbrev = hist_dimension_abbrev;
144 if (fwrite(&tag, sizeof(tag), 1, ofp) != 1
145 || fwrite(&hdr, sizeof(hdr), 1, ofp) != 1)
151 for (i = 0; i < hist_num_bins; ++i) {
152 bfd_put_16(core_bfd, hist_sample[i], (bfd_byte*) &count[0]);
153 if (fwrite(&count[0], sizeof(count), 1, ofp) != 1) {
158 } /* hist_write_hist */
162 * Calculate scaled entry point addresses (to save time in
163 * hist_assign_samples), and, on architectures that have procedure
164 * entry masks at the start of a function, possibly push the scaled
165 * entry points over the procedure entry mask, if it turns out that
166 * the entry point is in one bin and the code for a routine is in the
170 DEFUN_VOID(scale_and_align_entries)
173 #if OFFSET_TO_CODE > 0
174 bfd_vma bin_of_entry;
178 for (sym = symtab.base; sym < symtab.limit; sym++) {
179 sym->hist.scaled_addr = sym->addr / sizeof(UNIT);
180 #if OFFSET_TO_CODE > 0
181 bin_of_entry = (sym->hist.scaled_addr - lowpc) / hist_scale;
182 bin_of_code = (sym->hist.scaled_addr + UNITS_TO_CODE - lowpc) / hist_scale;
183 if (bin_of_entry < bin_of_code) {
185 printf("[scale_and_align_entries] pushing 0x%lx to 0x%lx\n",
186 sym->hist.scaled_addr, sym->aligned_addr + UNITS_TO_CODE));
187 sym->aligned_addr += UNITS_TO_CODE;
189 #endif /* OFFSET_TO_CODE > 0 */
191 } /* scale_and_align_entries */
195 * Assign samples to the symbol to which they belong.
197 * Histogram bin I covers some address range [BIN_LOWPC,BIN_HIGH_PC)
198 * which may overlap one more symbol address ranges. If a symbol
199 * overlaps with the bin's address range by O percent, then O percent
200 * of the bin's count is credited to that symbol.
202 * There are three cases as to where BIN_LOW_PC and BIN_HIGH_PC can be
203 * with respect to the symbol's address range [SYM_LOW_PC,
204 * SYM_HIGH_PC) as shown in the following diagram. OVERLAP computes
205 * the distance (in UNITs) between the arrows, the fraction of the
206 * sample that is to be credited to the symbol which starts at
209 * sym_low_pc sym_high_pc
213 * +-----------------------------------------------+
215 * | ->| |<- ->| |<- ->| |<- |
217 * +---------+ +---------+ +---------+
221 * bin_low_pc bin_high_pc bin_low_pc bin_high_pc bin_low_pc bin_high_pc
223 * For the VAX we assert that samples will never fall in the first two
224 * bytes of any routine, since that is the entry mask, thus we call
225 * scale_and_align_entries() to adjust the entry points if the entry
226 * mask falls in one bin but the code for the routine doesn't start
227 * until the next bin. In conjunction with the alignment of routine
228 * addresses, this should allow us to have only one sample for every
229 * four bytes of text space and never have any overlap (the two end
233 DEFUN_VOID(hist_assign_samples)
235 bfd_vma bin_low_pc, bin_high_pc;
236 bfd_vma sym_low_pc, sym_high_pc;
237 bfd_vma overlap, addr;
241 /* read samples and assign to symbols: */
242 hist_scale = highpc - lowpc;
243 hist_scale /= hist_num_bins;
244 scale_and_align_entries();
246 /* iterate over all sample bins: */
248 for (i = 0, j = 1; i < hist_num_bins; ++i) {
249 bin_count = hist_sample[i];
253 bin_low_pc = lowpc + (bfd_vma)(hist_scale * i);
254 bin_high_pc = lowpc + (bfd_vma)(hist_scale * (i + 1));
258 "[assign_samples] bin_low_pc=0x%lx, bin_high_pc=0x%lx, bin_count=%d\n",
259 sizeof(UNIT) * bin_low_pc, sizeof(UNIT) * bin_high_pc,
263 /* credit all symbols that are covered by bin I: */
265 for (j = j - 1; j < symtab.len; ++j) {
266 sym_low_pc = symtab.base[j].hist.scaled_addr;
267 sym_high_pc = symtab.base[j+1].hist.scaled_addr;
269 * If high end of bin is below entry address, go for next
272 if (bin_high_pc < sym_low_pc) {
276 * If low end of bin is above high end of symbol, go for
279 if (bin_low_pc >= sym_high_pc) {
283 MIN(bin_high_pc, sym_high_pc) - MAX(bin_low_pc, sym_low_pc);
287 "[assign_samples] [0x%lx,0x%lx) %s gets %f ticks %ld overlap\n",
288 symtab.base[j].addr, sizeof(UNIT) * sym_high_pc,
289 symtab.base[j].name, overlap * time / hist_scale,
291 addr = symtab.base[j].addr;
292 credit = overlap * time / hist_scale;
294 * Credit symbol if it appears in INCL_FLAT or that
295 * table is empty and it does not appear it in
298 if (sym_lookup(&syms[INCL_FLAT], addr)
299 || (syms[INCL_FLAT].len == 0
300 && !sym_lookup(&syms[EXCL_FLAT], addr)))
302 symtab.base[j].hist.time += credit;
304 total_time -= credit;
309 DBG(SAMPLEDEBUG, printf("[assign_samples] total_time %f\n",
311 } /* hist_assign_samples */
315 * Print header for flag histogram profile:
318 DEFUN(print_header, (prefix), const char prefix)
322 sprintf(unit, "%c%c/call", prefix, hist_dimension_abbrev);
324 if (bsd_style_output) {
325 printf("\ngranularity: each sample hit covers %ld byte(s)",
326 (long) hist_scale * sizeof(UNIT));
327 if (total_time > 0.0) {
328 printf(" for %.2f%% of %.2f %s\n\n",
329 100.0/total_time, total_time/hz, hist_dimension);
332 printf("\nEach sample counts as %g %s.\n", 1.0 / hz, hist_dimension);
335 if (total_time <= 0.0) {
336 printf(" no time accumulated\n\n");
337 /* this doesn't hurt since all the numerators will be zero: */
341 printf("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n",
342 "% ", "cumulative", "self ", "", "self ", "total ", "");
343 printf("%5.5s %9.9s %8.8s %8.8s %8.8s %8.8s %-8.8s\n",
344 "time", hist_dimension, hist_dimension, "calls", unit, unit,
350 DEFUN(print_line, (sym, scale), Sym *sym AND double scale)
352 if (ignore_zeros && sym->ncalls == 0 && sym->hist.time == 0) {
356 accum_time += sym->hist.time;
357 if (bsd_style_output) {
358 printf("%5.1f %10.2f %8.2f",
359 total_time > 0.0 ? 100 * sym->hist.time / total_time : 0.0,
360 accum_time / hz, sym->hist.time / hz);
362 printf("%6.2f %9.2f %8.2f",
363 total_time > 0.0 ? 100 * sym->hist.time / total_time : 0.0,
364 accum_time / hz, sym->hist.time / hz);
367 printf(" %8d %8.2f %8.2f ",
368 sym->ncalls, scale*sym->hist.time/hz/sym->ncalls,
369 scale*(sym->hist.time + sym->cg.child_time)/hz/sym->ncalls);
371 printf(" %8.8s %8.8s %8.8s ", "", "", "");
373 if (bsd_style_output) {
376 print_name_only(sym);
383 * Compare LP and RP. The primary comparison key is execution time,
384 * the secondary is number of invocation, and the tertiary is the
385 * lexicographic order of the function names.
388 DEFUN(cmp_time, (lp, rp), const PTR lp AND const PTR rp)
390 const Sym *left = *(const Sym **)lp;
391 const Sym *right = *(const Sym **)rp;
395 time_diff = right->hist.time - left->hist.time;
396 if (time_diff > 0.0) {
399 if (time_diff < 0.0) {
403 call_diff = right->ncalls - left->ncalls;
411 return strcmp(left->name, right->name);
416 * Print the flat histogram profile.
419 DEFUN_VOID(hist_print)
421 Sym **time_sorted_syms, *top_dog, *sym;
422 int index, log_scale;
423 double top_time, time;
427 first_output = FALSE;
433 if (bsd_style_output) {
434 if (print_descriptions) {
435 printf("\n\n\nflat profile:\n");
439 printf ("Flat profile:\n");
442 * Sort the symbol table by time (call-count and name as secondary
443 * and tertiary keys):
445 time_sorted_syms = (Sym**)xmalloc(symtab.len * sizeof(Sym*));
446 for (index = 0; index < symtab.len; ++index) {
447 time_sorted_syms[index] = &symtab.base[index];
449 qsort(time_sorted_syms, symtab.len, sizeof(Sym *), cmp_time);
451 if (bsd_style_output) {
452 log_scale = 5; /* milli-seconds is BSD-default */
455 * Search for symbol with highest per-call execution time and
461 for (index = 0; index < symtab.len; ++index) {
462 sym = time_sorted_syms[index];
464 time = (sym->hist.time + sym->cg.child_time) / sym->ncalls;
465 if (time > top_time) {
471 if (top_dog && top_dog->ncalls && top_time > 0.0) {
473 while (SItab[log_scale].scale * top_time < 1000.0
474 && log_scale < sizeof(SItab)/sizeof(SItab[0]) - 1)
482 * For now, the dimension is always seconds. In the future, we
483 * may also want to support other (pseudo-)dimensions (such as
484 * I-cache misses etc.).
486 print_header(SItab[log_scale].prefix);
487 for (index = 0; index < symtab.len; ++index) {
488 addr = time_sorted_syms[index]->addr;
490 * Print symbol if its in INCL_FLAT table or that table
491 * is empty and the symbol is not in EXCL_FLAT.
493 if (sym_lookup(&syms[INCL_FLAT], addr)
494 || (syms[INCL_FLAT].len == 0
495 && !sym_lookup(&syms[EXCL_FLAT], addr)))
497 print_line(time_sorted_syms[index], SItab[log_scale].scale);
500 free(time_sorted_syms);
502 if (print_descriptions && !bsd_style_output) {
507 /*** end of hist.c ***/