pmcstat: implement showing offsets into symbols in top mode

The -I option (and hotkey) is reused for this. Skipping symbol resolution is
moved to the new -A option (and hotkey).

While arguably this violates POLA I think it's a change for the better.
ALso note the -I option was added in head.

Differential Revision:	https://reviews.freebsd.org/D21658
This commit is contained in:
mjg 2020-08-05 19:05:49 +00:00
parent e87c28bd39
commit 778c921d1a
5 changed files with 60 additions and 24 deletions

View File

@ -107,8 +107,9 @@ struct pmcstat_args {
#define FLAGS_HAS_CPUMASK 0x00040000 /* -c */
#define FLAG_HAS_DURATION 0x00080000 /* -l secs */
#define FLAG_DO_WIDE_GPROF_HC 0x00100000 /* -e */
#define FLAG_SKIP_TOP_FN_RES 0x00200000 /* -I */
#define FLAG_SKIP_TOP_FN_RES 0x00200000 /* -A */
#define FLAG_FILTER_THREAD_ID 0x00400000 /* -L */
#define FLAG_SHOW_OFFSET 0x00800000 /* -I */
int pa_required; /* required features */
int pa_pplugin; /* pre-processing plugin */

View File

@ -152,10 +152,12 @@ pmcstat_cgnode_hash_lookup_pc(struct pmcstat_process *pp, pmc_id_t pmcid,
* Try determine the function at this offset. If we can't
* find a function round leave the `pc' value alone.
*/
if ((sym = pmcstat_symbol_search(image, pc)) != NULL)
pc = sym->ps_start;
else
pmcstat_stats.ps_samples_unknown_function++;
if (!(args.pa_flags & (FLAG_SKIP_TOP_FN_RES | FLAG_SHOW_OFFSET))) {
if ((sym = pmcstat_symbol_search(image, pc)) != NULL)
pc = sym->ps_start;
else
pmcstat_stats.ps_samples_unknown_function++;
}
for (hash = i = 0; i < sizeof(uintfptr_t); i++)
hash += (pc >> i) & 0xFF;
@ -485,22 +487,35 @@ pmcstat_cgnode_topprint(struct pmcstat_cgnode *cg,
v = PMCPL_CG_COUNTP(cg);
snprintf(vs, sizeof(vs), "%.1f", v);
v_attrs = PMCSTAT_ATTRPERCENT(v);
sym = NULL;
/* Format name. */
if (!(args.pa_flags & FLAG_SKIP_TOP_FN_RES))
sym = pmcstat_symbol_search(cg->pcg_image, cg->pcg_func);
if (sym != NULL) {
snprintf(ns, sizeof(ns), "%s",
pmcstat_string_unintern(sym->ps_name));
} else
sym = pmcstat_symbol_search(cg->pcg_image, cg->pcg_func);
if (sym == NULL) {
snprintf(ns, sizeof(ns), "%p",
(void *)(cg->pcg_image->pi_vaddr + cg->pcg_func));
} else {
switch (args.pa_flags & (FLAG_SKIP_TOP_FN_RES | FLAG_SHOW_OFFSET)) {
case FLAG_SKIP_TOP_FN_RES | FLAG_SHOW_OFFSET:
case FLAG_SKIP_TOP_FN_RES:
snprintf(ns, sizeof(ns), "%p",
(void *)(cg->pcg_image->pi_vaddr + cg->pcg_func));
break;
case FLAG_SHOW_OFFSET:
snprintf(ns, sizeof(ns), "%s+%#0lx",
pmcstat_string_unintern(sym->ps_name),
cg->pcg_func - sym->ps_start);
break;
default:
snprintf(ns, sizeof(ns), "%s",
pmcstat_string_unintern(sym->ps_name));
break;
}
}
PMCSTAT_ATTRON(v_attrs);
PMCSTAT_PRINTW("%5.5s", vs);
PMCSTAT_ATTROFF(v_attrs);
PMCSTAT_PRINTW(" %-10.10s %-20.20s",
PMCSTAT_PRINTW(" %-10.10s %-30.30s",
pmcstat_string_unintern(cg->pcg_image->pi_name),
ns);
@ -624,7 +639,7 @@ pmcpl_cg_topdisplay(void)
qsort(sortbuffer, nentries, sizeof(struct pmcstat_cgnode *),
pmcstat_cgnode_compare);
PMCSTAT_PRINTW("%5.5s %-10.10s %-20.20s %s\n",
PMCSTAT_PRINTW("%5.5s %-10.10s %-30.30s %s\n",
"%SAMP", "IMAGE", "FUNCTION", "CALLERS");
nentries = min(pmcstat_displayheight - 2, nentries);

View File

@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd May 25, 2018
.Dd August 5, 2020
.Dt PMCSTAT 8
.Os
.Sh NAME
@ -33,6 +33,7 @@
.Nd "performance measurement with performance monitoring hardware"
.Sh SYNOPSIS
.Nm
.Op Fl A
.Op Fl C
.Op Fl D Ar pathname
.Op Fl E
@ -123,6 +124,8 @@ process' current and future children.
.Sh OPTIONS
The following options are available:
.Bl -tag -width indent
.It Fl A
Skip symbol lookup and display address instead.
.It Fl C
Toggle between showing cumulative or incremental counts for
subsequent counting mode PMCs specified on the command line.
@ -161,7 +164,7 @@ this information is sent to the output file specified by the
.Fl o
option.
.It Fl I
Skip symbol lookup and display address instead.
Show the offset of the instruction pointer into the symbol.
.It Fl L
List all event names.
.It Fl M Ar mapfilename
@ -222,10 +225,10 @@ specified in
.Ar event-spec .
.It Fl T
Use a top like mode for sampling PMCs. The following hotkeys
can be used: 'c+a' switch to accumulative mode, 'c+d' switch
to delta mode, 'm' merge PMCs, 'n' change view, 'p' show next
PMC, ' ' pause, 'q' quit. calltree only: 'f' cost under threshold
is seen as a dot.
can be used: 'A' toggle symbol resolution, 'c+a' switch to accumulative mode, 'c+d'
switch to delta mode, 'I' toggle showing offsets into symbols, 'm' merge PMCs, 'n'
change view, 'p' show next PMC, ' ' pause, 'q' quit. calltree only: 'f' cost under
threshold is seen as a dot.
.It Fl U
Toggle capturing user-space call traces while in kernel mode.
The default is for sampling PMCs to capture user-space callchain information

View File

@ -511,8 +511,12 @@ main(int argc, char **argv)
CPU_COPY(&rootmask, &cpumask);
while ((option = getopt(argc, argv,
"CD:EF:G:ILM:NO:P:R:S:TUWZa:c:def:gi:k:l:m:n:o:p:qr:s:t:u:vw:z:")) != -1)
"ACD:EF:G:ILM:NO:P:R:S:TUWZa:c:def:gi:k:l:m:n:o:p:qr:s:t:u:vw:z:")) != -1)
switch (option) {
case 'A':
args.pa_flags |= FLAG_SKIP_TOP_FN_RES;
break;
case 'a': /* Annotate + callgraph */
args.pa_flags |= FLAG_DO_ANNOTATE;
args.pa_plugin = PMCSTAT_PL_ANNOTATE_CG;
@ -586,14 +590,15 @@ main(int argc, char **argv)
args.pa_plugin = PMCSTAT_PL_GPROF;
break;
case 'I':
args.pa_flags |= FLAG_SKIP_TOP_FN_RES;
break;
case 'i':
args.pa_flags |= FLAG_FILTER_THREAD_ID;
args.pa_tid = strtol(optarg, &end, 0);
break;
case 'I':
args.pa_flags |= FLAG_SHOW_OFFSET;
break;
case 'k': /* pathname to the kernel */
free(args.pa_kernel);
args.pa_kernel = strdup(optarg);

View File

@ -612,6 +612,12 @@ pmcstat_keypress_log(void)
c = wgetch(w);
wprintw(w, "Key: %c => ", c);
switch (c) {
case 'A':
if (args.pa_flags & FLAG_SKIP_TOP_FN_RES)
args.pa_flags &= ~FLAG_SKIP_TOP_FN_RES;
else
args.pa_flags |= FLAG_SKIP_TOP_FN_RES;
break;
case 'c':
wprintw(w, "enter mode 'd' or 'a' => ");
c = wgetch(w);
@ -623,6 +629,12 @@ pmcstat_keypress_log(void)
wprintw(w, "switching to accumulation mode");
}
break;
case 'I':
if (args.pa_flags & FLAG_SHOW_OFFSET)
args.pa_flags &= ~FLAG_SHOW_OFFSET;
else
args.pa_flags |= FLAG_SHOW_OFFSET;
break;
case 'm':
pmcstat_mergepmc = !pmcstat_mergepmc;
/*