1 /*- 2 * Copyright (c) 2005, Joseph Koshy 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 /* 31 * Transform a hwpmc(4) log into human readable form and into gprof(1) 32 * compatible profiles. 33 * 34 * Each executable object encountered in the log gets one 'gmon.out' 35 * profile per PMC. We currently track: 36 * - program executables 37 * - shared libraries loaded by the runtime loader 38 * - the runtime loader itself 39 * - the kernel. 40 * We do not track shared objects mapped in by dlopen() yet (this 41 * needs additional support from hwpmc(4)). 42 * 43 * 'gmon.out' profiles generated for a given sampling PMC are 44 * aggregates of all the samples for that particular executable 45 * object. 46 */ 47 48 #include <sys/param.h> 49 #include <sys/endian.h> 50 #include <sys/gmon.h> 51 #include <sys/imgact_aout.h> 52 #include <sys/imgact_elf.h> 53 #include <sys/mman.h> 54 #include <sys/pmc.h> 55 #include <sys/queue.h> 56 #include <sys/stat.h> 57 #include <sys/wait.h> 58 59 #include <netinet/in.h> 60 61 #include <assert.h> 62 #include <err.h> 63 #include <fcntl.h> 64 #include <libgen.h> 65 #include <limits.h> 66 #include <pmc.h> 67 #include <pmclog.h> 68 #include <sysexits.h> 69 #include <stdint.h> 70 #include <stdio.h> 71 #include <stdlib.h> 72 #include <string.h> 73 #include <unistd.h> 74 75 #include "pmcstat.h" 76 77 #define min(A,B) ((A) < (B) ? (A) : (B)) 78 #define max(A,B) ((A) > (B) ? (A) : (B)) 79 80 /* 81 * A simple implementation of interned strings. Each interned string 82 * is assigned a unique address, so that subsequent string compares 83 * can be done by a simple pointer comparision instead of with 84 * strcmp(). 85 */ 86 struct pmcstat_string { 87 LIST_ENTRY(pmcstat_string) ps_next; /* hash link */ 88 int ps_len; 89 int ps_hash; 90 const char *ps_string; 91 }; 92 93 static LIST_HEAD(,pmcstat_string) pmcstat_string_hash[PMCSTAT_NHASH]; 94 95 /* 96 * 'pmcstat_pmcrecord' is a mapping from PMC ids to human-readable 97 * names. 98 */ 99 100 struct pmcstat_pmcrecord { 101 LIST_ENTRY(pmcstat_pmcrecord) pr_next; 102 pmc_id_t pr_pmcid; 103 const char *pr_pmcname; 104 }; 105 106 static LIST_HEAD(,pmcstat_pmcrecord) pmcstat_pmcs = 107 LIST_HEAD_INITIALIZER(&pmcstat_pmcs); 108 109 110 /* 111 * struct pmcstat_gmonfile tracks a given 'gmon.out' file. These 112 * files are mmap()'ed in as needed. 113 */ 114 115 struct pmcstat_gmonfile { 116 LIST_ENTRY(pmcstat_gmonfile) pgf_next; /* list of entries */ 117 pmc_id_t pgf_pmcid; /* id of the associated pmc */ 118 size_t pgf_nbuckets; /* #buckets in this gmon.out */ 119 const char *pgf_name; /* pathname of gmon.out file */ 120 size_t pgf_ndatabytes; /* number of bytes mapped */ 121 void *pgf_gmondata; /* pointer to mmap'ed data */ 122 }; 123 124 static TAILQ_HEAD(,pmcstat_gmonfile) pmcstat_gmonfiles = 125 TAILQ_HEAD_INITIALIZER(pmcstat_gmonfiles); 126 127 /* 128 * A 'pmcstat_image' structure describes an executable program on 129 * disk. 'pi_internedpath' is a cookie representing the pathname of 130 * the executable. 'pi_start' and 'pi_end' are the least and greatest 131 * virtual addresses for the text segments in the executable. 132 * 'pi_gmonlist' contains a linked list of gmon.out files associated 133 * with this image. 134 */ 135 136 enum pmcstat_image_type { 137 PMCSTAT_IMAGE_UNKNOWN = 0, 138 PMCSTAT_IMAGE_ELF, 139 PMCSTAT_IMAGE_AOUT 140 }; 141 142 struct pmcstat_image { 143 LIST_ENTRY(pmcstat_image) pi_next; /* hash link */ 144 TAILQ_ENTRY(pmcstat_image) pi_lru; /* LRU list */ 145 const char *pi_internedpath; /* cookie */ 146 const char *pi_samplename; /* sample path name */ 147 148 enum pmcstat_image_type pi_type; /* executable type */ 149 uintfptr_t pi_start; /* start address (inclusive) */ 150 uintfptr_t pi_end; /* end address (exclusive) */ 151 uintfptr_t pi_entry; /* entry address */ 152 int pi_isdynamic; /* whether a dynamic object */ 153 const char *pi_dynlinkerpath; /* path in .interp section */ 154 155 LIST_HEAD(,pmcstat_gmonfile) pi_gmlist; 156 }; 157 158 static LIST_HEAD(,pmcstat_image) pmcstat_image_hash[PMCSTAT_NHASH]; 159 static TAILQ_HEAD(,pmcstat_image) pmcstat_image_lru = 160 TAILQ_HEAD_INITIALIZER(pmcstat_image_lru); 161 162 struct pmcstat_pcmap { 163 TAILQ_ENTRY(pmcstat_pcmap) ppm_next; 164 uintfptr_t ppm_lowpc; 165 uintfptr_t ppm_highpc; 166 struct pmcstat_image *ppm_image; 167 }; 168 169 /* 170 * A 'pmcstat_process' structure tracks processes. 171 */ 172 173 struct pmcstat_process { 174 LIST_ENTRY(pmcstat_process) pp_next; /* hash-next */ 175 pid_t pp_pid; /* associated pid */ 176 int pp_isactive; /* whether active */ 177 uintfptr_t pp_entryaddr; /* entry address */ 178 TAILQ_HEAD(,pmcstat_pcmap) pp_map; /* address range map */ 179 }; 180 181 static LIST_HEAD(,pmcstat_process) pmcstat_process_hash[PMCSTAT_NHASH]; 182 183 static struct pmcstat_process *pmcstat_kernproc; /* kernel 'process' */ 184 185 /* 186 * Prototypes 187 */ 188 189 static void pmcstat_gmon_create_file(struct pmcstat_gmonfile *_pgf, 190 struct pmcstat_image *_image); 191 static const char *pmcstat_gmon_create_name(const char *_sd, 192 struct pmcstat_image *_img, pmc_id_t _pmcid); 193 static void pmcstat_gmon_map_file(struct pmcstat_gmonfile *_pgf); 194 static void pmcstat_gmon_unmap_file(struct pmcstat_gmonfile *_pgf); 195 196 static struct pmcstat_image *pmcstat_image_from_path(const char *_path); 197 static enum pmcstat_image_type pmcstat_image_get_type(const char *_p); 198 static void pmcstat_image_get_elf_params(struct pmcstat_image *_image); 199 static void pmcstat_image_increment_bucket(struct pmcstat_pcmap *_pcm, 200 uintfptr_t _pc, pmc_id_t _pmcid, struct pmcstat_args *_a); 201 static void pmcstat_image_link(struct pmcstat_process *_pp, 202 struct pmcstat_image *_i, uintfptr_t _lpc, uintfptr_t _hpc); 203 204 static void pmcstat_pmcid_add(pmc_id_t _pmcid, const char *_name, 205 struct pmcstat_args *_a); 206 static const char *pmcstat_pmcid_to_name(pmc_id_t _pmcid); 207 208 static void pmcstat_process_add_elf_image(struct pmcstat_process *_pp, 209 const char *_path, uintfptr_t _entryaddr); 210 static void pmcstat_process_exec(struct pmcstat_process *_pp, 211 const char *_path, uintfptr_t _entryaddr); 212 static struct pmcstat_process *pmcstat_process_lookup(pid_t _pid, int _allocate); 213 static struct pmcstat_pcmap *pmcstat_process_find_map( 214 struct pmcstat_process *_p, uintfptr_t _pc); 215 216 static int pmcstat_string_compute_hash(const char *_string); 217 static const char *pmcstat_string_intern(const char *_s); 218 static struct pmcstat_string *pmcstat_string_lookup(const char *_s); 219 220 221 /* 222 * Create a gmon.out file and size it. 223 */ 224 225 static void 226 pmcstat_gmon_create_file(struct pmcstat_gmonfile *pgf, 227 struct pmcstat_image *image) 228 { 229 int fd; 230 size_t count; 231 struct gmonhdr gm; 232 char buffer[DEFAULT_BUFFER_SIZE]; 233 234 if ((fd = open(pgf->pgf_name, O_RDWR|O_NOFOLLOW|O_CREAT, 235 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) 236 err(EX_OSERR, "ERROR: Cannot open \"%s\"", pgf->pgf_name); 237 238 gm.lpc = image->pi_start; 239 gm.hpc = image->pi_end; 240 gm.ncnt = (pgf->pgf_nbuckets * sizeof(HISTCOUNTER)) + 241 sizeof(struct gmonhdr); 242 gm.version = GMONVERSION; 243 gm.profrate = 0; /* use ticks */ 244 gm.histcounter_type = 0; /* compatibility with moncontrol() */ 245 gm.spare[0] = gm.spare[1] = 0; 246 247 /* Write out the gmon header */ 248 if (write(fd, &gm, sizeof(gm)) < 0) 249 goto error; 250 251 /* Zero fill the samples[] array */ 252 (void) memset(buffer, 0, sizeof(buffer)); 253 254 count = pgf->pgf_ndatabytes - sizeof(struct gmonhdr); 255 while (count > sizeof(buffer)) { 256 if (write(fd, &buffer, sizeof(buffer)) < 0) 257 goto error; 258 count -= sizeof(buffer); 259 } 260 261 if (write(fd, &buffer, count) < 0) 262 goto error; 263 264 (void) close(fd); 265 266 return; 267 268 error: 269 err(EX_OSERR, "ERROR: Cannot write \"%s\"", pgf->pgf_name); 270 } 271 272 const char * 273 pmcstat_gmon_create_name(const char *samplesdir, struct pmcstat_image *image, 274 pmc_id_t pmcid) 275 { 276 const char *pmcname; 277 char fullpath[PATH_MAX]; 278 279 pmcname = pmcstat_pmcid_to_name(pmcid); 280 281 (void) snprintf(fullpath, sizeof(fullpath), 282 "%s/%s/%s", samplesdir, pmcname, image->pi_samplename); 283 284 return pmcstat_string_intern(fullpath); 285 } 286 287 288 static void 289 pmcstat_gmon_map_file(struct pmcstat_gmonfile *pgf) 290 { 291 int fd; 292 293 /* the gmon.out file must already exist */ 294 if ((fd = open(pgf->pgf_name, O_RDWR | O_NOFOLLOW, 0)) < 0) 295 err(EX_OSERR, "ERROR: cannot open \"%s\"", 296 pgf->pgf_name); 297 298 pgf->pgf_gmondata = mmap(NULL, pgf->pgf_ndatabytes, 299 PROT_READ|PROT_WRITE, MAP_NOSYNC|MAP_SHARED, fd, 0); 300 301 if (pgf->pgf_gmondata == MAP_FAILED) 302 /* XXX unmap a few files and try again? */ 303 err(EX_OSERR, "ERROR: cannot map \"%s\"", pgf->pgf_name); 304 305 (void) close(fd); 306 } 307 308 /* 309 * Unmap the data mapped from a gmon.out file. 310 */ 311 312 static void 313 pmcstat_gmon_unmap_file(struct pmcstat_gmonfile *pgf) 314 { 315 (void) msync(pgf->pgf_gmondata, pgf->pgf_ndatabytes, 316 MS_SYNC); 317 (void) munmap(pgf->pgf_gmondata, pgf->pgf_ndatabytes); 318 pgf->pgf_gmondata = NULL; 319 } 320 321 static void 322 pmcstat_image_get_elf_params(struct pmcstat_image *image) 323 { 324 int fd, i; 325 struct stat st; 326 void *mapbase; 327 uintfptr_t minva, maxva; 328 const Elf_Ehdr *h; 329 const Elf_Phdr *ph; 330 const Elf_Shdr *sh; 331 const char *path; 332 333 assert(image->pi_type == PMCSTAT_IMAGE_UNKNOWN); 334 335 minva = ~(uintfptr_t) 0; 336 maxva = (uintfptr_t) 0; 337 path = image->pi_internedpath; 338 339 if ((fd = open(path, O_RDONLY, 0)) < 0) 340 err(EX_OSERR, "ERROR: Cannot open \"%s\"", path); 341 342 if (fstat(fd, &st) < 0) 343 err(EX_OSERR, "ERROR: Cannot stat \"%s\"", path); 344 345 if ((mapbase = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == 346 MAP_FAILED) 347 err(EX_OSERR, "ERROR: Cannot mmap \"%s\"", path); 348 349 (void) close(fd); 350 351 h = (const Elf_Ehdr *) mapbase; 352 if (!IS_ELF(*h)) 353 err(EX_SOFTWARE, "ERROR: \"%s\" not an ELF file", path); 354 355 sh = (const Elf_Shdr *)((uintptr_t) mapbase + h->e_shoff); 356 357 if (h->e_type == ET_EXEC || h->e_type == ET_DYN) { 358 /* 359 * Some kind of executable object: find the min,max va 360 * for its executable sections. 361 */ 362 for (i = 0; i < h->e_shnum; i++) 363 if (sh[i].sh_flags & SHF_EXECINSTR) { /* code */ 364 minva = min(minva, sh[i].sh_addr); 365 maxva = max(maxva, sh[i].sh_addr + 366 sh[i].sh_size); 367 } 368 } else 369 err(EX_DATAERR, "ERROR: Unknown file type for \"%s\"", 370 image->pi_internedpath); 371 372 image->pi_type = PMCSTAT_IMAGE_ELF; 373 image->pi_start = minva; 374 image->pi_entry = h->e_entry; 375 image->pi_end = maxva; 376 image->pi_isdynamic = 0; 377 image->pi_dynlinkerpath = NULL; 378 379 380 if (h->e_type == ET_EXEC) { 381 ph = (const Elf_Phdr *)((uintptr_t) mapbase + h->e_phoff); 382 for (i = 0; i < h->e_phnum; i++) { 383 switch (ph[i].p_type) { 384 case PT_DYNAMIC: 385 image->pi_isdynamic = 1; 386 break; 387 case PT_INTERP: 388 image->pi_dynlinkerpath = 389 pmcstat_string_intern((char *) mapbase + 390 ph[i].p_offset); 391 break; 392 } 393 } 394 } 395 396 if (munmap(mapbase, st.st_size) < 0) 397 err(EX_OSERR, "ERROR: Cannot unmap \"%s\"", path); 398 399 } 400 401 /* 402 * Locate an image descriptor given an interned path, adding a fresh 403 * descriptor to the cache if necessary. This function also finds a 404 * suitable name for this image's sample file. 405 */ 406 407 static struct pmcstat_image * 408 pmcstat_image_from_path(const char *internedpath) 409 { 410 int count, hash, nlen; 411 struct pmcstat_image *pi; 412 char *sn; 413 char name[NAME_MAX]; 414 415 hash = pmcstat_string_compute_hash(internedpath); 416 417 /* Look for an existing entry. */ 418 LIST_FOREACH(pi, &pmcstat_image_hash[hash], pi_next) 419 if (pi->pi_internedpath == internedpath) { 420 /* move descriptor to the head of the lru list */ 421 TAILQ_REMOVE(&pmcstat_image_lru, pi, pi_lru); 422 TAILQ_INSERT_HEAD(&pmcstat_image_lru, pi, pi_lru); 423 return pi; 424 } 425 426 /* 427 * Allocate a new entry and place at the head of the hash and 428 * LRU lists. 429 */ 430 pi = malloc(sizeof(*pi)); 431 if (pi == NULL) 432 return NULL; 433 434 pi->pi_type = PMCSTAT_IMAGE_UNKNOWN; 435 pi->pi_internedpath = internedpath; 436 pi->pi_start = ~0; 437 pi->pi_entry = ~0; 438 pi->pi_end = 0; 439 440 /* 441 * Look for a suitable name for the sample files associated 442 * with this image: if `basename(path)`+".gmon" is available, 443 * we use that, otherwise we try iterating through 444 * `basename(path)`+ "~" + NNN + ".gmon" till we get a free 445 * entry. 446 */ 447 if ((sn = basename(internedpath)) == NULL) 448 err(EX_OSERR, "ERROR: Cannot process \"%s\"", internedpath); 449 450 nlen = strlen(sn); 451 nlen = min(nlen, (int) sizeof(name) - 6); /* ".gmon\0" */ 452 453 snprintf(name, sizeof(name), "%.*s.gmon", nlen, sn); 454 455 if (pmcstat_string_lookup(name) == NULL) 456 pi->pi_samplename = pmcstat_string_intern(name); 457 else { 458 nlen = strlen(sn); 459 nlen = min(nlen, (int) sizeof(name)-10); /* "~ddd.gmon\0" */ 460 count = 0; 461 do { 462 count++; 463 snprintf(name, sizeof(name), "%.*s~%3.3d", 464 nlen, sn, count); 465 if (pmcstat_string_lookup(name) == NULL) { 466 pi->pi_samplename = pmcstat_string_intern(name); 467 count = 0; 468 } 469 } while (count > 0); 470 } 471 472 LIST_INIT(&pi->pi_gmlist); 473 474 LIST_INSERT_HEAD(&pmcstat_image_hash[hash], pi, pi_next); 475 TAILQ_INSERT_HEAD(&pmcstat_image_lru, pi, pi_lru); 476 477 return pi; 478 } 479 480 /* 481 * Given an open file, determine its file type. 482 */ 483 484 static enum pmcstat_image_type 485 pmcstat_image_get_type(const char *path) 486 { 487 int fd; 488 Elf_Ehdr eh; 489 struct exec ex; 490 ssize_t nbytes; 491 char buffer[DEFAULT_BUFFER_SIZE]; 492 493 if ((fd = open(path, O_RDONLY)) < 0) 494 err(EX_OSERR, "ERROR: Cannot open \"%s\"", path); 495 496 nbytes = max(sizeof(eh), sizeof(ex)); 497 if ((nbytes = pread(fd, buffer, nbytes, 0)) < 0) 498 err(EX_OSERR, "ERROR: Cannot read \"%s\"", path); 499 500 (void) close(fd); 501 502 /* check if its an ELF file */ 503 if ((unsigned) nbytes >= sizeof(Elf_Ehdr)) { 504 bcopy(buffer, &eh, sizeof(eh)); 505 if (IS_ELF(eh)) 506 return PMCSTAT_IMAGE_ELF; 507 } 508 509 /* Look for an A.OUT header */ 510 if ((unsigned) nbytes >= sizeof(struct exec)) { 511 bcopy(buffer, &ex, sizeof(ex)); 512 if (!N_BADMAG(ex)) 513 return PMCSTAT_IMAGE_AOUT; 514 } 515 516 return PMCSTAT_IMAGE_UNKNOWN; 517 } 518 519 /* 520 * Increment the bucket in the gmon.out file corresponding to 'pmcid' 521 * and 'pc'. 522 */ 523 524 static void 525 pmcstat_image_increment_bucket(struct pmcstat_pcmap *map, uintfptr_t pc, 526 pmc_id_t pmcid, struct pmcstat_args *a) 527 { 528 struct pmcstat_image *image; 529 struct pmcstat_gmonfile *pgf; 530 uintfptr_t bucket; 531 HISTCOUNTER *hc; 532 533 assert(pc >= map->ppm_lowpc && pc < map->ppm_highpc); 534 535 /* 536 * Find the gmon file corresponding to 'pmcid', creating it if 537 * needed. 538 */ 539 540 image = map->ppm_image; 541 542 LIST_FOREACH(pgf, &image->pi_gmlist, pgf_next) 543 if (pgf->pgf_pmcid == pmcid) 544 break; 545 546 /* If we don't have a gmon.out file for this PMCid, create one */ 547 if (pgf == NULL) { 548 if ((pgf = calloc(1, sizeof(*pgf))) == NULL) 549 err(EX_OSERR, "ERROR:"); 550 551 pgf->pgf_gmondata = NULL; /* mark as unmapped */ 552 pgf->pgf_name = pmcstat_gmon_create_name(a->pa_samplesdir, 553 image, pmcid); 554 pgf->pgf_pmcid = pmcid; 555 assert(image->pi_end > image->pi_start); 556 pgf->pgf_nbuckets = (image->pi_end - image->pi_start) / 557 FUNCTION_ALIGNMENT; /* see <machine/profile.h> */ 558 pgf->pgf_ndatabytes = sizeof(struct gmonhdr) + 559 pgf->pgf_nbuckets * sizeof(HISTCOUNTER); 560 561 pmcstat_gmon_create_file(pgf, image); 562 563 LIST_INSERT_HEAD(&image->pi_gmlist, pgf, pgf_next); 564 } 565 566 /* 567 * Map the gmon file in if needed. It may have been mapped 568 * out under memory pressure. 569 */ 570 if (pgf->pgf_gmondata == NULL) 571 pmcstat_gmon_map_file(pgf); 572 573 bucket = (pc - map->ppm_lowpc) / FUNCTION_ALIGNMENT; 574 575 assert(bucket < pgf->pgf_nbuckets); 576 577 hc = (HISTCOUNTER *) ((uintptr_t) pgf->pgf_gmondata + 578 sizeof(struct gmonhdr)); 579 580 /* saturating add */ 581 if (hc[bucket] < 0xFFFF) 582 hc[bucket]++; 583 584 } 585 586 /* 587 * Record the fact that PC values from 'lowpc' to 'highpc' come from 588 * image 'image'. 589 */ 590 591 static void 592 pmcstat_image_link(struct pmcstat_process *pp, struct pmcstat_image *image, 593 uintfptr_t lowpc, uintfptr_t highpc) 594 { 595 struct pmcstat_pcmap *pcm, *pcmnew; 596 597 if ((pcmnew = malloc(sizeof(*pcmnew))) == NULL) 598 err(EX_OSERR, "ERROR: "); 599 600 pcmnew->ppm_lowpc = lowpc; 601 pcmnew->ppm_highpc = highpc; 602 pcmnew->ppm_image = image; 603 604 TAILQ_FOREACH(pcm, &pp->pp_map, ppm_next) 605 if (pcm->ppm_lowpc < lowpc) 606 break; 607 608 if (pcm == NULL) 609 TAILQ_INSERT_TAIL(&pp->pp_map, pcmnew, ppm_next); 610 else 611 TAILQ_INSERT_BEFORE(pcm, pcmnew, ppm_next); 612 } 613 614 /* 615 * Add a {pmcid,name} mapping. 616 */ 617 618 static void 619 pmcstat_pmcid_add(pmc_id_t pmcid, const char *name, struct pmcstat_args *a) 620 { 621 struct pmcstat_pmcrecord *pr; 622 struct stat st; 623 char fullpath[PATH_MAX]; 624 625 LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) 626 if (pr->pr_pmcid == pmcid) { 627 pr->pr_pmcname = name; 628 return; 629 } 630 631 if ((pr = malloc(sizeof(*pr))) == NULL) 632 err(EX_OSERR, "ERROR: Cannot allocate pmc record"); 633 634 pr->pr_pmcid = pmcid; 635 pr->pr_pmcname = name; 636 LIST_INSERT_HEAD(&pmcstat_pmcs, pr, pr_next); 637 638 (void) snprintf(fullpath, sizeof(fullpath), "%s/%s", a->pa_samplesdir, 639 name); 640 641 /* If the path name exists, it should be a directory */ 642 if (stat(fullpath, &st) == 0 && S_ISDIR(st.st_mode)) 643 return; 644 645 if (mkdir(fullpath, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) < 0) 646 err(EX_OSERR, "ERROR: Cannot create directory \"%s\"", 647 fullpath); 648 } 649 650 /* 651 * Given a pmcid in use, find its human-readable name, or a 652 */ 653 654 static const char * 655 pmcstat_pmcid_to_name(pmc_id_t pmcid) 656 { 657 struct pmcstat_pmcrecord *pr; 658 char fullpath[PATH_MAX]; 659 660 LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) 661 if (pr->pr_pmcid == pmcid) 662 return pr->pr_pmcname; 663 664 /* create a default name and add this entry */ 665 if ((pr = malloc(sizeof(*pr))) == NULL) 666 err(EX_OSERR, "ERROR: "); 667 pr->pr_pmcid = pmcid; 668 669 (void) snprintf(fullpath, sizeof(fullpath), "%X", (unsigned int) pmcid); 670 pr->pr_pmcname = pmcstat_string_intern(fullpath); 671 672 LIST_INSERT_HEAD(&pmcstat_pmcs, pr, pr_next); 673 674 return pr->pr_pmcname; 675 } 676 677 /* 678 * Associate an ELF image with a process. Argument 'path' names the 679 * executable while 'fd' is an already open descriptor to it. 680 */ 681 682 static void 683 pmcstat_process_add_elf_image(struct pmcstat_process *pp, const char *path, 684 uintfptr_t entryaddr) 685 { 686 size_t linelen; 687 FILE *rf; 688 char *line; 689 uintmax_t libstart; 690 struct pmcstat_image *image, *rtldimage; 691 char libpath[PATH_MAX]; 692 char command[PATH_MAX + sizeof(PMCSTAT_LDD_COMMAND) + 1]; 693 694 /* Look up path in the cache. */ 695 if ((image = pmcstat_image_from_path(path)) == NULL) 696 return; 697 698 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) 699 pmcstat_image_get_elf_params(image); 700 701 /* Create a map entry for the base executable. */ 702 pmcstat_image_link(pp, image, image->pi_start, image->pi_end); 703 704 /* 705 * For dynamically linked executables we need to: 706 * (a) find where the dynamic linker was mapped to for this 707 * process, 708 * (b) find all the executable objects that the dynamic linker 709 * brought in. 710 */ 711 if (image->pi_isdynamic) { 712 713 /* 714 * The runtime loader gets loaded just after the maximum 715 * possible heap address. Like so: 716 * 717 * [ TEXT DATA BSS HEAP -->*RTLD SHLIBS <--STACK] 718 * ^ ^ 719 * 0 VM_MAXUSER_ADDRESS 720 * 721 * The exact address where the loader gets mapped in 722 * will vary according to the size of the executable 723 * and the limits on the size of the process'es data 724 * segment at the time of exec(). The entry address 725 * recorded at process exec time corresponds to the 726 * 'start' address inside the dynamic linker. From 727 * this we can figure out the address where the 728 * runtime loader's file object had been mapped to. 729 */ 730 rtldimage = pmcstat_image_from_path(image->pi_dynlinkerpath); 731 if (rtldimage == NULL) 732 err(EX_OSERR, "ERROR: Cannot find image for " 733 "\"%s\"", image->pi_dynlinkerpath); 734 if (rtldimage->pi_type == PMCSTAT_IMAGE_UNKNOWN) 735 pmcstat_image_get_elf_params(rtldimage); 736 737 libstart = entryaddr - rtldimage->pi_entry; 738 pmcstat_image_link(pp, rtldimage, libstart, 739 libstart + rtldimage->pi_end - rtldimage->pi_start); 740 741 /* Process all other objects loaded by this executable. */ 742 (void) snprintf(command, sizeof(command), "%s %s", 743 PMCSTAT_LDD_COMMAND, path); 744 745 if ((rf = popen(command, "r")) == NULL) 746 err(EX_OSERR, "ERROR: Cannot create pipe"); 747 748 (void) fgetln(rf, &linelen); 749 750 while (!feof(rf) && !ferror(rf)) { 751 752 if ((line = fgetln(rf, &linelen)) == NULL) 753 continue; 754 line[linelen-1] = '\0'; 755 756 if (sscanf(line, "%s %jx", 757 libpath, &libstart) != 2) 758 continue; 759 760 image = pmcstat_image_from_path( 761 pmcstat_string_intern(libpath)); 762 if (image == NULL) 763 err(EX_OSERR, "ERROR: Cannot process " 764 "\"%s\"", libpath); 765 766 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) 767 pmcstat_image_get_elf_params(image); 768 769 pmcstat_image_link(pp, image, libstart + image->pi_start, 770 libstart + image->pi_end); 771 } 772 773 (void) pclose(rf); 774 775 } 776 } 777 778 /* 779 * Find the process descriptor corresponding to a PID. If 'allocate' 780 * is zero, we return a NULL if a pid descriptor could not be found or 781 * a process descriptor process. If 'allocate' is non-zero, then we 782 * will attempt to allocate a fresh process descriptor. Zombie 783 * process descriptors are only removed if a fresh allocation for the 784 * same PID is requested. 785 */ 786 787 static struct pmcstat_process * 788 pmcstat_process_lookup(pid_t pid, int allocate) 789 { 790 uint32_t hash; 791 struct pmcstat_pcmap *ppm, *ppmtmp; 792 struct pmcstat_process *pp, *pptmp; 793 794 hash = (uint32_t) pid & PMCSTAT_HASH_MASK; /* simplicity wins */ 795 796 LIST_FOREACH_SAFE(pp, &pmcstat_process_hash[hash], pp_next, pptmp) 797 if (pp->pp_pid == pid) { 798 /* Found a descriptor, check and process zombies */ 799 if (allocate && !pp->pp_isactive) { 800 /* remove maps */ 801 TAILQ_FOREACH_SAFE(ppm, &pp->pp_map, ppm_next, 802 ppmtmp) { 803 TAILQ_REMOVE(&pp->pp_map, ppm, ppm_next); 804 free(ppm); 805 } 806 /* remove process entry */ 807 LIST_REMOVE(pp, pp_next); 808 free(pp); 809 break; 810 } 811 return pp; 812 } 813 814 if (!allocate) 815 return NULL; 816 817 if ((pp = malloc(sizeof(*pp))) == NULL) 818 err(EX_OSERR, "ERROR: Cannot allocate pid descriptor"); 819 820 pp->pp_pid = pid; 821 pp->pp_isactive = 1; 822 823 TAILQ_INIT(&pp->pp_map); 824 825 LIST_INSERT_HEAD(&pmcstat_process_hash[hash], pp, pp_next); 826 return pp; 827 } 828 829 /* 830 * Associate an image and a process. 831 */ 832 833 static void 834 pmcstat_process_exec(struct pmcstat_process *pp, const char *path, 835 uintfptr_t entryaddr) 836 { 837 enum pmcstat_image_type filetype; 838 struct pmcstat_image *image; 839 840 if ((image = pmcstat_image_from_path(path)) == NULL) 841 return; 842 843 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) 844 filetype = pmcstat_image_get_type(path); 845 else 846 filetype = image->pi_type; 847 848 switch (filetype) { 849 case PMCSTAT_IMAGE_ELF: 850 pmcstat_process_add_elf_image(pp, path, entryaddr); 851 break; 852 853 case PMCSTAT_IMAGE_AOUT: 854 break; 855 856 default: 857 err(EX_SOFTWARE, "ERROR: Unsupported executable type for " 858 "\"%s\"", path); 859 } 860 } 861 862 863 /* 864 * Find the map entry associated with process 'p' at PC value 'pc'. 865 */ 866 867 static struct pmcstat_pcmap * 868 pmcstat_process_find_map(struct pmcstat_process *p, uintfptr_t pc) 869 { 870 struct pmcstat_pcmap *ppm; 871 872 TAILQ_FOREACH(ppm, &p->pp_map, ppm_next) 873 if (pc >= ppm->ppm_lowpc && pc < ppm->ppm_highpc) 874 return ppm; 875 876 return NULL; 877 } 878 879 880 /* 881 * Compute a 'hash' value for a string. 882 */ 883 884 static int 885 pmcstat_string_compute_hash(const char *s) 886 { 887 int hash; 888 889 for (hash = 0; *s; s++) 890 hash ^= *s; 891 892 return hash & PMCSTAT_HASH_MASK; 893 } 894 895 /* 896 * Intern a copy of string 's', and return a pointer to it. 897 */ 898 899 static const char * 900 pmcstat_string_intern(const char *s) 901 { 902 struct pmcstat_string *ps; 903 int hash, len; 904 905 hash = pmcstat_string_compute_hash(s); 906 len = strlen(s); 907 908 if ((ps = pmcstat_string_lookup(s)) != NULL) 909 return ps->ps_string; 910 911 if ((ps = malloc(sizeof(*ps))) == NULL) 912 err(EX_OSERR, "ERROR: Could not intern string"); 913 ps->ps_len = len; 914 ps->ps_hash = hash; 915 ps->ps_string = strdup(s); 916 LIST_INSERT_HEAD(&pmcstat_string_hash[hash], ps, ps_next); 917 return ps->ps_string; 918 } 919 920 static struct pmcstat_string * 921 pmcstat_string_lookup(const char *s) 922 { 923 struct pmcstat_string *ps; 924 int hash, len; 925 926 hash = pmcstat_string_compute_hash(s); 927 len = strlen(s); 928 929 LIST_FOREACH(ps, &pmcstat_string_hash[hash], ps_next) 930 if (ps->ps_len == len && ps->ps_hash == hash && 931 strcmp(ps->ps_string, s) == 0) 932 return ps; 933 return NULL; 934 } 935 936 /* 937 * Public Interfaces. 938 */ 939 940 /* 941 * Close a logfile, after first flushing all in-module queued data. 942 */ 943 944 int 945 pmcstat_close_log(struct pmcstat_args *a) 946 { 947 if (pmc_flush_logfile() < 0 || 948 pmc_configure_logfile(-1) < 0) 949 err(EX_OSERR, "ERROR: logging failed"); 950 a->pa_flags &= ~(FLAG_HAS_OUTPUT_LOGFILE | FLAG_HAS_PIPE); 951 return a->pa_flags & FLAG_HAS_PIPE ? PMCSTAT_EXITING : 952 PMCSTAT_FINISHED; 953 } 954 955 956 int 957 pmcstat_convert_log(struct pmcstat_args *a) 958 { 959 uintfptr_t pc; 960 struct pmcstat_process *pp, *ppnew; 961 struct pmcstat_pcmap *ppm, *ppmtmp; 962 struct pmclog_ev ev; 963 const char *image_path; 964 965 while (pmclog_read(a->pa_logparser, &ev) == 0) { 966 assert(ev.pl_state == PMCLOG_OK); 967 968 switch (ev.pl_type) { 969 case PMCLOG_TYPE_MAPPINGCHANGE: 970 /* 971 * Introduce an address range mapping for a 972 * process. 973 */ 974 break; 975 976 case PMCLOG_TYPE_PCSAMPLE: 977 978 /* 979 * We bring in the gmon file for the image 980 * currently associated with the PMC & pid 981 * pair and increment the appropriate entry 982 * bin inside this. 983 */ 984 pc = ev.pl_u.pl_s.pl_pc; 985 pp = pmcstat_process_lookup(ev.pl_u.pl_s.pl_pid, 1); 986 if ((ppm = pmcstat_process_find_map(pp, pc)) == NULL && 987 (ppm = pmcstat_process_find_map(pmcstat_kernproc, 988 pc)) == NULL) 989 break; /* unknown process,offset pair */ 990 991 pmcstat_image_increment_bucket(ppm, pc, 992 ev.pl_u.pl_s.pl_pmcid, a); 993 994 break; 995 996 case PMCLOG_TYPE_PMCALLOCATE: 997 /* 998 * Record the association pmc id between this 999 * PMC and its name. 1000 */ 1001 pmcstat_pmcid_add(ev.pl_u.pl_a.pl_pmcid, 1002 pmcstat_string_intern(ev.pl_u.pl_a.pl_evname), a); 1003 break; 1004 1005 case PMCLOG_TYPE_PROCEXEC: 1006 1007 /* 1008 * Change the executable image associated with 1009 * a process. 1010 */ 1011 pp = pmcstat_process_lookup(ev.pl_u.pl_x.pl_pid, 1); 1012 1013 /* delete the current process map */ 1014 TAILQ_FOREACH_SAFE(ppm, &pp->pp_map, ppm_next, ppmtmp) { 1015 TAILQ_REMOVE(&pp->pp_map, ppm, ppm_next); 1016 free(ppm); 1017 } 1018 1019 /* locate the descriptor for the new 'base' image */ 1020 image_path = pmcstat_string_intern( 1021 ev.pl_u.pl_x.pl_pathname); 1022 1023 /* link to the new image */ 1024 pmcstat_process_exec(pp, image_path, 1025 ev.pl_u.pl_x.pl_entryaddr); 1026 break; 1027 1028 case PMCLOG_TYPE_PROCEXIT: 1029 1030 /* 1031 * Due to the way the log is generated, the 1032 * last few samples corresponding to a process 1033 * may appear in the log after the process 1034 * exit event is recorded. Thus we keep the 1035 * process' descriptor and associated data 1036 * structures around, but mark the process as 1037 * having exited. 1038 */ 1039 pp = pmcstat_process_lookup(ev.pl_u.pl_e.pl_pid, 0); 1040 if (pp == NULL) 1041 break; 1042 pp->pp_isactive = 0; /* make a zombie */ 1043 break; 1044 1045 case PMCLOG_TYPE_SYSEXIT: 1046 pp = pmcstat_process_lookup(ev.pl_u.pl_se.pl_pid, 0); 1047 if (pp == NULL) 1048 break; 1049 pp->pp_isactive = 0; /* make a zombie */ 1050 break; 1051 1052 case PMCLOG_TYPE_PROCFORK: 1053 1054 /* 1055 * If we had been tracking 'oldpid', then clone 1056 * its pid descriptor. 1057 */ 1058 pp = pmcstat_process_lookup(ev.pl_u.pl_f.pl_oldpid, 0); 1059 if (pp == NULL) 1060 break; 1061 1062 ppnew = 1063 pmcstat_process_lookup(ev.pl_u.pl_f.pl_newpid, 1); 1064 1065 /* copy the old process' address maps */ 1066 TAILQ_FOREACH(ppm, &pp->pp_map, ppm_next) 1067 pmcstat_image_link(ppnew, ppm->ppm_image, 1068 ppm->ppm_lowpc, ppm->ppm_highpc); 1069 break; 1070 1071 default: /* other types of entries are not relevant */ 1072 break; 1073 } 1074 } 1075 1076 if (ev.pl_state == PMCLOG_EOF) 1077 return PMCSTAT_FINISHED; 1078 else if (ev.pl_state == PMCLOG_REQUIRE_DATA) 1079 return PMCSTAT_RUNNING; 1080 1081 err(EX_DATAERR, "ERROR: event parsing failed (record %jd, " 1082 "offset 0x%jx)", (uintmax_t) ev.pl_count + 1, ev.pl_offset); 1083 } 1084 1085 1086 /* 1087 * Open a log file, for reading or writing. 1088 * 1089 * The function returns the fd of a successfully opened log or -1 in 1090 * case of failure. 1091 */ 1092 1093 int 1094 pmcstat_open(const char *path, int mode) 1095 { 1096 int fd; 1097 1098 /* 1099 * If 'path' is "-" then open one of stdin or stdout depending 1100 * on the value of 'mode'. Otherwise, treat 'path' as a file 1101 * name and open that. 1102 */ 1103 if (path[0] == '-' && path[1] == '\0') 1104 fd = (mode == PMCSTAT_OPEN_FOR_READ) ? 0 : 1; 1105 else 1106 fd = open(path, mode == PMCSTAT_OPEN_FOR_READ ? 1107 O_RDONLY : (O_WRONLY|O_CREAT|O_TRUNC), 1108 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); 1109 1110 return fd; 1111 } 1112 1113 /* 1114 * Print log entries as text. 1115 */ 1116 1117 int 1118 pmcstat_print_log(struct pmcstat_args *a) 1119 { 1120 struct pmclog_ev ev; 1121 1122 while (pmclog_read(a->pa_logparser, &ev) == 0) { 1123 assert(ev.pl_state == PMCLOG_OK); 1124 switch (ev.pl_type) { 1125 case PMCLOG_TYPE_CLOSELOG: 1126 PMCSTAT_PRINT_ENTRY(a,"closelog",); 1127 break; 1128 case PMCLOG_TYPE_DROPNOTIFY: 1129 PMCSTAT_PRINT_ENTRY(a,"drop",); 1130 break; 1131 case PMCLOG_TYPE_INITIALIZE: 1132 PMCSTAT_PRINT_ENTRY(a,"initlog","0x%x \"%s\"", 1133 ev.pl_u.pl_i.pl_version, 1134 pmc_name_of_cputype(ev.pl_u.pl_i.pl_arch)); 1135 break; 1136 case PMCLOG_TYPE_MAPPINGCHANGE: 1137 PMCSTAT_PRINT_ENTRY(a,"mapping","%s %d %p %p \"%s\"", 1138 ev.pl_u.pl_m.pl_type == PMCLOG_MAPPING_INSERT ? 1139 "insert" : "delete", 1140 ev.pl_u.pl_m.pl_pid, 1141 (void *) ev.pl_u.pl_m.pl_start, 1142 (void *) ev.pl_u.pl_m.pl_end, 1143 ev.pl_u.pl_m.pl_pathname); 1144 break; 1145 case PMCLOG_TYPE_PCSAMPLE: 1146 PMCSTAT_PRINT_ENTRY(a,"sample","0x%x %d %p %c", 1147 ev.pl_u.pl_s.pl_pmcid, 1148 ev.pl_u.pl_s.pl_pid, 1149 (void *) ev.pl_u.pl_s.pl_pc, 1150 ev.pl_u.pl_s.pl_usermode ? 'u' : 's'); 1151 break; 1152 case PMCLOG_TYPE_PMCALLOCATE: 1153 PMCSTAT_PRINT_ENTRY(a,"allocate","0x%x \"%s\" 0x%x", 1154 ev.pl_u.pl_a.pl_pmcid, 1155 ev.pl_u.pl_a.pl_evname, 1156 ev.pl_u.pl_a.pl_flags); 1157 break; 1158 case PMCLOG_TYPE_PMCATTACH: 1159 PMCSTAT_PRINT_ENTRY(a,"attach","0x%x %d \"%s\"", 1160 ev.pl_u.pl_t.pl_pmcid, 1161 ev.pl_u.pl_t.pl_pid, 1162 ev.pl_u.pl_t.pl_pathname); 1163 break; 1164 case PMCLOG_TYPE_PMCDETACH: 1165 PMCSTAT_PRINT_ENTRY(a,"detach","0x%x %d", 1166 ev.pl_u.pl_d.pl_pmcid, 1167 ev.pl_u.pl_d.pl_pid); 1168 break; 1169 case PMCLOG_TYPE_PROCCSW: 1170 PMCSTAT_PRINT_ENTRY(a,"cswval","0x%x %d %jd", 1171 ev.pl_u.pl_c.pl_pmcid, 1172 ev.pl_u.pl_c.pl_pid, 1173 ev.pl_u.pl_c.pl_value); 1174 break; 1175 case PMCLOG_TYPE_PROCEXEC: 1176 PMCSTAT_PRINT_ENTRY(a,"exec","0x%x %d %p \"%s\"", 1177 ev.pl_u.pl_x.pl_pmcid, 1178 ev.pl_u.pl_x.pl_pid, 1179 (void *) ev.pl_u.pl_x.pl_entryaddr, 1180 ev.pl_u.pl_x.pl_pathname); 1181 break; 1182 case PMCLOG_TYPE_PROCEXIT: 1183 PMCSTAT_PRINT_ENTRY(a,"exitval","0x%x %d %jd", 1184 ev.pl_u.pl_e.pl_pmcid, 1185 ev.pl_u.pl_e.pl_pid, 1186 ev.pl_u.pl_e.pl_value); 1187 break; 1188 case PMCLOG_TYPE_PROCFORK: 1189 PMCSTAT_PRINT_ENTRY(a,"fork","%d %d", 1190 ev.pl_u.pl_f.pl_oldpid, 1191 ev.pl_u.pl_f.pl_newpid); 1192 break; 1193 case PMCLOG_TYPE_USERDATA: 1194 PMCSTAT_PRINT_ENTRY(a,"userdata","0x%x", 1195 ev.pl_u.pl_u.pl_userdata); 1196 break; 1197 case PMCLOG_TYPE_SYSEXIT: 1198 PMCSTAT_PRINT_ENTRY(a,"exit","%d", 1199 ev.pl_u.pl_se.pl_pid); 1200 break; 1201 default: 1202 fprintf(a->pa_printfile, "unknown %d", 1203 ev.pl_type); 1204 } 1205 } 1206 1207 if (ev.pl_state == PMCLOG_EOF) 1208 return PMCSTAT_FINISHED; 1209 else if (ev.pl_state == PMCLOG_REQUIRE_DATA) 1210 return PMCSTAT_RUNNING; 1211 1212 err(EX_DATAERR, "ERROR: event parsing failed " 1213 "(record %jd, offset 0x%jx)", 1214 (uintmax_t) ev.pl_count + 1, ev.pl_offset); 1215 /*NOTREACHED*/ 1216 } 1217 1218 /* 1219 * Process a log file in offline analysis mode. 1220 */ 1221 1222 int 1223 pmcstat_process_log(struct pmcstat_args *a) 1224 { 1225 1226 /* 1227 * If gprof style profiles haven't been asked for, just print the 1228 * log to the current output file. 1229 */ 1230 if (a->pa_flags & FLAG_DO_PRINT) 1231 return pmcstat_print_log(a); 1232 else 1233 /* convert the log to gprof compatible profiles */ 1234 return pmcstat_convert_log(a); 1235 } 1236 1237 void 1238 pmcstat_initialize_logging(struct pmcstat_args *a) 1239 { 1240 int i; 1241 const char *kernpath; 1242 struct pmcstat_image *img; 1243 1244 /* use a convenient format for 'ldd' output */ 1245 if (setenv("LD_TRACE_LOADED_OBJECTS_FMT1","%p %x\n",1) != 0) 1246 goto error; 1247 1248 /* Initialize hash tables */ 1249 for (i = 0; i < PMCSTAT_NHASH; i++) { 1250 LIST_INIT(&pmcstat_image_hash[i]); 1251 LIST_INIT(&pmcstat_process_hash[i]); 1252 LIST_INIT(&pmcstat_string_hash[i]); 1253 } 1254 1255 /* create a fake 'process' entry for the kernel with pid == -1 */ 1256 if ((pmcstat_kernproc = pmcstat_process_lookup((pid_t) -1, 1)) == NULL) 1257 goto error; 1258 1259 if ((kernpath = pmcstat_string_intern(a->pa_kernel)) == NULL) 1260 goto error; 1261 1262 img = pmcstat_image_from_path(kernpath); 1263 1264 pmcstat_image_get_elf_params(img); 1265 pmcstat_image_link(pmcstat_kernproc, img, img->pi_start, img->pi_end); 1266 1267 return; 1268 1269 error: 1270 err(EX_OSERR, "ERROR: Cannot initialize logging"); 1271 } 1272 1273 void 1274 pmcstat_shutdown_logging(void) 1275 { 1276 int i; 1277 struct pmcstat_gmonfile *pgf, *pgftmp; 1278 struct pmcstat_image *pi, *pitmp; 1279 struct pmcstat_process *pp, *pptmp; 1280 struct pmcstat_string *ps, *pstmp; 1281 1282 for (i = 0; i < PMCSTAT_NHASH; i++) { 1283 LIST_FOREACH_SAFE(pi, &pmcstat_image_hash[i], pi_next, pitmp) { 1284 /* flush gmon.out data to disk */ 1285 LIST_FOREACH_SAFE(pgf, &pi->pi_gmlist, pgf_next, 1286 pgftmp) { 1287 pmcstat_gmon_unmap_file(pgf); 1288 LIST_REMOVE(pgf, pgf_next); 1289 free(pgf); 1290 } 1291 1292 LIST_REMOVE(pi, pi_next); 1293 free(pi); 1294 } 1295 LIST_FOREACH_SAFE(pp, &pmcstat_process_hash[i], pp_next, 1296 pptmp) { 1297 LIST_REMOVE(pp, pp_next); 1298 free(pp); 1299 } 1300 LIST_FOREACH_SAFE(ps, &pmcstat_string_hash[i], ps_next, 1301 pstmp) { 1302 LIST_REMOVE(ps, ps_next); 1303 free(ps); 1304 } 1305 } 1306 } 1307