Add the -m option to pmcstat.
This option prints the list of sampled PCs along with the function name, the start and end addresses of this where their live within. Reviewed by: jkoshy Tested by: gnn Sponsored by: Nokia
This commit is contained in:
parent
38cc5da78e
commit
c0252222a2
@ -48,6 +48,7 @@
|
||||
.Op Fl d
|
||||
.Op Fl g
|
||||
.Op Fl k Ar kerneldir
|
||||
.Op Fl m Ar pathname
|
||||
.Op Fl n Ar rate
|
||||
.Op Fl o Ar outputfile
|
||||
.Op Fl p Ar event-spec
|
||||
@ -232,6 +233,19 @@ This directory specifies where
|
||||
should look for the kernel and its modules.
|
||||
The default is
|
||||
.Pa /boot/kernel .
|
||||
.It Fl m Ar pathname
|
||||
Print the sampled PCs with the name, the start and ending addresses
|
||||
of the function within they live.
|
||||
The
|
||||
.Ar pathname
|
||||
argument is mandatory and indicates where informations will be stored.
|
||||
If argument
|
||||
.Ar pathname
|
||||
is a
|
||||
.Dq Li -
|
||||
this information is sent to the output file specified by the
|
||||
.Fl o
|
||||
option.
|
||||
.It Fl n Ar rate
|
||||
Set the default sampling rate for subsequent sampling mode
|
||||
PMCs specified on the command line.
|
||||
|
@ -594,7 +594,7 @@ main(int argc, char **argv)
|
||||
}
|
||||
|
||||
while ((option = getopt(argc, argv,
|
||||
"CD:EG:M:NO:P:R:S:Wc:dgk:n:o:p:qr:s:t:vw:z:")) != -1)
|
||||
"CD:EG:M:NO:P:R:S:Wc:dgk:m:n:o:p:qr:s:t:vw:z:")) != -1)
|
||||
switch (option) {
|
||||
case 'C': /* cumulative values */
|
||||
use_cumulative_counts = !use_cumulative_counts;
|
||||
@ -644,6 +644,11 @@ main(int argc, char **argv)
|
||||
args.pa_flags |= FLAG_HAS_KERNELPATH;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
args.pa_flags |= FLAG_WANTS_MAPPINGS;
|
||||
graphfilename = optarg;
|
||||
break;
|
||||
|
||||
case 'E': /* log process exit */
|
||||
do_logprocexit = !do_logprocexit;
|
||||
args.pa_required |= (FLAG_HAS_PROCESS_PMCS |
|
||||
@ -827,7 +832,8 @@ main(int argc, char **argv)
|
||||
if (argc) /* command line present */
|
||||
args.pa_flags |= FLAG_HAS_COMMANDLINE;
|
||||
|
||||
if (args.pa_flags & (FLAG_DO_GPROF | FLAG_DO_CALLGRAPHS))
|
||||
if (args.pa_flags & (FLAG_DO_GPROF | FLAG_DO_CALLGRAPHS |
|
||||
FLAG_WANTS_MAPPINGS))
|
||||
args.pa_flags |= FLAG_DO_ANALYSIS;
|
||||
|
||||
/*
|
||||
@ -839,6 +845,16 @@ main(int argc, char **argv)
|
||||
errx(EX_USAGE, "ERROR: options -O and -R are mutually "
|
||||
"exclusive.");
|
||||
|
||||
/* -m option is allowed with -R only. */
|
||||
if (args.pa_flags & FLAG_WANTS_MAPPINGS && args.pa_inputpath == NULL)
|
||||
errx(EX_USAGE, "ERROR: option -m requires an input file");
|
||||
|
||||
/* -m option is not allowed combined with -g or -G. */
|
||||
if (args.pa_flags & FLAG_WANTS_MAPPINGS &&
|
||||
args.pa_flags & (FLAG_DO_GPROF | FLAG_DO_CALLGRAPHS))
|
||||
errx(EX_USAGE, "ERROR: option -m and -g | -G are mutually "
|
||||
"exclusive");
|
||||
|
||||
if (args.pa_flags & FLAG_READ_LOGFILE) {
|
||||
errmsg = NULL;
|
||||
if (args.pa_flags & FLAG_HAS_COMMANDLINE)
|
||||
@ -980,6 +996,12 @@ main(int argc, char **argv)
|
||||
"for writing", graphfilename);
|
||||
}
|
||||
}
|
||||
if (args.pa_flags & FLAG_WANTS_MAPPINGS) {
|
||||
args.pa_graphfile = fopen(graphfilename, "w");
|
||||
if (args.pa_graphfile == NULL)
|
||||
err(EX_OSERR, "ERROR: cannot open \"%s\" for writing",
|
||||
graphfilename);
|
||||
}
|
||||
|
||||
/* if we've been asked to process a log file, do that and exit */
|
||||
if (args.pa_flags & FLAG_READ_LOGFILE) {
|
||||
|
@ -49,6 +49,7 @@
|
||||
#define FLAG_DO_PRINT 0x00002000 /* -o */
|
||||
#define FLAG_DO_CALLGRAPHS 0x00004000 /* -G */
|
||||
#define FLAG_DO_ANALYSIS 0x00008000 /* -g or -G */
|
||||
#define FLAG_WANTS_MAPPINGS 0x00010000 /* -m */
|
||||
|
||||
#define DEFAULT_SAMPLE_COUNT 65536
|
||||
#define DEFAULT_WAIT_INTERVAL 5.0
|
||||
|
@ -1969,9 +1969,10 @@ static int
|
||||
pmcstat_analyze_log(struct pmcstat_args *a)
|
||||
{
|
||||
uint32_t cpu, cpuflags;
|
||||
uintfptr_t pc;
|
||||
uintfptr_t pc, newpc;
|
||||
pid_t pid;
|
||||
struct pmcstat_image *image;
|
||||
struct pmcstat_symbol *sym;
|
||||
struct pmcstat_process *pp, *ppnew;
|
||||
struct pmcstat_pcmap *ppm, *ppmtmp;
|
||||
struct pmclog_ev ev;
|
||||
@ -2085,21 +2086,41 @@ pmcstat_analyze_log(struct pmcstat_args *a)
|
||||
pp = pmcstat_process_lookup(ev.pl_u.pl_cc.pl_pid,
|
||||
PMCSTAT_ALLOCATE);
|
||||
|
||||
pmcstat_record_callchain(pp,
|
||||
ev.pl_u.pl_cc.pl_pmcid, ev.pl_u.pl_cc.pl_npc,
|
||||
ev.pl_u.pl_cc.pl_pc,
|
||||
PMC_CALLCHAIN_CPUFLAGS_TO_USERMODE(cpuflags), a);
|
||||
if ((a->pa_flags & FLAG_WANTS_MAPPINGS) == 0)
|
||||
pmcstat_record_callchain(pp,
|
||||
ev.pl_u.pl_cc.pl_pmcid,
|
||||
ev.pl_u.pl_cc.pl_npc, ev.pl_u.pl_cc.pl_pc,
|
||||
PMC_CALLCHAIN_CPUFLAGS_TO_USERMODE(cpuflags), a);
|
||||
|
||||
if ((a->pa_flags & FLAG_DO_GPROF) == 0)
|
||||
if ((a->pa_flags &
|
||||
(FLAG_DO_GPROF | FLAG_WANTS_MAPPINGS)) == 0)
|
||||
break;
|
||||
|
||||
pc = ev.pl_u.pl_cc.pl_pc[0];
|
||||
if ((ppm = pmcstat_process_find_map(pp, pc)) == NULL &&
|
||||
(ppm = pmcstat_process_find_map(pmcstat_kernproc,
|
||||
pc)) == NULL) { /* unknown offset */
|
||||
if (PMC_CALLCHAIN_CPUFLAGS_TO_USERMODE(cpuflags) == 0)
|
||||
pp = pmcstat_kernproc;
|
||||
ppm = pmcstat_process_find_map(pp, pc);
|
||||
if (ppm == NULL) {
|
||||
|
||||
/* Unknown offset. */
|
||||
pmcstat_stats.ps_samples_unknown_offset++;
|
||||
break;
|
||||
}
|
||||
if (a->pa_flags & FLAG_WANTS_MAPPINGS) {
|
||||
image = ppm->ppm_image;
|
||||
newpc = pc - (ppm->ppm_lowpc +
|
||||
(image->pi_vaddr - image->pi_start));
|
||||
sym = pmcstat_symbol_search(image, newpc);
|
||||
if (sym == NULL)
|
||||
break;
|
||||
fprintf(a->pa_graphfile, "%p %s 0x%jx 0x%jx\n",
|
||||
(void *)pc,
|
||||
pmcstat_string_unintern(sym->ps_name),
|
||||
(uintmax_t)(sym->ps_start +
|
||||
image->pi_vaddr), (uintmax_t)(sym->ps_end +
|
||||
image->pi_vaddr));
|
||||
break;
|
||||
}
|
||||
|
||||
pmcstat_image_increment_bucket(ppm, pc,
|
||||
ev.pl_u.pl_cc.pl_pmcid, a);
|
||||
|
Loading…
Reference in New Issue
Block a user