pmcannotate: Add a '-m' mode option to control per-line annotations.

- "block" (the default mode) displays per-block percentages in front of
   each annotated line.

- "global" displays a global percentage in front of each line.

- "raw" displays the raw count of sample hits in front of each line.

Reviewed by:	Pau Amma <pauamma@gundo.com>, mav
Sponsored by:	University of Cambridge, Google, Inc.
Differential Revision:	https://reviews.freebsd.org/D35401

(cherry picked from commit de11299323e0a647ae2164f74ca966862e7c4dd8)
This commit is contained in:
John Baldwin 2025-01-14 10:39:53 -05:00
parent 08f22bb41f
commit 067de34b8e
2 changed files with 60 additions and 9 deletions

View file

@ -25,7 +25,7 @@
.\" out of the use of this software, even if advised of the possibility of
.\" such damage.
.\"
.Dd November 20, 2008
.Dd January 14, 2025
.Dt PMCANNOTATE 8
.Os
.Sh NAME
@ -37,6 +37,7 @@
.Op Fl h
.Op Fl k Ar pathname
.Op Fl l Ar level
.Op Fl m Ar mode
.Ar pmcout.out binaryobj
.Sh DESCRIPTION
The
@ -84,6 +85,18 @@ This directory specifies where
should look for the kernel and its modules.
The default is
.Pa /boot/kernel .
.It Fl m Ar mode
Format to use when annotating source or assembly lines.
One of:
.Bl -tag -width indent
.It Cm block
Display percentage of matching samples relative to samples
falling in the current block.
.It Cm global
Display percentage of matching samples relative to all samples.
.It Cm raw
Display the raw count of matching samples.
.El
.El
.Sh LIMITATIONS
As long as

View file

@ -35,6 +35,7 @@
#include <sys/queue.h>
#include <ctype.h>
#include <err.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
@ -59,7 +60,7 @@
exit(EXIT_FAILURE); \
} while (0)
#define PERCSAMP(x) ((x) * 100 / totalsamples)
#define PERCSAMP(x) ((float)(x) * 100 / totalsamples)
struct entry {
TAILQ_ENTRY(entry) en_iter;
@ -109,7 +110,9 @@ static TAILQ_HEAD(, aggent) fqueue = TAILQ_HEAD_INITIALIZER(fqueue);
* Use a float value in order to automatically promote operations
* to return a float value rather than use casts.
*/
static float totalsamples;
static u_int totalsamples;
static enum { RAW, BLOCK_PERCENT, GLOBAL_PERCENT } print_mode;
/*
* Identifies a string cointaining objdump's assembly printout.
@ -501,6 +504,30 @@ general_insertent(struct entry *entry)
TAILQ_INSERT_TAIL(&mainlst, entry, en_iter);
}
/*
* Return a string either holding a percentage or the raw count value.
*/
static const char *
print_count(u_int nsamples, u_int totsamples)
{
static char buf[16];
switch (print_mode) {
case RAW:
snprintf(buf, sizeof(buf), "%u", nsamples);
break;
case BLOCK_PERCENT:
snprintf(buf, sizeof(buf), "%.2f%%", (float)nsamples * 100 /
totsamples);
break;
case GLOBAL_PERCENT:
snprintf(buf, sizeof(buf), "%.2f%%", (float)nsamples * 100 /
totalsamples);
break;
}
return (buf);
}
/*
* Printout the body of an "objdump -d" assembly function.
* It does simply stops when a new function is encountered,
@ -529,8 +556,8 @@ general_printasm(FILE *fp, struct aggent *agg)
if (obj == NULL)
printf("\t| %s", buffer);
else
printf("%.2f%%\t| %s",
(float)obj->en_nsamples * 100 / agg->ag_nsamples,
printf("%7s | %s",
print_count(obj->en_nsamples, agg->ag_nsamples),
buffer);
}
}
@ -623,8 +650,8 @@ printblock(FILE *fp, struct aggent *agg)
printf("\t| %s", buffer);
else {
done = 1;
printf("%.2f%%\t| %s",
(float)tnsamples * 100 / agg->ag_nsamples, buffer);
printf("%7s | %s",
print_count(tnsamples, agg->ag_nsamples), buffer);
}
}
@ -657,7 +684,7 @@ usage(const char *progname)
{
fprintf(stderr,
"usage: %s [-a] [-h] [-k kfile] [-l lb] pmcraw.out binary\n",
"usage: %s [-a] [-h] [-k kfile] [-l lb] [-m mode] pmcraw.out binary\n",
progname);
exit(EXIT_SUCCESS);
}
@ -682,7 +709,8 @@ main(int argc, char *argv[])
kfile = NULL;
asmsrc = 0;
limit = 0.5;
while ((cget = getopt(argc, argv, "ahl:k:")) != -1)
print_mode = BLOCK_PERCENT;
while ((cget = getopt(argc, argv, "ahl:m:k:")) != -1)
switch(cget) {
case 'a':
asmsrc = 1;
@ -693,6 +721,16 @@ main(int argc, char *argv[])
case 'l':
limit = (float)atof(optarg);
break;
case 'm':
if (strcasecmp(optarg, "raw") == 0)
print_mode = RAW;
else if (strcasecmp(optarg, "global") == 0)
print_mode = GLOBAL_PERCENT;
else if (strcasecmp(optarg, "block") == 0)
print_mode = BLOCK_PERCENT;
else
errx(1, "Invalid mode %s", optarg);
break;
case 'h':
case '?':
default: