diff options
author | fabient <fabient@FreeBSD.org> | 2010-05-07 19:48:50 +0000 |
---|---|---|
committer | fabient <fabient@FreeBSD.org> | 2010-05-07 19:48:50 +0000 |
commit | 1e4578001fb2726b9e555d41c0efcb03599eae62 (patch) | |
tree | c3fdabcde44aeed7cc79b85ac78199e46916daf7 /usr.sbin/pmcstat/pmcpl_calltree.c | |
parent | 9dae33e9a6c4641d10e6bd125ca2b6bbcab85f50 (diff) | |
download | FreeBSD-src-1e4578001fb2726b9e555d41c0efcb03599eae62.zip FreeBSD-src-1e4578001fb2726b9e555d41c0efcb03599eae62.tar.gz |
Rework the calltree top view by critical callchain.
The percentage show is the sum of the cost for the codepath.
MFC after: 1 week
Diffstat (limited to 'usr.sbin/pmcstat/pmcpl_calltree.c')
-rw-r--r-- | usr.sbin/pmcstat/pmcpl_calltree.c | 190 |
1 files changed, 104 insertions, 86 deletions
diff --git a/usr.sbin/pmcstat/pmcpl_calltree.c b/usr.sbin/pmcstat/pmcpl_calltree.c index f8ceece..0955133 100644 --- a/usr.sbin/pmcstat/pmcpl_calltree.c +++ b/usr.sbin/pmcstat/pmcpl_calltree.c @@ -120,8 +120,15 @@ struct pmcpl_ct_node_hash { struct pmcpl_ct_sample pmcpl_ct_callid; #define PMCPL_CT_MAXCOL PMC_CALLCHAIN_DEPTH_MAX -#define PMCPL_CT_MAXLINE 256 -struct pmcpl_ct_node *pmcpl_ct_topscreen[PMCPL_CT_MAXCOL][PMCPL_CT_MAXLINE]; +#define PMCPL_CT_MAXLINE 1024 /* TODO: dynamic. */ + +struct pmcpl_ct_line { + unsigned ln_sum; + unsigned ln_index; +}; + +struct pmcpl_ct_line pmcpl_ct_topmax[PMCPL_CT_MAXLINE+1]; +struct pmcpl_ct_node *pmcpl_ct_topscreen[PMCPL_CT_MAXCOL+1][PMCPL_CT_MAXLINE+1]; /* * All nodes indexed by function/image name are placed in a hash table. @@ -225,28 +232,6 @@ pmcpl_ct_arc_grow(int cursize, int *maxsize, struct pmcpl_ct_arc **items) } /* - * Compare two arc by samples value. - */ -static int -pmcpl_ct_arc_compare(void *thunk, const void *a, const void *b) -{ - const struct pmcpl_ct_arc *ct1, *ct2; - int pmcin = *(int *)thunk; - - ct1 = (const struct pmcpl_ct_arc *) a; - ct2 = (const struct pmcpl_ct_arc *) b; - - /* Sort in reverse order */ - if (PMCPL_CT_SAMPLE(pmcin, &ct1->pcta_samples) < - PMCPL_CT_SAMPLE(pmcin, &ct2->pcta_samples)) - return (1); - if (PMCPL_CT_SAMPLE(pmcin, &ct1->pcta_samples) > - PMCPL_CT_SAMPLE(pmcin, &ct2->pcta_samples)) - return (-1); - return (0); -} - -/* * Grow the instr table. */ @@ -366,9 +351,9 @@ pmcpl_ct_node_cleartag(void) static int pmcpl_ct_node_dumptop(int pmcin, struct pmcpl_ct_node *ct, - struct pmcpl_ct_sample *rsamples, int x, int *y, int maxy) + struct pmcpl_ct_sample *rsamples, int x, int *y) { - int i; + int i, terminal; if (ct->pct_flags & PMCPL_PCT_TAG) return 0; @@ -382,12 +367,21 @@ pmcpl_ct_node_dumptop(int pmcin, struct pmcpl_ct_node *ct, pmcpl_ct_topscreen[x][*y] = ct; /* - * This is a terminal node + * Check if this is a terminal node. + * We need to check that some samples exist + * for at least one arc for that PMC. */ - if (ct->pct_narc == 0) { + terminal = 1; + for (i = 0; i < ct->pct_narc; i++) + if (PMCPL_CT_SAMPLE(pmcin, + &ct->pct_arc[i].pcta_samples) != 0) { + terminal = 0; + break; + } + + if (ct->pct_narc == 0 || terminal) { pmcpl_ct_topscreen[x+1][*y] = NULL; - if (*y >= PMCPL_CT_MAXLINE || - *y >= maxy) + if (*y >= PMCPL_CT_MAXLINE) return 1; *y = *y + 1; for (i=0; i < x; i++) @@ -396,14 +390,7 @@ pmcpl_ct_node_dumptop(int pmcin, struct pmcpl_ct_node *ct, return 0; } - /* - * Quicksort the arcs. - */ - qsort_r(ct->pct_arc, ct->pct_narc, sizeof(struct pmcpl_ct_arc), - &pmcin, pmcpl_ct_arc_compare); - for (i = 0; i < ct->pct_narc; i++) { - /* Skip this arc if there is no sample at all. */ if (PMCPL_CT_SAMPLE(pmcin, &ct->pct_arc[i].pcta_samples) == 0) continue; @@ -411,7 +398,7 @@ pmcpl_ct_node_dumptop(int pmcin, struct pmcpl_ct_node *ct, &ct->pct_arc[i].pcta_samples) > pmcstat_threshold) { if (pmcpl_ct_node_dumptop(pmcin, ct->pct_arc[i].pcta_child, - rsamples, x+1, y, maxy)) + rsamples, x+1, y)) return 1; } } @@ -420,12 +407,36 @@ pmcpl_ct_node_dumptop(int pmcin, struct pmcpl_ct_node *ct, } /* + * Compare two top line by sum. + */ +static int +pmcpl_ct_line_compare(const void *a, const void *b) +{ + const struct pmcpl_ct_line *ct1, *ct2; + + ct1 = (const struct pmcpl_ct_line *) a; + ct2 = (const struct pmcpl_ct_line *) b; + + /* Sort in reverse order */ + if (ct1->ln_sum < ct2->ln_sum) + return (1); + if (ct1->ln_sum > ct2->ln_sum) + return (-1); + return (0); +} + +/* * Format and display given PMC index. */ static void pmcpl_ct_node_printtop(struct pmcpl_ct_sample *rsamples, int pmcin, int maxy) { +#undef TS +#undef TSI +#define TS(x, y) (pmcpl_ct_topscreen[x][y]) +#define TSI(x, y) (pmcpl_ct_topscreen[x][pmcpl_ct_topmax[y].ln_index]) + int v_attrs, ns_len, vs_len, is_len, width, indentwidth, x, y; float v; char ns[30], vs[10], is[20]; @@ -433,33 +444,60 @@ pmcpl_ct_node_printtop(struct pmcpl_ct_sample *rsamples, int pmcin, int maxy) struct pmcstat_symbol *sym; const char *space = " "; + /* + * Sort by line cost. + */ + for (y = 0; ; y++) { + ct = TS(1, y); + if (ct == NULL) + break; + + pmcpl_ct_topmax[y].ln_sum = 0; + pmcpl_ct_topmax[y].ln_index = y; + for (x = 1; TS(x, y) != NULL; x++) { + pmcpl_ct_topmax[y].ln_sum += + PMCPL_CT_SAMPLE(pmcin, &TS(x, y)->pct_samples); + } + } + qsort(pmcpl_ct_topmax, y, sizeof(pmcpl_ct_topmax[0]), + pmcpl_ct_line_compare); + pmcpl_ct_topmax[y].ln_index = y; + for (y = 0; y < maxy; y++) { - /* Output image. */ - ct = pmcpl_ct_topscreen[0][y]; - snprintf(is, sizeof(is), "%-10.10s", - pmcstat_string_unintern(ct->pct_image->pi_name)); - PMCSTAT_PRINTW("%s ", is); - width = indentwidth = 11; + ct = TSI(1, y); + if (ct == NULL) + break; + + if (y > 0) + PMCSTAT_PRINTW("\n"); - for (x = 0; pmcpl_ct_topscreen[x][y] !=NULL; x++) { + /* Output sum. */ + v = pmcpl_ct_topmax[y].ln_sum * 100.0 / + rsamples->sb[pmcin]; + snprintf(vs, sizeof(vs), "%.1f", v); + v_attrs = PMCSTAT_ATTRPERCENT(v); + PMCSTAT_ATTRON(v_attrs); + PMCSTAT_PRINTW("%5.5s ", vs); + PMCSTAT_ATTROFF(v_attrs); - ct = pmcpl_ct_topscreen[x][y]; + width = indentwidth = 5 + 1; + + for (x = 1; (ct = TSI(x, y)) != NULL; x++) { - ns[0] = '\0'; ns_len = 0; vs[0] = '\0'; vs_len = 0; is[0] = '\0'; is_len = 0; /* Format value. */ v = PMCPL_CT_SAMPLEP(pmcin, &ct->pct_samples); if (v > pmcstat_threshold) - vs_len = snprintf(vs, sizeof(vs), "(%.1f%%)", v); + vs_len = snprintf(vs, sizeof(vs), + "(%.1f%%)", v); v_attrs = PMCSTAT_ATTRPERCENT(v); if (pmcstat_skiplink && v <= pmcstat_threshold) { - PMCSTAT_PRINTW(". "); - width += 2; - continue; - } + strlcpy(ns, ".", sizeof(ns)); + ns_len = 1; + } else { sym = pmcstat_symbol_search(ct->pct_image, ct->pct_func); if (sym != NULL) { ns_len = snprintf(ns, sizeof(ns), "%s", @@ -469,12 +507,14 @@ pmcpl_ct_node_printtop(struct pmcpl_ct_sample *rsamples, int pmcin, int maxy) (void *)ct->pct_func); /* Format image. */ - if (x > 0 && pmcpl_ct_topscreen[x-1][y]->pct_image != ct->pct_image) + if (x == 1 || + TSI(x-1, y)->pct_image != ct->pct_image) is_len = snprintf(is, sizeof(is), "@%s", pmcstat_string_unintern(ct->pct_image->pi_name)); /* Check for line wrap. */ width += ns_len + is_len + vs_len + 1; + } if (width >= pmcstat_displaywidth) { maxy--; if (y >= maxy) @@ -487,7 +527,6 @@ pmcpl_ct_node_printtop(struct pmcpl_ct_sample *rsamples, int pmcin, int maxy) PMCSTAT_PRINTW("%s%s%s ", ns, is, vs); PMCSTAT_ATTROFF(v_attrs); } - PMCSTAT_PRINTW("\n"); } } @@ -498,46 +537,25 @@ pmcpl_ct_node_printtop(struct pmcpl_ct_sample *rsamples, int pmcin, int maxy) void pmcpl_ct_topdisplay(void) { - int i, x, y, pmcin; + int y; struct pmcpl_ct_sample r, *rsamples; rsamples = &r; pmcpl_ct_samples_root(rsamples); - PMCSTAT_PRINTW("%-10.10s %s\n", "IMAGE", "CALLTREE"); + pmcpl_ct_node_cleartag(); - for (pmcin = 0; pmcin < pmcstat_npmcs; pmcin++) { - /* Filter PMCs. */ - if (pmcstat_pmcinfilter != pmcin) - continue; + PMCSTAT_PRINTW("%5.5s %s\n", "%SAMP", "CALLTREE"); - pmcpl_ct_node_cleartag(); - - /* Quicksort the arcs. */ - qsort_r(pmcpl_ct_root->pct_arc, - pmcpl_ct_root->pct_narc, - sizeof(struct pmcpl_ct_arc), - &pmcin, pmcpl_ct_arc_compare); - - x = y = 0; - for (i = 0; i < pmcpl_ct_root->pct_narc; i++) { - /* Skip this arc if there is no sample at all. */ - if (PMCPL_CT_SAMPLE(pmcin, - &pmcpl_ct_root->pct_arc[i].pcta_samples) == 0) - continue; - if (PMCPL_CT_SAMPLEP(pmcin, - &pmcpl_ct_root->pct_arc[i].pcta_samples) <= - pmcstat_threshold) - continue; - if (pmcpl_ct_node_dumptop(pmcin, - pmcpl_ct_root->pct_arc[i].pcta_child, - rsamples, x, &y, pmcstat_displayheight - 2)) { - break; - } - } + y = 0; + if (pmcpl_ct_node_dumptop(pmcstat_pmcinfilter, + pmcpl_ct_root, rsamples, 0, &y)) + PMCSTAT_PRINTW("...\n"); + pmcpl_ct_topscreen[1][y] = NULL; + + pmcpl_ct_node_printtop(rsamples, + pmcstat_pmcinfilter, pmcstat_displayheight - 2); - pmcpl_ct_node_printtop(rsamples, pmcin, y); - } pmcpl_ct_samples_free(rsamples); } |