Index: usr.sbin/pmcstat/pmcpl_gprof.c =================================================================== --- usr.sbin/pmcstat/pmcpl_gprof.c +++ usr.sbin/pmcstat/pmcpl_gprof.c @@ -74,6 +74,14 @@ #include "pmcpl_callgraph.h" #include "pmcpl_gprof.h" +typedef uint64_t WIDEHISTCOUNTER; + +#define WIDEHISTCOUNTER_MAX UINT64_MAX +#define HISTCOUNTER_MAX USHRT_MAX +#define WIDEHISTCOUNTER_GMONTYPE ((int) 64) +#define HISTCOUNTER_GMONTYPE ((int) 0) +static int hc_sz=0; + /* * struct pmcstat_gmonfile tracks a given 'gmon.out' file. These * files are mmap()'ed in as needed. @@ -126,11 +134,13 @@ gm.lpc = image->pi_start; gm.hpc = image->pi_end; - gm.ncnt = (pgf->pgf_nbuckets * sizeof(HISTCOUNTER)) + - sizeof(struct gmonhdr); + gm.ncnt = (pgf->pgf_nbuckets * hc_sz) + sizeof(struct gmonhdr); gm.version = GMONVERSION; gm.profrate = 0; /* use ticks */ - gm.histcounter_type = 0; /* compatibility with moncontrol() */ + if (args.pa_flags & FLAG_DO_WIDE_GPROF_HC) + gm.histcounter_type = WIDEHISTCOUNTER_GMONTYPE; + else + gm.histcounter_type = HISTCOUNTER_GMONTYPE;; gm.spare[0] = gm.spare[1] = 0; /* Write out the gmon header */ @@ -400,6 +410,7 @@ struct pmcstat_gmonfile *pgf; uintfptr_t bucket; HISTCOUNTER *hc; + WIDEHISTCOUNTER *whc; pmc_id_t pmcid; (void) nsamples; (void) usermode; (void) cpu; @@ -437,6 +448,14 @@ */ pgf = pmcstat_image_find_gmonfile(image, pmcid); if (pgf == NULL) { + if (hc_sz == 0) { + /* Determine the correct histcounter size. */ + if (args.pa_flags & FLAG_DO_WIDE_GPROF_HC) + hc_sz = sizeof(WIDEHISTCOUNTER); + else + hc_sz = sizeof(HISTCOUNTER); + } + if ((pgf = calloc(1, sizeof(*pgf))) == NULL) err(EX_OSERR, "ERROR:"); @@ -448,7 +467,7 @@ pgf->pgf_nbuckets = (image->pi_end - image->pi_start) / FUNCTION_ALIGNMENT; /* see */ pgf->pgf_ndatabytes = sizeof(struct gmonhdr) + - pgf->pgf_nbuckets * sizeof(HISTCOUNTER); + pgf->pgf_nbuckets * hc_sz; pgf->pgf_nsamples = 0; pgf->pgf_file = NULL; @@ -474,14 +493,25 @@ assert(bucket < pgf->pgf_nbuckets); - hc = (HISTCOUNTER *) ((uintptr_t) pgf->pgf_gmondata + - sizeof(struct gmonhdr)); - - /* saturating add */ - if (hc[bucket] < 0xFFFFU) /* XXX tie this to sizeof(HISTCOUNTER) */ - hc[bucket]++; - else /* mark that an overflow occurred */ - pgf->pgf_overflow = 1; + if (args.pa_flags & FLAG_DO_WIDE_GPROF_HC) { + whc = (WIDEHISTCOUNTER *) ((uintptr_t) pgf->pgf_gmondata + + sizeof(struct gmonhdr)); + + /* saturating add */ + if (whc[bucket] < WIDEHISTCOUNTER_MAX) + whc[bucket]++; + else /* mark that an overflow occurred */ + pgf->pgf_overflow = 1; + } else { + hc = (HISTCOUNTER *) ((uintptr_t) pgf->pgf_gmondata + + sizeof(struct gmonhdr)); + + /* saturating add */ + if (hc[bucket] < HISTCOUNTER_MAX) + hc[bucket]++; + else /* mark that an overflow occurred */ + pgf->pgf_overflow = 1; + } pgf->pgf_nsamples++; } Index: usr.sbin/pmcstat/pmcstat.h =================================================================== --- usr.sbin/pmcstat/pmcstat.h +++ usr.sbin/pmcstat/pmcstat.h @@ -55,6 +55,7 @@ #define FLAG_DO_ANALYSIS 0x00020000 /* -g or -G or -m or -T */ #define FLAGS_HAS_CPUMASK 0x00040000 /* -c */ #define FLAG_HAS_DURATION 0x00080000 /* -l secs */ +#define FLAG_DO_WIDE_GPROF_HC 0x00100000 /* -e */ #define DEFAULT_SAMPLE_COUNT 65536 #define DEFAULT_WAIT_INTERVAL 5.0 Index: usr.sbin/pmcstat/pmcstat.8 =================================================================== --- usr.sbin/pmcstat/pmcstat.8 +++ usr.sbin/pmcstat/pmcstat.8 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 27, 2015 +.Dd November 17, 2015 .Dt PMCSTAT 8 .Os .Sh NAME @@ -49,6 +49,7 @@ .Op Fl a Ar pathname .Op Fl c Ar cpu-spec .Op Fl d +.Op Fl e .Op Fl f Ar pluginopt .Op Fl g .Op Fl k Ar kerneldir @@ -260,6 +261,12 @@ .Fl P , or .Fl S ) . +.It Fl e +Specify that the gprof profile files will use a wide history counter. +These files are produced in a format compatible with +.Xr gprof 1 . +However, other tools that cannot fully parse a BSD-style +gmon header might be unable to correctly parse these files. .It Fl f Ar pluginopt Pass option string to the active plugin. .br Index: usr.sbin/pmcstat/pmcstat.c =================================================================== --- usr.sbin/pmcstat/pmcstat.c +++ usr.sbin/pmcstat/pmcstat.c @@ -506,6 +506,7 @@ "\t -a file\t print sampled PCs and callgraph to \"file\"\n" "\t -c cpu-list\t set cpus for subsequent system-wide PMCs\n" "\t -d\t\t (toggle) track descendants\n" + "\t -e\t\t use wide history counter for gprof(1) output\n" "\t -f spec\t pass \"spec\" to as plugin option\n" "\t -g\t\t produce gprof(1) compatible profiles\n" "\t -k dir\t\t set the path to the kernel\n" @@ -627,7 +628,7 @@ CPU_COPY(&rootmask, &cpumask); while ((option = getopt(argc, argv, - "CD:EF:G:M:NO:P:R:S:TWa:c:df:gk:l:m:n:o:p:qr:s:t:vw:z:")) != -1) + "CD:EF:G:M:NO:P:R:S:TWa:c:def:gk:l:m:n:o:p:qr:s:t:vw:z:")) != -1) switch (option) { case 'a': /* Annotate + callgraph */ args.pa_flags |= FLAG_DO_ANNOTATE; @@ -668,6 +669,10 @@ args.pa_required |= FLAG_HAS_PROCESS_PMCS; break; + case 'e': /* wide gprof metrics */ + args.pa_flags |= FLAG_DO_WIDE_GPROF_HC; + break; + case 'F': /* produce a system-wide calltree */ args.pa_flags |= FLAG_DO_CALLGRAPHS; args.pa_plugin = PMCSTAT_PL_CALLTREE; @@ -1022,6 +1027,13 @@ "ERROR: options -g/-G/-m/-T require sampling PMCs or -R to be specified." ); + /* check if -e was specified without -g */ + if ((args.pa_flags & FLAG_DO_WIDE_GPROF_HC) && + !(args.pa_flags & FLAG_DO_GPROF)) + errx(EX_USAGE, +"ERROR: option -e requires gprof mode to be specified." + ); + /* check if -O was spuriously specified */ if ((args.pa_flags & FLAG_HAS_OUTPUT_LOGFILE) && (args.pa_required & FLAG_HAS_OUTPUT_LOGFILE) == 0)