summaryrefslogtreecommitdiffstats
path: root/usr.sbin/pmcstat
diff options
context:
space:
mode:
authorjkoshy <jkoshy@FreeBSD.org>2005-09-13 02:23:25 +0000
committerjkoshy <jkoshy@FreeBSD.org>2005-09-13 02:23:25 +0000
commit14b399b10383b000dd4ca86ddb47dfdb6e1113a1 (patch)
treed1e6a4b0ccf715917f2e88f3f65e6507b530a5a6 /usr.sbin/pmcstat
parent665ea151e9869946909a706dbf36651b30d31ebb (diff)
downloadFreeBSD-src-14b399b10383b000dd4ca86ddb47dfdb6e1113a1.zip
FreeBSD-src-14b399b10383b000dd4ca86ddb47dfdb6e1113a1.tar.gz
Fix a bug that caused generated gmon.out profiles to be out of
whack. Use saturating arithmetic when incrementing a bucket. Improve a few comments. MFC after: 3 days
Diffstat (limited to 'usr.sbin/pmcstat')
-rw-r--r--usr.sbin/pmcstat/pmcstat_log.c41
1 files changed, 31 insertions, 10 deletions
diff --git a/usr.sbin/pmcstat/pmcstat_log.c b/usr.sbin/pmcstat/pmcstat_log.c
index 500959d..7cfc841 100644
--- a/usr.sbin/pmcstat/pmcstat_log.c
+++ b/usr.sbin/pmcstat/pmcstat_log.c
@@ -30,6 +30,19 @@ __FBSDID("$FreeBSD$");
/*
* Transform a hwpmc(4) log into human readable form and into gprof(1)
* compatible profiles.
+ *
+ * Each executable object encountered in the log gets one 'gmon.out'
+ * profile per PMC. We currently track:
+ * - program executables
+ * - shared libraries loaded by the runtime loader
+ * - the runtime loader itself
+ * - the kernel.
+ * We do not track shared objects mapped in by dlopen() yet (this
+ * needs additional support from hwpmc(4)).
+ *
+ * 'gmon.out' profiles generated for a given sampling PMC are
+ * aggregates of all the samples for that particular executable
+ * object.
*/
#include <sys/param.h>
@@ -80,7 +93,7 @@ struct pmcstat_string {
static LIST_HEAD(,pmcstat_string) pmcstat_string_hash[PMCSTAT_NHASH];
/*
- * 'pmcstat_pmcs' is a mapping for PMC ids to their human-readable
+ * 'pmcstat_pmcrecord' is a mapping from PMC ids to human-readable
* names.
*/
@@ -93,11 +106,17 @@ struct pmcstat_pmcrecord {
static LIST_HEAD(,pmcstat_pmcrecord) pmcstat_pmcs =
LIST_HEAD_INITIALIZER(&pmcstat_pmcs);
+
+/*
+ * struct pmcstat_gmonfile tracks a given 'gmon.out' file. These
+ * files are mmap()'ed in as needed.
+ */
+
struct pmcstat_gmonfile {
LIST_ENTRY(pmcstat_gmonfile) pgf_next; /* list of entries */
pmc_id_t pgf_pmcid; /* id of the associated pmc */
- size_t pgf_nsamples; /* number of samples in this gmon.out */
- const char *pgf_name; /* name of gmon.out file */
+ size_t pgf_nbuckets; /* #buckets in this gmon.out */
+ const char *pgf_name; /* pathname of gmon.out file */
size_t pgf_ndatabytes; /* number of bytes mapped */
void *pgf_gmondata; /* pointer to mmap'ed data */
};
@@ -105,8 +124,6 @@ struct pmcstat_gmonfile {
static TAILQ_HEAD(,pmcstat_gmonfile) pmcstat_gmonfiles =
TAILQ_HEAD_INITIALIZER(pmcstat_gmonfiles);
-#define GM_TO_BUCKETS(GM) ((uint16_t *) ((char *) (GM) + sizeof(*(GM))))
-
/*
* A 'pmcstat_image' structure describes an executable program on
* disk. 'pi_internedpath' is a cookie representing the pathname of
@@ -218,7 +235,8 @@ pmcstat_gmon_create_file(struct pmcstat_gmonfile *pgf,
gm.lpc = image->pi_start;
gm.hpc = image->pi_end;
- gm.ncnt = pgf->pgf_nsamples;
+ gm.ncnt = (pgf->pgf_nbuckets * sizeof(HISTCOUNTER)) +
+ sizeof(struct gmonhdr);
gm.version = GMONVERSION;
gm.profrate = 0; /* use ticks */
gm.histcounter_type = 0; /* compatibility with moncontrol() */
@@ -514,10 +532,10 @@ pmcstat_image_increment_bucket(struct pmcstat_pcmap *map, uintfptr_t pc,
pgf->pgf_name = pmcstat_gmon_create_name(a->pa_samplesdir,
image, pmcid);
pgf->pgf_pmcid = pmcid;
- pgf->pgf_nsamples = (image->pi_end - image->pi_start) /
+ pgf->pgf_nbuckets = (image->pi_end - image->pi_start) /
FUNCTION_ALIGNMENT; /* see <machine/profile.h> */
pgf->pgf_ndatabytes = sizeof(struct gmonhdr) +
- pgf->pgf_nsamples * sizeof(HISTCOUNTER);
+ pgf->pgf_nbuckets * sizeof(HISTCOUNTER);
pmcstat_gmon_create_file(pgf, image);
@@ -533,11 +551,14 @@ pmcstat_image_increment_bucket(struct pmcstat_pcmap *map, uintfptr_t pc,
bucket = (pc - map->ppm_lowpc) / FUNCTION_ALIGNMENT;
- assert(bucket < pgf->pgf_nsamples);
+ assert(bucket < pgf->pgf_nbuckets);
hc = (HISTCOUNTER *) ((uintptr_t) pgf->pgf_gmondata +
sizeof(struct gmonhdr));
- hc[bucket]++;
+
+ /* saturating add */
+ if (hc[bucket] < 0xFFFF)
+ hc[bucket]++;
}
OpenPOWER on IntegriCloud