Index: usr.sbin/pmcannotate/pmcannotate.8 =================================================================== --- usr.sbin/pmcannotate/pmcannotate.8 +++ usr.sbin/pmcannotate/pmcannotate.8 @@ -39,6 +39,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 @@ -86,6 +87,18 @@ 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 Index: usr.sbin/pmcannotate/pmcannotate.c =================================================================== --- usr.sbin/pmcannotate/pmcannotate.c +++ usr.sbin/pmcannotate/pmcannotate.c @@ -37,6 +37,7 @@ #include #include +#include #include #include #include @@ -61,7 +62,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; @@ -111,7 +112,9 @@ * 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. @@ -503,6 +506,30 @@ 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, @@ -531,8 +558,8 @@ 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); } } @@ -625,8 +652,8 @@ 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); } } @@ -659,7 +686,7 @@ { 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); } @@ -684,7 +711,8 @@ 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; @@ -695,6 +723,16 @@ 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: