2 * Copyright (c) 2009, Fabien Thomas
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * Process hwpmc(4) samples as calltree.
30 * Output file format compatible with Kcachegrind (kdesdk).
31 * Handle top mode with a sorted tree display.
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
37 #include <sys/param.h>
38 #include <sys/endian.h>
39 #include <sys/queue.h>
58 #include "pmcstat_log.h"
59 #include "pmcstat_top.h"
60 #include "pmcpl_calltree.h"
62 #define PMCPL_CT_GROWSIZE 4
64 static pmcstat_interned_string pmcpl_ct_prevfn;
66 static int pmcstat_skiplink = 0;
70 /* Get the sample value for PMC a. */
71 #define PMCPL_CT_SAMPLE(a, b) \
72 ((a) < (b)->npmcs ? (b)->sb[a] : 0)
74 /* Get the sample value in percent related to rsamples. */
75 #define PMCPL_CT_SAMPLEP(a, b) \
76 (PMCPL_CT_SAMPLE(a, b) * 100.0 / rsamples->sb[a])
78 struct pmcpl_ct_sample {
79 int npmcs; /* Max pmc index available. */
80 unsigned *sb; /* Sample buffer for 0..npmcs. */
84 struct pmcpl_ct_sample pcta_samples;
85 struct pmcpl_ct_sample pcta_callid;
87 struct pmcpl_ct_node *pcta_child;
90 struct pmcpl_ct_instr {
92 struct pmcpl_ct_sample pctf_samples;
96 * Each calltree node is tracked by a pmcpl_ct_node struct.
98 struct pmcpl_ct_node {
99 #define PMCPL_PCT_TAG 0x00000001 /* Loop detection. */
101 struct pmcstat_image *pct_image;
103 struct pmcpl_ct_sample pct_samples;
107 struct pmcpl_ct_arc *pct_arc;
109 /* TODO: optimize for large number of items. */
112 struct pmcpl_ct_instr *pct_instr;
115 struct pmcpl_ct_node_hash {
116 struct pmcpl_ct_node *pch_ctnode;
117 LIST_ENTRY(pmcpl_ct_node_hash) pch_next;
120 struct pmcpl_ct_sample pmcpl_ct_callid;
122 #define PMCPL_CT_MAXCOL PMC_CALLCHAIN_DEPTH_MAX
123 #define PMCPL_CT_MAXLINE 256
124 struct pmcpl_ct_node *pmcpl_ct_topscreen[PMCPL_CT_MAXCOL][PMCPL_CT_MAXLINE];
127 * All nodes indexed by function/image name are placed in a hash table.
129 static LIST_HEAD(,pmcpl_ct_node_hash) pmcpl_ct_node_hash[PMCSTAT_NHASH];
132 * Root node for the graph.
134 static struct pmcpl_ct_node *pmcpl_ct_root;
141 * Initialize a samples.
145 pmcpl_ct_samples_init(struct pmcpl_ct_sample *samples)
157 pmcpl_ct_samples_free(struct pmcpl_ct_sample *samples)
166 * Grow a sample block to store pmcstat_npmcs PMCs.
170 pmcpl_ct_samples_grow(struct pmcpl_ct_sample *samples)
174 /* Enough storage. */
175 if (pmcstat_npmcs <= samples->npmcs)
178 npmcs = samples->npmcs +
179 max(pmcstat_npmcs - samples->npmcs, PMCPL_CT_GROWSIZE);
180 samples->sb = realloc(samples->sb, npmcs * sizeof(unsigned));
181 if (samples->sb == NULL)
182 errx(EX_SOFTWARE, "ERROR: out of memory");
183 bzero((char *)samples->sb + samples->npmcs * sizeof(unsigned),
184 (npmcs - samples->npmcs) * sizeof(unsigned));
185 samples->npmcs = npmcs;
189 * Compute the sum of all root arcs.
193 pmcpl_ct_samples_root(struct pmcpl_ct_sample *samples)
197 pmcpl_ct_samples_init(samples);
198 pmcpl_ct_samples_grow(samples);
200 for (i = 0; i < pmcpl_ct_root->pct_narc; i++)
201 for (pmcin = 0; pmcin < pmcstat_npmcs; pmcin++)
202 samples->sb[pmcin] += PMCPL_CT_SAMPLE(pmcin,
203 &pmcpl_ct_root->pct_arc[i].pcta_samples);
207 * Grow the arc table.
211 pmcpl_ct_arc_grow(int cursize, int *maxsize, struct pmcpl_ct_arc **items)
215 if (cursize < *maxsize)
218 nmaxsize = *maxsize + max(cursize + 1 - *maxsize, PMCPL_CT_GROWSIZE);
219 *items = realloc(*items, nmaxsize * sizeof(struct pmcpl_ct_arc));
221 errx(EX_SOFTWARE, "ERROR: out of memory");
222 bzero((char *)*items + *maxsize * sizeof(struct pmcpl_ct_arc),
223 (nmaxsize - *maxsize) * sizeof(struct pmcpl_ct_arc));
228 * Compare two arc by samples value.
231 pmcpl_ct_arc_compare(void *thunk, const void *a, const void *b)
233 const struct pmcpl_ct_arc *ct1, *ct2;
234 int pmcin = *(int *)thunk;
236 ct1 = (const struct pmcpl_ct_arc *) a;
237 ct2 = (const struct pmcpl_ct_arc *) b;
239 /* Sort in reverse order */
240 if (PMCPL_CT_SAMPLE(pmcin, &ct1->pcta_samples) <
241 PMCPL_CT_SAMPLE(pmcin, &ct2->pcta_samples))
243 if (PMCPL_CT_SAMPLE(pmcin, &ct1->pcta_samples) >
244 PMCPL_CT_SAMPLE(pmcin, &ct2->pcta_samples))
250 * Grow the instr table.
254 pmcpl_ct_instr_grow(int cursize, int *maxsize, struct pmcpl_ct_instr **items)
258 if (cursize < *maxsize)
261 nmaxsize = *maxsize + max(cursize + 1 - *maxsize, PMCPL_CT_GROWSIZE);
262 *items = realloc(*items, nmaxsize * sizeof(struct pmcpl_ct_instr));
264 errx(EX_SOFTWARE, "ERROR: out of memory");
265 bzero((char *)*items + *maxsize * sizeof(struct pmcpl_ct_instr),
266 (nmaxsize - *maxsize) * sizeof(struct pmcpl_ct_instr));
271 * Add a new instruction sample to given node.
275 pmcpl_ct_instr_add(struct pmcpl_ct_node *ct, int pmcin, uintfptr_t pc)
278 struct pmcpl_ct_instr *in;
280 for (i = 0; i<ct->pct_ninstr; i++) {
281 if (ct->pct_instr[i].pctf_func == pc) {
282 in = &ct->pct_instr[i];
283 pmcpl_ct_samples_grow(&in->pctf_samples);
284 in->pctf_samples.sb[pmcin]++;
289 pmcpl_ct_instr_grow(ct->pct_ninstr, &ct->pct_instr_c, &ct->pct_instr);
290 in = &ct->pct_instr[ct->pct_ninstr];
292 pmcpl_ct_samples_init(&in->pctf_samples);
293 pmcpl_ct_samples_grow(&in->pctf_samples);
294 in->pctf_samples.sb[pmcin] = 1;
299 * Allocate a new node.
302 static struct pmcpl_ct_node *
303 pmcpl_ct_node_allocate(struct pmcstat_image *image, uintfptr_t pc)
305 struct pmcpl_ct_node *ct;
307 if ((ct = malloc(sizeof(*ct))) == NULL)
308 err(EX_OSERR, "ERROR: Cannot allocate callgraph node");
311 ct->pct_image = image;
314 pmcpl_ct_samples_init(&ct->pct_samples);
322 ct->pct_instr = NULL;
332 pmcpl_ct_node_free(struct pmcpl_ct_node *ct)
336 for (i = 0; i < ct->pct_narc; i++) {
337 pmcpl_ct_samples_free(&ct->pct_arc[i].pcta_samples);
338 pmcpl_ct_samples_free(&ct->pct_arc[i].pcta_callid);
341 pmcpl_ct_samples_free(&ct->pct_samples);
348 * Clear the graph tag on each node.
351 pmcpl_ct_node_cleartag(void)
354 struct pmcpl_ct_node_hash *pch;
356 for (i = 0; i < PMCSTAT_NHASH; i++)
357 LIST_FOREACH(pch, &pmcpl_ct_node_hash[i], pch_next)
358 pch->pch_ctnode->pct_flags &= ~PMCPL_PCT_TAG;
360 pmcpl_ct_root->pct_flags &= ~PMCPL_PCT_TAG;
364 * Print the callchain line by line with maximum cost at top.
368 pmcpl_ct_node_dumptop(int pmcin, struct pmcpl_ct_node *ct,
369 struct pmcpl_ct_sample *rsamples, int x, int *y, int maxy)
373 if (ct->pct_flags & PMCPL_PCT_TAG)
376 ct->pct_flags |= PMCPL_PCT_TAG;
378 if (x >= PMCPL_CT_MAXCOL) {
379 pmcpl_ct_topscreen[x][*y] = NULL;
382 pmcpl_ct_topscreen[x][*y] = ct;
385 * This is a terminal node
387 if (ct->pct_narc == 0) {
388 pmcpl_ct_topscreen[x+1][*y] = NULL;
389 if (*y >= PMCPL_CT_MAXLINE ||
393 for (i=0; i < x; i++)
394 pmcpl_ct_topscreen[i][*y] =
395 pmcpl_ct_topscreen[i][*y - 1];
400 * Quicksort the arcs.
402 qsort_r(ct->pct_arc, ct->pct_narc, sizeof(struct pmcpl_ct_arc),
403 &pmcin, pmcpl_ct_arc_compare);
405 for (i = 0; i < ct->pct_narc; i++) {
406 if (PMCPL_CT_SAMPLEP(pmcin,
407 &ct->pct_arc[i].pcta_samples) > pmcstat_threshold) {
408 if (pmcpl_ct_node_dumptop(pmcin,
409 ct->pct_arc[i].pcta_child,
410 rsamples, x+1, y, maxy))
419 * Format and display given PMC index.
423 pmcpl_ct_node_printtop(struct pmcpl_ct_sample *rsamples, int pmcin, int maxy)
425 int v_attrs, ns_len, vs_len, is_len, width, indentwidth, x, y;
427 char ns[30], vs[10], is[20];
428 struct pmcpl_ct_node *ct;
429 struct pmcstat_symbol *sym;
430 const char *space = " ";
432 for (y = 0; y < maxy; y++) {
434 ct = pmcpl_ct_topscreen[0][y];
435 snprintf(is, sizeof(is), "%-10.10s",
436 pmcstat_string_unintern(ct->pct_image->pi_name));
437 PMCSTAT_PRINTW("%s ", is);
438 width = indentwidth = 11;
440 for (x = 0; pmcpl_ct_topscreen[x][y] !=NULL; x++) {
442 ct = pmcpl_ct_topscreen[x][y];
444 ns[0] = '\0'; ns_len = 0;
445 vs[0] = '\0'; vs_len = 0;
446 is[0] = '\0'; is_len = 0;
449 v = PMCPL_CT_SAMPLEP(pmcin, &ct->pct_samples);
450 if (v > pmcstat_threshold)
451 vs_len = snprintf(vs, sizeof(vs), "(%.1f%%)", v);
452 v_attrs = PMCSTAT_ATTRPERCENT(v);
454 if (pmcstat_skiplink && v <= pmcstat_threshold) {
455 PMCSTAT_PRINTW(". ");
459 sym = pmcstat_symbol_search(ct->pct_image, ct->pct_func);
461 ns_len = snprintf(ns, sizeof(ns), "%s",
462 pmcstat_string_unintern(sym->ps_name));
464 ns_len = snprintf(ns, sizeof(ns), "%p",
465 (void *)ct->pct_func);
468 if (x > 0 && pmcpl_ct_topscreen[x-1][y]->pct_image != ct->pct_image)
469 is_len = snprintf(is, sizeof(is), "@%s",
470 pmcstat_string_unintern(ct->pct_image->pi_name));
472 /* Check for line wrap. */
473 width += ns_len + is_len + vs_len + 1;
474 if (width >= pmcstat_displaywidth) {
478 PMCSTAT_PRINTW("\n%*s", indentwidth, space);
479 width = indentwidth + ns_len + is_len + vs_len;
482 PMCSTAT_ATTRON(v_attrs);
483 PMCSTAT_PRINTW("%s%s%s ", ns, is, vs);
484 PMCSTAT_ATTROFF(v_attrs);
486 PMCSTAT_PRINTW("\n");
491 * Output top mode snapshot.
495 pmcpl_ct_topdisplay(void)
498 struct pmcpl_ct_sample rsamples;
500 pmcpl_ct_samples_root(&rsamples);
502 PMCSTAT_PRINTW("%-10.10s %s\n", "IMAGE", "CALLTREE");
504 for (pmcin = 0; pmcin < pmcstat_npmcs; pmcin++) {
506 if (pmcstat_pmcinfilter != pmcin)
509 pmcpl_ct_node_cleartag();
511 /* Quicksort the arcs. */
512 qsort_r(pmcpl_ct_root->pct_arc,
513 pmcpl_ct_root->pct_narc,
514 sizeof(struct pmcpl_ct_arc),
515 &pmcin, pmcpl_ct_arc_compare);
518 for (i = 0; i < pmcpl_ct_root->pct_narc; i++) {
519 if (pmcpl_ct_node_dumptop(pmcin,
520 pmcpl_ct_root->pct_arc[i].pcta_child,
521 &rsamples, x, &y, pmcstat_displayheight - 2)) {
526 pmcpl_ct_node_printtop(&rsamples, pmcin, y);
528 pmcpl_ct_samples_free(&rsamples);
532 * Handle top mode keypress.
536 pmcpl_ct_topkeypress(int c, WINDOW *w)
541 pmcstat_skiplink = !pmcstat_skiplink;
542 wprintw(w, "skip empty link %s", pmcstat_skiplink ? "on" : "off");
550 * Look for a callgraph node associated with pmc `pmcid' in the global
551 * hash table that corresponds to the given `pc' value in the process map
555 static struct pmcpl_ct_node *
556 pmcpl_ct_node_hash_lookup_pc(struct pmcpl_ct_node *parent,
557 struct pmcstat_pcmap *ppm, uintfptr_t pc, int pmcin)
559 struct pmcstat_symbol *sym;
560 struct pmcstat_image *image;
561 struct pmcpl_ct_node *ct;
562 struct pmcpl_ct_node_hash *h;
563 struct pmcpl_ct_arc *arc;
564 uintfptr_t loadaddress;
568 assert(parent != NULL);
570 image = ppm->ppm_image;
572 loadaddress = ppm->ppm_lowpc + image->pi_vaddr - image->pi_start;
573 pc -= loadaddress; /* Convert to an offset in the image. */
576 * Try determine the function at this offset. If we can't
577 * find a function round leave the `pc' value alone.
579 if ((sym = pmcstat_symbol_search(image, pc)) != NULL)
582 for (hash = i = 0; i < (int)sizeof(uintfptr_t); i++)
583 hash += (pc >> i) & 0xFF;
585 hash &= PMCSTAT_HASH_MASK;
588 LIST_FOREACH(h, &pmcpl_ct_node_hash[hash], pch_next) {
593 if (ct->pct_image == image && ct->pct_func == pc) {
595 * Find related arc in parent node and
596 * increment the sample count.
598 for (i = 0; i < parent->pct_narc; i++) {
599 if (parent->pct_arc[i].pcta_child == ct) {
600 arc = &parent->pct_arc[i];
601 pmcpl_ct_samples_grow(&arc->pcta_samples);
602 arc->pcta_samples.sb[pmcin]++;
603 /* Estimate call count. */
604 pmcpl_ct_samples_grow(&arc->pcta_callid);
605 if (pmcpl_ct_callid.sb[pmcin] -
606 arc->pcta_callid.sb[pmcin] > 1)
608 arc->pcta_callid.sb[pmcin] =
609 pmcpl_ct_callid.sb[pmcin];
615 * No arc found for us, add ourself to the parent.
617 pmcpl_ct_arc_grow(parent->pct_narc,
618 &parent->pct_arc_c, &parent->pct_arc);
619 arc = &parent->pct_arc[parent->pct_narc];
620 pmcpl_ct_samples_grow(&arc->pcta_samples);
621 arc->pcta_samples.sb[pmcin] = 1;
623 pmcpl_ct_samples_grow(&arc->pcta_callid);
624 arc->pcta_callid.sb[pmcin] = pmcpl_ct_callid.sb[pmcin];
625 arc->pcta_child = ct;
632 * We haven't seen this (pmcid, pc) tuple yet, so allocate a
633 * new callgraph node and a new hash table entry for it.
635 ct = pmcpl_ct_node_allocate(image, pc);
636 if ((h = malloc(sizeof(*h))) == NULL)
637 err(EX_OSERR, "ERROR: Could not allocate callgraph node");
640 LIST_INSERT_HEAD(&pmcpl_ct_node_hash[hash], h, pch_next);
642 pmcpl_ct_arc_grow(parent->pct_narc,
643 &parent->pct_arc_c, &parent->pct_arc);
644 arc = &parent->pct_arc[parent->pct_narc];
645 pmcpl_ct_samples_grow(&arc->pcta_samples);
646 arc->pcta_samples.sb[pmcin] = 1;
648 pmcpl_ct_samples_grow(&arc->pcta_callid);
649 arc->pcta_callid.sb[pmcin] = pmcpl_ct_callid.sb[pmcin];
650 arc->pcta_child = ct;
656 * Record a callchain.
660 pmcpl_ct_process(struct pmcstat_process *pp, struct pmcstat_pmcrecord *pmcr,
661 uint32_t nsamples, uintfptr_t *cc, int usermode, uint32_t cpu)
664 struct pmcstat_pcmap *ppm[PMC_CALLCHAIN_DEPTH_MAX];
665 struct pmcstat_process *km;
666 struct pmcpl_ct_node *parent, *child;
670 assert(nsamples>0 && nsamples<=PMC_CALLCHAIN_DEPTH_MAX);
672 /* Get the PMC index. */
673 pmcin = pmcr->pr_pmcin;
676 * Validate mapping for the callchain.
677 * Go from bottom to first invalid entry.
679 km = pmcstat_kernproc;
680 for (n = 0; n < (int)nsamples; n++) {
681 ppm[n] = pmcstat_process_find_map(usermode ?
683 if (ppm[n] == NULL) {
684 /* Detect full frame capture (kernel + user). */
686 ppm[n] = pmcstat_process_find_map(pp, cc[n]);
695 pmcstat_stats.ps_callchain_dubious_frames++;
699 /* Increase the call generation counter. */
700 pmcpl_ct_samples_grow(&pmcpl_ct_callid);
701 pmcpl_ct_callid.sb[pmcin]++;
704 * Iterate remaining addresses.
706 for (parent = pmcpl_ct_root, child = NULL; n >= 0; n--) {
707 child = pmcpl_ct_node_hash_lookup_pc(parent, ppm[n], cc[n],
710 pmcstat_stats.ps_callchain_dubious_frames++;
717 * Increment the sample count for this PMC.
720 pmcpl_ct_samples_grow(&child->pct_samples);
721 child->pct_samples.sb[pmcin]++;
723 /* Update per instruction sample if required. */
724 if (args.pa_ctdumpinstr)
725 pmcpl_ct_instr_add(child, pmcin, cc[0] -
726 (ppm[0]->ppm_lowpc + ppm[0]->ppm_image->pi_vaddr -
727 ppm[0]->ppm_image->pi_start));
732 * Print node self cost.
736 pmcpl_ct_node_printself(struct pmcpl_ct_node *ct)
740 struct pmcstat_symbol *sym;
741 char sourcefile[PATH_MAX];
742 char funcname[PATH_MAX];
747 #ifdef PMCPL_CT_OPTIMIZEFN
748 if (pmcpl_ct_prevfn != ct->pct_image->pi_fullpath) {
750 pmcpl_ct_prevfn = ct->pct_image->pi_fullpath;
751 fprintf(args.pa_graphfile, "ob=%s\n",
752 pmcstat_string_unintern(pmcpl_ct_prevfn));
753 #ifdef PMCPL_CT_OPTIMIZEFN
760 if (pmcstat_image_addr2line(ct->pct_image, ct->pct_func,
761 sourcefile, sizeof(sourcefile), &line,
762 funcname, sizeof(funcname))) {
763 fprintf(args.pa_graphfile, "fn=%s\n",
766 sym = pmcstat_symbol_search(ct->pct_image, ct->pct_func);
768 fprintf(args.pa_graphfile, "fn=%s\n",
769 pmcstat_string_unintern(sym->ps_name));
771 fprintf(args.pa_graphfile, "fn=%p\n",
772 (void *)(ct->pct_image->pi_vaddr + ct->pct_func));
778 if (ct->pct_ninstr > 0) {
779 for (i = 0; i < ct->pct_ninstr; i++) {
780 addr = ct->pct_image->pi_vaddr +
781 ct->pct_instr[i].pctf_func;
783 if (pmcstat_image_addr2line(ct->pct_image, addr,
784 sourcefile, sizeof(sourcefile), &line,
785 funcname, sizeof(funcname)))
786 fprintf(args.pa_graphfile, "fl=%s\n", sourcefile);
787 fprintf(args.pa_graphfile, "%p %u", (void *)addr, line);
788 for (j = 0; j<pmcstat_npmcs; j++)
789 fprintf(args.pa_graphfile, " %u",
791 &ct->pct_instr[i].pctf_samples));
792 fprintf(args.pa_graphfile, "\n");
795 addr = ct->pct_image->pi_vaddr + ct->pct_func;
797 if (pmcstat_image_addr2line(ct->pct_image, addr,
798 sourcefile, sizeof(sourcefile), &line,
799 funcname, sizeof(funcname)))
800 fprintf(args.pa_graphfile, "fl=%s\n", sourcefile);
801 fprintf(args.pa_graphfile, "* *");
802 for (i = 0; i<pmcstat_npmcs ; i++)
803 fprintf(args.pa_graphfile, " %u",
804 PMCPL_CT_SAMPLE(i, &ct->pct_samples));
805 fprintf(args.pa_graphfile, "\n");
810 * Print node child cost.
814 pmcpl_ct_node_printchild(struct pmcpl_ct_node *ct)
818 struct pmcstat_symbol *sym;
819 struct pmcpl_ct_node *child;
820 char sourcefile[PATH_MAX];
821 char funcname[PATH_MAX];
825 * TODO: attach child cost to the real position in the funtion.
826 * TODO: cfn=<fn> / call <ncall> addr(<fn>) / addr(call <fn>) <arccost>
828 for (i=0 ; i<ct->pct_narc; i++) {
829 child = ct->pct_arc[i].pcta_child;
832 #ifdef PMCPL_CT_OPTIMIZEFN
833 if (pmcpl_ct_prevfn != child->pct_image->pi_fullpath) {
835 pmcpl_ct_prevfn = child->pct_image->pi_fullpath;
836 fprintf(args.pa_graphfile, "cob=%s\n",
837 pmcstat_string_unintern(pmcpl_ct_prevfn));
838 #if PMCPL_CT_OPTIMIZEFN
841 /* Child function name. */
842 addr = child->pct_image->pi_vaddr + child->pct_func;
843 /* Child function source file. */
844 if (pmcstat_image_addr2line(child->pct_image, addr,
845 sourcefile, sizeof(sourcefile), &line,
846 funcname, sizeof(funcname))) {
847 fprintf(args.pa_graphfile, "cfn=%s\n", funcname);
848 fprintf(args.pa_graphfile, "cfl=%s\n", sourcefile);
850 sym = pmcstat_symbol_search(child->pct_image,
853 fprintf(args.pa_graphfile, "cfn=%s\n",
854 pmcstat_string_unintern(sym->ps_name));
856 fprintf(args.pa_graphfile, "cfn=%p\n", (void *)addr);
859 /* Child function address, line and call count. */
860 fprintf(args.pa_graphfile, "calls=%u %p %u\n",
861 ct->pct_arc[i].pcta_call, (void *)addr, line);
863 if (ct->pct_image != NULL) {
864 /* Call address, line, sample. */
865 addr = ct->pct_image->pi_vaddr + ct->pct_func;
867 pmcstat_image_addr2line(ct->pct_image, addr, sourcefile,
868 sizeof(sourcefile), &line,
869 funcname, sizeof(funcname));
870 fprintf(args.pa_graphfile, "%p %u", (void *)addr, line);
873 fprintf(args.pa_graphfile, "* *");
874 for (j = 0; j<pmcstat_npmcs; j++)
875 fprintf(args.pa_graphfile, " %u",
876 PMCPL_CT_SAMPLE(j, &ct->pct_arc[i].pcta_samples));
877 fprintf(args.pa_graphfile, "\n");
882 * Clean the PMC name for Kcachegrind formula
886 pmcpl_ct_fixup_pmcname(char *s)
896 * Print a calltree (KCachegrind) for all PMCs.
903 struct pmcpl_ct_node_hash *pch;
904 struct pmcpl_ct_sample rsamples;
907 pmcpl_ct_samples_root(&rsamples);
908 pmcpl_ct_prevfn = NULL;
910 fprintf(args.pa_graphfile,
913 "positions: instr line\n"
915 for (i=0; i<pmcstat_npmcs; i++) {
916 snprintf(name, sizeof(name), "%s_%d",
917 pmcstat_pmcindex_to_name(i), i);
918 pmcpl_ct_fixup_pmcname(name);
919 fprintf(args.pa_graphfile, " %s", name);
921 fprintf(args.pa_graphfile, "\nsummary:");
922 for (i=0; i<pmcstat_npmcs ; i++)
923 fprintf(args.pa_graphfile, " %u",
924 PMCPL_CT_SAMPLE(i, &rsamples));
925 fprintf(args.pa_graphfile, "\n\n");
930 fprintf(args.pa_graphfile, "ob=FreeBSD\n");
931 fprintf(args.pa_graphfile, "fn=ROOT\n");
932 fprintf(args.pa_graphfile, "* *");
933 for (i = 0; i<pmcstat_npmcs ; i++)
934 fprintf(args.pa_graphfile, " 0");
935 fprintf(args.pa_graphfile, "\n");
936 pmcpl_ct_node_printchild(pmcpl_ct_root);
938 for (n = 0; n < PMCSTAT_NHASH; n++)
939 LIST_FOREACH(pch, &pmcpl_ct_node_hash[n], pch_next) {
940 pmcpl_ct_node_printself(pch->pch_ctnode);
941 pmcpl_ct_node_printchild(pch->pch_ctnode);
944 pmcpl_ct_samples_free(&rsamples);
948 pmcpl_ct_configure(char *opt)
951 if (strncmp(opt, "skiplink=", 9) == 0) {
952 pmcstat_skiplink = atoi(opt+9);
964 pmcpl_ct_prevfn = NULL;
965 pmcpl_ct_root = pmcpl_ct_node_allocate(NULL, 0);
967 for (i = 0; i < PMCSTAT_NHASH; i++)
968 LIST_INIT(&pmcpl_ct_node_hash[i]);
970 pmcpl_ct_samples_init(&pmcpl_ct_callid);
976 pmcpl_ct_shutdown(FILE *mf)
979 struct pmcpl_ct_node_hash *pch, *pchtmp;
983 if (args.pa_flags & FLAG_DO_CALLGRAPHS)
990 for (i = 0; i < PMCSTAT_NHASH; i++) {
991 LIST_FOREACH_SAFE(pch, &pmcpl_ct_node_hash[i], pch_next,
993 pmcpl_ct_node_free(pch->pch_ctnode);
998 pmcpl_ct_node_free(pmcpl_ct_root);
999 pmcpl_ct_root = NULL;
1001 pmcpl_ct_samples_free(&pmcpl_ct_callid);