1203790Sfabient/*- 2203790Sfabient * Copyright (c) 2005-2007, Joseph Koshy 3203790Sfabient * Copyright (c) 2007 The FreeBSD Foundation 4203790Sfabient * Copyright (c) 2009, Fabien Thomas 5203790Sfabient * All rights reserved. 6203790Sfabient * 7203790Sfabient * Portions of this software were developed by A. Joseph Koshy under 8203790Sfabient * sponsorship from the FreeBSD Foundation and Google, Inc. 9203790Sfabient * 10203790Sfabient * Redistribution and use in source and binary forms, with or without 11203790Sfabient * modification, are permitted provided that the following conditions 12203790Sfabient * are met: 13203790Sfabient * 1. Redistributions of source code must retain the above copyright 14203790Sfabient * notice, this list of conditions and the following disclaimer. 15203790Sfabient * 2. Redistributions in binary form must reproduce the above copyright 16203790Sfabient * notice, this list of conditions and the following disclaimer in the 17203790Sfabient * documentation and/or other materials provided with the distribution. 18203790Sfabient * 19203790Sfabient * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20203790Sfabient * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21203790Sfabient * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22203790Sfabient * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23203790Sfabient * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24203790Sfabient * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25203790Sfabient * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26203790Sfabient * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27203790Sfabient * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28203790Sfabient * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29203790Sfabient * SUCH DAMAGE. 30203790Sfabient */ 31203790Sfabient 32203790Sfabient/* 33203790Sfabient * Transform a hwpmc(4) log into human readable form, and into 34203790Sfabient * gprof(1) compatible profiles. 35203790Sfabient */ 36203790Sfabient 37203790Sfabient#include <sys/cdefs.h> 38203790Sfabient__FBSDID("$FreeBSD: stable/10/usr.sbin/pmcstat/pmcpl_gprof.c 322399 2017-08-11 11:38:04Z kib $"); 39203790Sfabient 40203790Sfabient#include <sys/param.h> 41203790Sfabient#include <sys/endian.h> 42203790Sfabient#include <sys/gmon.h> 43203790Sfabient#include <sys/imgact_aout.h> 44203790Sfabient#include <sys/imgact_elf.h> 45203790Sfabient#include <sys/mman.h> 46203790Sfabient#include <sys/pmc.h> 47203790Sfabient#include <sys/queue.h> 48203790Sfabient#include <sys/socket.h> 49203790Sfabient#include <sys/stat.h> 50203790Sfabient#include <sys/wait.h> 51203790Sfabient 52203790Sfabient#include <netinet/in.h> 53203790Sfabient 54203790Sfabient#include <assert.h> 55203790Sfabient#include <curses.h> 56203790Sfabient#include <err.h> 57203790Sfabient#include <errno.h> 58203790Sfabient#include <fcntl.h> 59203790Sfabient#include <gelf.h> 60203790Sfabient#include <libgen.h> 61203790Sfabient#include <limits.h> 62203790Sfabient#include <netdb.h> 63203790Sfabient#include <pmc.h> 64203790Sfabient#include <pmclog.h> 65203790Sfabient#include <sysexits.h> 66203790Sfabient#include <stdint.h> 67203790Sfabient#include <stdio.h> 68203790Sfabient#include <stdlib.h> 69203790Sfabient#include <string.h> 70203790Sfabient#include <unistd.h> 71203790Sfabient 72203790Sfabient#include "pmcstat.h" 73203790Sfabient#include "pmcstat_log.h" 74203790Sfabient#include "pmcpl_callgraph.h" 75203790Sfabient#include "pmcpl_gprof.h" 76203790Sfabient 77294046Sjtltypedef uint64_t WIDEHISTCOUNTER; 78294046Sjtl 79294046Sjtl#define WIDEHISTCOUNTER_MAX UINT64_MAX 80294046Sjtl#define HISTCOUNTER_MAX USHRT_MAX 81294046Sjtl#define WIDEHISTCOUNTER_GMONTYPE ((int) 64) 82294046Sjtl#define HISTCOUNTER_GMONTYPE ((int) 0) 83294046Sjtlstatic int hc_sz=0; 84294046Sjtl 85203790Sfabient/* 86203790Sfabient * struct pmcstat_gmonfile tracks a given 'gmon.out' file. These 87203790Sfabient * files are mmap()'ed in as needed. 88203790Sfabient */ 89203790Sfabient 90203790Sfabientstruct pmcstat_gmonfile { 91203790Sfabient LIST_ENTRY(pmcstat_gmonfile) pgf_next; /* list of entries */ 92203790Sfabient int pgf_overflow; /* whether a count overflowed */ 93203790Sfabient pmc_id_t pgf_pmcid; /* id of the associated pmc */ 94203790Sfabient size_t pgf_nbuckets; /* #buckets in this gmon.out */ 95203790Sfabient unsigned int pgf_nsamples; /* #samples in this gmon.out */ 96203790Sfabient pmcstat_interned_string pgf_name; /* pathname of gmon.out file */ 97203790Sfabient size_t pgf_ndatabytes; /* number of bytes mapped */ 98203790Sfabient void *pgf_gmondata; /* pointer to mmap'ed data */ 99203790Sfabient FILE *pgf_file; /* used when writing gmon arcs */ 100203790Sfabient}; 101203790Sfabient 102203790Sfabient/* 103203790Sfabient * Prototypes 104203790Sfabient */ 105203790Sfabient 106203790Sfabientstatic void pmcstat_gmon_create_file(struct pmcstat_gmonfile *_pgf, 107203790Sfabient struct pmcstat_image *_image); 108203790Sfabientstatic pmcstat_interned_string pmcstat_gmon_create_name(const char *_sd, 109203790Sfabient struct pmcstat_image *_img, pmc_id_t _pmcid); 110203790Sfabientstatic void pmcstat_gmon_map_file(struct pmcstat_gmonfile *_pgf); 111203790Sfabientstatic void pmcstat_gmon_unmap_file(struct pmcstat_gmonfile *_pgf); 112203790Sfabient 113203790Sfabientstatic struct pmcstat_gmonfile *pmcstat_image_find_gmonfile(struct 114203790Sfabient pmcstat_image *_i, pmc_id_t _id); 115203790Sfabient 116203790Sfabient/* 117203790Sfabient * Create a gmon.out file and size it. 118203790Sfabient */ 119203790Sfabient 120203790Sfabientstatic void 121203790Sfabientpmcstat_gmon_create_file(struct pmcstat_gmonfile *pgf, 122203790Sfabient struct pmcstat_image *image) 123203790Sfabient{ 124203790Sfabient int fd; 125203790Sfabient size_t count; 126203790Sfabient struct gmonhdr gm; 127203790Sfabient const char *pathname; 128203790Sfabient char buffer[DEFAULT_BUFFER_SIZE]; 129203790Sfabient 130203790Sfabient pathname = pmcstat_string_unintern(pgf->pgf_name); 131203790Sfabient if ((fd = open(pathname, O_RDWR|O_NOFOLLOW|O_CREAT, 132203790Sfabient S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) 133203790Sfabient err(EX_OSERR, "ERROR: Cannot open \"%s\"", pathname); 134203790Sfabient 135203790Sfabient gm.lpc = image->pi_start; 136203790Sfabient gm.hpc = image->pi_end; 137294046Sjtl gm.ncnt = (pgf->pgf_nbuckets * hc_sz) + sizeof(struct gmonhdr); 138203790Sfabient gm.version = GMONVERSION; 139203790Sfabient gm.profrate = 0; /* use ticks */ 140294046Sjtl if (args.pa_flags & FLAG_DO_WIDE_GPROF_HC) 141294046Sjtl gm.histcounter_type = WIDEHISTCOUNTER_GMONTYPE; 142294046Sjtl else 143294046Sjtl gm.histcounter_type = HISTCOUNTER_GMONTYPE; 144203790Sfabient gm.spare[0] = gm.spare[1] = 0; 145203790Sfabient 146203790Sfabient /* Write out the gmon header */ 147203790Sfabient if (write(fd, &gm, sizeof(gm)) < 0) 148203790Sfabient goto error; 149203790Sfabient 150203790Sfabient /* Zero fill the samples[] array */ 151203790Sfabient (void) memset(buffer, 0, sizeof(buffer)); 152203790Sfabient 153203790Sfabient count = pgf->pgf_ndatabytes - sizeof(struct gmonhdr); 154203790Sfabient while (count > sizeof(buffer)) { 155203790Sfabient if (write(fd, &buffer, sizeof(buffer)) < 0) 156203790Sfabient goto error; 157203790Sfabient count -= sizeof(buffer); 158203790Sfabient } 159203790Sfabient 160203790Sfabient if (write(fd, &buffer, count) < 0) 161203790Sfabient goto error; 162203790Sfabient 163203790Sfabient (void) close(fd); 164203790Sfabient 165203790Sfabient return; 166203790Sfabient 167203790Sfabient error: 168203790Sfabient err(EX_OSERR, "ERROR: Cannot write \"%s\"", pathname); 169203790Sfabient} 170203790Sfabient 171203790Sfabient/* 172203790Sfabient * Determine the full pathname of a gmon.out file for a given 173203790Sfabient * (image,pmcid) combination. Return the interned string. 174203790Sfabient */ 175203790Sfabient 176203790Sfabientpmcstat_interned_string 177203790Sfabientpmcstat_gmon_create_name(const char *samplesdir, struct pmcstat_image *image, 178203790Sfabient pmc_id_t pmcid) 179203790Sfabient{ 180203790Sfabient const char *pmcname; 181203790Sfabient char fullpath[PATH_MAX]; 182203790Sfabient 183203790Sfabient pmcname = pmcstat_pmcid_to_name(pmcid); 184206635Sfabient if (!pmcname) 185206635Sfabient err(EX_SOFTWARE, "ERROR: cannot find pmcid"); 186203790Sfabient 187203790Sfabient (void) snprintf(fullpath, sizeof(fullpath), 188203790Sfabient "%s/%s/%s", samplesdir, pmcname, 189203790Sfabient pmcstat_string_unintern(image->pi_samplename)); 190203790Sfabient 191203790Sfabient return (pmcstat_string_intern(fullpath)); 192203790Sfabient} 193203790Sfabient 194203790Sfabient 195203790Sfabient/* 196203790Sfabient * Mmap in a gmon.out file for processing. 197203790Sfabient */ 198203790Sfabient 199203790Sfabientstatic void 200203790Sfabientpmcstat_gmon_map_file(struct pmcstat_gmonfile *pgf) 201203790Sfabient{ 202203790Sfabient int fd; 203203790Sfabient const char *pathname; 204203790Sfabient 205203790Sfabient pathname = pmcstat_string_unintern(pgf->pgf_name); 206203790Sfabient 207203790Sfabient /* the gmon.out file must already exist */ 208203790Sfabient if ((fd = open(pathname, O_RDWR | O_NOFOLLOW, 0)) < 0) 209203790Sfabient err(EX_OSERR, "ERROR: cannot open \"%s\"", pathname); 210203790Sfabient 211203790Sfabient pgf->pgf_gmondata = mmap(NULL, pgf->pgf_ndatabytes, 212203790Sfabient PROT_READ|PROT_WRITE, MAP_NOSYNC|MAP_SHARED, fd, 0); 213203790Sfabient 214203790Sfabient if (pgf->pgf_gmondata == MAP_FAILED) 215203790Sfabient err(EX_OSERR, "ERROR: cannot map \"%s\"", pathname); 216203790Sfabient 217203790Sfabient (void) close(fd); 218203790Sfabient} 219203790Sfabient 220203790Sfabient/* 221203790Sfabient * Unmap a gmon.out file after sync'ing its data to disk. 222203790Sfabient */ 223203790Sfabient 224203790Sfabientstatic void 225203790Sfabientpmcstat_gmon_unmap_file(struct pmcstat_gmonfile *pgf) 226203790Sfabient{ 227203790Sfabient (void) msync(pgf->pgf_gmondata, pgf->pgf_ndatabytes, 228203790Sfabient MS_SYNC); 229203790Sfabient (void) munmap(pgf->pgf_gmondata, pgf->pgf_ndatabytes); 230203790Sfabient pgf->pgf_gmondata = NULL; 231203790Sfabient} 232203790Sfabient 233203790Sfabientstatic void 234203790Sfabientpmcstat_gmon_append_arc(struct pmcstat_image *image, pmc_id_t pmcid, 235203790Sfabient uintptr_t rawfrom, uintptr_t rawto, uint32_t count) 236203790Sfabient{ 237203790Sfabient struct rawarc arc; /* from <sys/gmon.h> */ 238203790Sfabient const char *pathname; 239203790Sfabient struct pmcstat_gmonfile *pgf; 240203790Sfabient 241203790Sfabient if ((pgf = pmcstat_image_find_gmonfile(image, pmcid)) == NULL) 242203790Sfabient return; 243203790Sfabient 244203790Sfabient if (pgf->pgf_file == NULL) { 245203790Sfabient pathname = pmcstat_string_unintern(pgf->pgf_name); 246203790Sfabient if ((pgf->pgf_file = fopen(pathname, "a")) == NULL) 247203790Sfabient return; 248203790Sfabient } 249203790Sfabient 250203790Sfabient arc.raw_frompc = rawfrom + image->pi_vaddr; 251203790Sfabient arc.raw_selfpc = rawto + image->pi_vaddr; 252203790Sfabient arc.raw_count = count; 253203790Sfabient 254203790Sfabient (void) fwrite(&arc, sizeof(arc), 1, pgf->pgf_file); 255203790Sfabient 256203790Sfabient} 257203790Sfabient 258203790Sfabientstatic struct pmcstat_gmonfile * 259203790Sfabientpmcstat_image_find_gmonfile(struct pmcstat_image *image, pmc_id_t pmcid) 260203790Sfabient{ 261203790Sfabient struct pmcstat_gmonfile *pgf; 262203790Sfabient LIST_FOREACH(pgf, &image->pi_gmlist, pgf_next) 263203790Sfabient if (pgf->pgf_pmcid == pmcid) 264203790Sfabient return (pgf); 265203790Sfabient return (NULL); 266203790Sfabient} 267203790Sfabient 268203790Sfabientstatic void 269203790Sfabientpmcstat_cgnode_do_gmon_arcs(struct pmcstat_cgnode *cg, pmc_id_t pmcid) 270203790Sfabient{ 271203790Sfabient struct pmcstat_cgnode *cgc; 272203790Sfabient 273203790Sfabient /* 274203790Sfabient * Look for child nodes that belong to the same image. 275203790Sfabient */ 276203790Sfabient 277203790Sfabient LIST_FOREACH(cgc, &cg->pcg_children, pcg_sibling) { 278203790Sfabient if (cgc->pcg_image == cg->pcg_image) 279203790Sfabient pmcstat_gmon_append_arc(cg->pcg_image, pmcid, 280203790Sfabient cgc->pcg_func, cg->pcg_func, cgc->pcg_count); 281203790Sfabient if (cgc->pcg_nchildren > 0) 282203790Sfabient pmcstat_cgnode_do_gmon_arcs(cgc, pmcid); 283203790Sfabient } 284203790Sfabient} 285203790Sfabient 286203790Sfabientstatic void 287203790Sfabientpmcstat_callgraph_do_gmon_arcs_for_pmcid(pmc_id_t pmcid) 288203790Sfabient{ 289203790Sfabient int n; 290203790Sfabient struct pmcstat_cgnode_hash *pch; 291203790Sfabient 292203790Sfabient for (n = 0; n < PMCSTAT_NHASH; n++) 293203790Sfabient LIST_FOREACH(pch, &pmcstat_cgnode_hash[n], pch_next) 294203790Sfabient if (pch->pch_pmcid == pmcid && 295203790Sfabient pch->pch_cgnode->pcg_nchildren > 1) 296203790Sfabient pmcstat_cgnode_do_gmon_arcs(pch->pch_cgnode, 297203790Sfabient pmcid); 298203790Sfabient} 299203790Sfabient 300203790Sfabient 301203790Sfabientstatic void 302203790Sfabientpmcstat_callgraph_do_gmon_arcs(void) 303203790Sfabient{ 304203790Sfabient struct pmcstat_pmcrecord *pmcr; 305203790Sfabient 306203790Sfabient LIST_FOREACH(pmcr, &pmcstat_pmcs, pr_next) 307203790Sfabient pmcstat_callgraph_do_gmon_arcs_for_pmcid(pmcr->pr_pmcid); 308203790Sfabient} 309203790Sfabient 310203790Sfabientvoid 311203790Sfabientpmcpl_gmon_initimage(struct pmcstat_image *pi) 312203790Sfabient{ 313203790Sfabient int count, nlen; 314203790Sfabient char *sn; 315203790Sfabient char name[NAME_MAX]; 316203790Sfabient 317203790Sfabient /* 318203790Sfabient * Look for a suitable name for the sample files associated 319203790Sfabient * with this image: if `basename(path)`+".gmon" is available, 320203790Sfabient * we use that, otherwise we try iterating through 321203790Sfabient * `basename(path)`+ "~" + NNN + ".gmon" till we get a free 322203790Sfabient * entry. 323203790Sfabient */ 324203790Sfabient if ((sn = basename(pmcstat_string_unintern(pi->pi_execpath))) == NULL) 325203790Sfabient err(EX_OSERR, "ERROR: Cannot process \"%s\"", 326203790Sfabient pmcstat_string_unintern(pi->pi_execpath)); 327203790Sfabient 328203790Sfabient nlen = strlen(sn); 329203790Sfabient nlen = min(nlen, (int) (sizeof(name) - sizeof(".gmon"))); 330203790Sfabient 331203790Sfabient snprintf(name, sizeof(name), "%.*s.gmon", nlen, sn); 332203790Sfabient 333203790Sfabient /* try use the unabridged name first */ 334203790Sfabient if (pmcstat_string_lookup(name) == NULL) 335203790Sfabient pi->pi_samplename = pmcstat_string_intern(name); 336203790Sfabient else { 337203790Sfabient /* 338203790Sfabient * Otherwise use a prefix from the original name and 339228990Suqs * up to 3 digits. 340203790Sfabient */ 341203790Sfabient nlen = strlen(sn); 342203790Sfabient nlen = min(nlen, (int) (sizeof(name)-sizeof("~NNN.gmon"))); 343203790Sfabient count = 0; 344203790Sfabient do { 345203790Sfabient if (++count > 999) 346227524Sobrien errx(EX_CANTCREAT, 347227524Sobrien "ERROR: cannot create a gmon file for" 348227524Sobrien " \"%s\"", name); 349203790Sfabient snprintf(name, sizeof(name), "%.*s~%3.3d.gmon", 350203790Sfabient nlen, sn, count); 351203790Sfabient if (pmcstat_string_lookup(name) == NULL) { 352203790Sfabient pi->pi_samplename = 353203790Sfabient pmcstat_string_intern(name); 354203790Sfabient count = 0; 355203790Sfabient } 356203790Sfabient } while (count > 0); 357203790Sfabient } 358203790Sfabient 359203790Sfabient LIST_INIT(&pi->pi_gmlist); 360203790Sfabient} 361203790Sfabient 362203790Sfabientvoid 363203790Sfabientpmcpl_gmon_shutdownimage(struct pmcstat_image *pi) 364203790Sfabient{ 365203790Sfabient struct pmcstat_gmonfile *pgf, *pgftmp; 366203790Sfabient 367203790Sfabient LIST_FOREACH_SAFE(pgf, &pi->pi_gmlist, pgf_next, pgftmp) { 368203790Sfabient if (pgf->pgf_file) 369203790Sfabient (void) fclose(pgf->pgf_file); 370203790Sfabient LIST_REMOVE(pgf, pgf_next); 371203790Sfabient free(pgf); 372203790Sfabient } 373203790Sfabient} 374203790Sfabient 375203790Sfabientvoid 376203790Sfabientpmcpl_gmon_newpmc(pmcstat_interned_string ps, struct pmcstat_pmcrecord *pr) 377203790Sfabient{ 378203790Sfabient struct stat st; 379203790Sfabient char fullpath[PATH_MAX]; 380203790Sfabient 381203790Sfabient (void) pr; 382203790Sfabient 383203790Sfabient /* 384203790Sfabient * Create the appropriate directory to hold gmon.out files. 385203790Sfabient */ 386203790Sfabient 387203790Sfabient (void) snprintf(fullpath, sizeof(fullpath), "%s/%s", args.pa_samplesdir, 388203790Sfabient pmcstat_string_unintern(ps)); 389203790Sfabient 390203790Sfabient /* If the path name exists, it should be a directory */ 391203790Sfabient if (stat(fullpath, &st) == 0 && S_ISDIR(st.st_mode)) 392203790Sfabient return; 393203790Sfabient 394203790Sfabient if (mkdir(fullpath, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) < 0) 395203790Sfabient err(EX_OSERR, "ERROR: Cannot create directory \"%s\"", 396203790Sfabient fullpath); 397203790Sfabient} 398203790Sfabient 399203790Sfabient/* 400203790Sfabient * Increment the bucket in the gmon.out file corresponding to 'pmcid' 401203790Sfabient * and 'pc'. 402203790Sfabient */ 403203790Sfabient 404203790Sfabientvoid 405203790Sfabientpmcpl_gmon_process(struct pmcstat_process *pp, struct pmcstat_pmcrecord *pmcr, 406203790Sfabient uint32_t nsamples, uintfptr_t *cc, int usermode, uint32_t cpu) 407203790Sfabient{ 408203790Sfabient struct pmcstat_pcmap *map; 409203790Sfabient struct pmcstat_image *image; 410203790Sfabient struct pmcstat_gmonfile *pgf; 411203790Sfabient uintfptr_t bucket; 412203790Sfabient HISTCOUNTER *hc; 413294046Sjtl WIDEHISTCOUNTER *whc; 414203790Sfabient pmc_id_t pmcid; 415203790Sfabient 416203790Sfabient (void) nsamples; (void) usermode; (void) cpu; 417203790Sfabient 418203790Sfabient map = pmcstat_process_find_map(usermode ? pp : pmcstat_kernproc, cc[0]); 419203790Sfabient if (map == NULL) { 420203790Sfabient /* Unknown offset. */ 421203790Sfabient pmcstat_stats.ps_samples_unknown_offset++; 422203790Sfabient return; 423203790Sfabient } 424203790Sfabient 425203790Sfabient assert(cc[0] >= map->ppm_lowpc && cc[0] < map->ppm_highpc); 426203790Sfabient 427203790Sfabient image = map->ppm_image; 428203790Sfabient pmcid = pmcr->pr_pmcid; 429203790Sfabient 430203790Sfabient /* 431203790Sfabient * If this is the first time we are seeing a sample for 432203790Sfabient * this executable image, try determine its parameters. 433203790Sfabient */ 434203790Sfabient if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) 435203790Sfabient pmcstat_image_determine_type(image); 436203790Sfabient 437203790Sfabient assert(image->pi_type != PMCSTAT_IMAGE_UNKNOWN); 438203790Sfabient 439203790Sfabient /* Ignore samples in images that we know nothing about. */ 440203790Sfabient if (image->pi_type == PMCSTAT_IMAGE_INDETERMINABLE) { 441203790Sfabient pmcstat_stats.ps_samples_indeterminable++; 442203790Sfabient return; 443203790Sfabient } 444203790Sfabient 445203790Sfabient /* 446203790Sfabient * Find the gmon file corresponding to 'pmcid', creating it if 447203790Sfabient * needed. 448203790Sfabient */ 449203790Sfabient pgf = pmcstat_image_find_gmonfile(image, pmcid); 450203790Sfabient if (pgf == NULL) { 451294046Sjtl if (hc_sz == 0) { 452294046Sjtl /* Determine the correct histcounter size. */ 453294046Sjtl if (args.pa_flags & FLAG_DO_WIDE_GPROF_HC) 454294046Sjtl hc_sz = sizeof(WIDEHISTCOUNTER); 455294046Sjtl else 456294046Sjtl hc_sz = sizeof(HISTCOUNTER); 457294046Sjtl } 458294046Sjtl 459203790Sfabient if ((pgf = calloc(1, sizeof(*pgf))) == NULL) 460203790Sfabient err(EX_OSERR, "ERROR:"); 461203790Sfabient 462203790Sfabient pgf->pgf_gmondata = NULL; /* mark as unmapped */ 463203790Sfabient pgf->pgf_name = pmcstat_gmon_create_name(args.pa_samplesdir, 464203790Sfabient image, pmcid); 465203790Sfabient pgf->pgf_pmcid = pmcid; 466203790Sfabient assert(image->pi_end > image->pi_start); 467322399Skib pgf->pgf_nbuckets = howmany(image->pi_end - image->pi_start, 468322399Skib FUNCTION_ALIGNMENT); /* see <machine/profile.h> */ 469203790Sfabient pgf->pgf_ndatabytes = sizeof(struct gmonhdr) + 470294046Sjtl pgf->pgf_nbuckets * hc_sz; 471203790Sfabient pgf->pgf_nsamples = 0; 472203790Sfabient pgf->pgf_file = NULL; 473203790Sfabient 474203790Sfabient pmcstat_gmon_create_file(pgf, image); 475203790Sfabient 476203790Sfabient LIST_INSERT_HEAD(&image->pi_gmlist, pgf, pgf_next); 477203790Sfabient } 478203790Sfabient 479203790Sfabient /* 480203790Sfabient * Map the gmon file in if needed. It may have been mapped 481203790Sfabient * out under memory pressure. 482203790Sfabient */ 483203790Sfabient if (pgf->pgf_gmondata == NULL) 484203790Sfabient pmcstat_gmon_map_file(pgf); 485203790Sfabient 486203790Sfabient assert(pgf->pgf_gmondata != NULL); 487203790Sfabient 488203790Sfabient /* 489203790Sfabient * 490203790Sfabient */ 491203790Sfabient 492203790Sfabient bucket = (cc[0] - map->ppm_lowpc) / FUNCTION_ALIGNMENT; 493203790Sfabient 494203790Sfabient assert(bucket < pgf->pgf_nbuckets); 495203790Sfabient 496294046Sjtl if (args.pa_flags & FLAG_DO_WIDE_GPROF_HC) { 497294046Sjtl whc = (WIDEHISTCOUNTER *) ((uintptr_t) pgf->pgf_gmondata + 498294046Sjtl sizeof(struct gmonhdr)); 499203790Sfabient 500294046Sjtl /* saturating add */ 501294046Sjtl if (whc[bucket] < WIDEHISTCOUNTER_MAX) 502294046Sjtl whc[bucket]++; 503294046Sjtl else /* mark that an overflow occurred */ 504294046Sjtl pgf->pgf_overflow = 1; 505294046Sjtl } else { 506294046Sjtl hc = (HISTCOUNTER *) ((uintptr_t) pgf->pgf_gmondata + 507294046Sjtl sizeof(struct gmonhdr)); 508203790Sfabient 509294046Sjtl /* saturating add */ 510294046Sjtl if (hc[bucket] < HISTCOUNTER_MAX) 511294046Sjtl hc[bucket]++; 512294046Sjtl else /* mark that an overflow occurred */ 513294046Sjtl pgf->pgf_overflow = 1; 514294046Sjtl } 515294046Sjtl 516203790Sfabient pgf->pgf_nsamples++; 517203790Sfabient} 518203790Sfabient 519203790Sfabient/* 520203790Sfabient * Shutdown module. 521203790Sfabient */ 522203790Sfabient 523203790Sfabientvoid 524203790Sfabientpmcpl_gmon_shutdown(FILE *mf) 525203790Sfabient{ 526203790Sfabient int i; 527203790Sfabient struct pmcstat_gmonfile *pgf; 528203790Sfabient struct pmcstat_image *pi; 529203790Sfabient 530203790Sfabient /* 531203790Sfabient * Sync back all gprof flat profile data. 532203790Sfabient */ 533203790Sfabient for (i = 0; i < PMCSTAT_NHASH; i++) { 534203790Sfabient LIST_FOREACH(pi, &pmcstat_image_hash[i], pi_next) { 535203790Sfabient if (mf) 536203790Sfabient (void) fprintf(mf, " \"%s\" => \"%s\"", 537203790Sfabient pmcstat_string_unintern(pi->pi_execpath), 538203790Sfabient pmcstat_string_unintern( 539203790Sfabient pi->pi_samplename)); 540203790Sfabient 541203790Sfabient /* flush gmon.out data to disk */ 542203790Sfabient LIST_FOREACH(pgf, &pi->pi_gmlist, pgf_next) { 543203790Sfabient pmcstat_gmon_unmap_file(pgf); 544203790Sfabient if (mf) 545203790Sfabient (void) fprintf(mf, " %s/%d", 546203790Sfabient pmcstat_pmcid_to_name( 547203790Sfabient pgf->pgf_pmcid), 548203790Sfabient pgf->pgf_nsamples); 549203790Sfabient if (pgf->pgf_overflow && args.pa_verbosity >= 1) 550227524Sobrien warnx( 551227524Sobrien"WARNING: profile \"%s\" overflowed.", 552203790Sfabient pmcstat_string_unintern( 553203790Sfabient pgf->pgf_name)); 554203790Sfabient } 555203790Sfabient 556203790Sfabient if (mf) 557203790Sfabient (void) fprintf(mf, "\n"); 558203790Sfabient } 559203790Sfabient } 560203790Sfabient 561203790Sfabient /* 562203790Sfabient * Compute arcs and add these to the gprof files. 563203790Sfabient */ 564203790Sfabient if (args.pa_flags & FLAG_DO_GPROF && args.pa_graphdepth > 1) 565203790Sfabient pmcstat_callgraph_do_gmon_arcs(); 566203790Sfabient} 567