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 #if defined(__amd64__) 332 const Elf32_Ehdr *h32; 333 const Elf32_Phdr *ph32; 334 const Elf32_Shdr *sh32; 335 #endif 336 const char *path; 337 338 assert(image->pi_type == PMCSTAT_IMAGE_UNKNOWN); 339 340 minva = ~(uintfptr_t) 0; 341 maxva = (uintfptr_t) 0; 342 path = image->pi_internedpath; 343 344 if ((fd = open(path, O_RDONLY, 0)) < 0) 345 err(EX_OSERR, "ERROR: Cannot open \"%s\"", path); 346 347 if (fstat(fd, &st) < 0) 348 err(EX_OSERR, "ERROR: Cannot stat \"%s\"", path); 349 350 if ((mapbase = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == 351 MAP_FAILED) 352 err(EX_OSERR, "ERROR: Cannot mmap \"%s\"", path); 353 354 (void) close(fd); 355 356 h = (const Elf_Ehdr *) mapbase; 357 if (!IS_ELF(*h)) 358 err(EX_SOFTWARE, "ERROR: \"%s\" not an ELF file", path); 359 360 /* we only handle executable objects */ 361 if (h->e_type != ET_EXEC && h->e_type != ET_DYN) 362 err(EX_DATAERR, "ERROR: Unknown file type for \"%s\"", 363 image->pi_internedpath); 364 365 #define GET_VA(H, SH, MINVA, MAXVA) do { \ 366 for (i = 0; i < (H)->e_shnum; i++) \ 367 if ((SH)[i].sh_flags & SHF_EXECINSTR) { \ 368 (MINVA) = min((MINVA),(SH)[i].sh_addr); \ 369 (MAXVA) = max((MAXVA),(SH)[i].sh_addr + \ 370 (SH)[i].sh_size); \ 371 } \ 372 } while (0) 373 374 375 #define GET_PHDR_INFO(H, PH, IMAGE) do { \ 376 for (i = 0; i < (H)->e_phnum; i++) { \ 377 switch ((PH)[i].p_type) { \ 378 case PT_DYNAMIC: \ 379 image->pi_isdynamic = 1; \ 380 break; \ 381 case PT_INTERP: \ 382 image->pi_dynlinkerpath = \ 383 pmcstat_string_intern( \ 384 (char *) mapbase + \ 385 (PH)[i].p_offset); \ 386 break; \ 387 } \ 388 } \ 389 } while (0) 390 391 image->pi_type = PMCSTAT_IMAGE_ELF; 392 image->pi_isdynamic = 0; 393 image->pi_dynlinkerpath = NULL; 394 395 switch (h->e_machine) { 396 case EM_386: 397 case EM_486: 398 #if defined(__amd64__) 399 /* a 32 bit executable */ 400 h32 = (const Elf32_Ehdr *) h; 401 sh32 = (const Elf32_Shdr *)((uintptr_t) mapbase + h32->e_shoff); 402 403 GET_VA(h32, sh32, minva, maxva); 404 405 image->pi_entry = h32->e_entry; 406 407 if (h32->e_type == ET_EXEC) { 408 ph32 = (const Elf32_Phdr *)((uintptr_t) mapbase + 409 h32->e_phoff); 410 GET_PHDR_INFO(h32, ph32, image); 411 } 412 break; 413 #endif 414 default: 415 sh = (const Elf_Shdr *)((uintptr_t) mapbase + h->e_shoff); 416 417 GET_VA(h, sh, minva, maxva); 418 419 image->pi_entry = h->e_entry; 420 421 if (h->e_type == ET_EXEC) { 422 ph = (const Elf_Phdr *)((uintptr_t) mapbase + 423 h->e_phoff); 424 GET_PHDR_INFO(h, ph, image); 425 } 426 break; 427 } 428 429 #undef GET_PHDR_INFO 430 #undef GET_VA 431 432 image->pi_start = minva; 433 image->pi_end = maxva; 434 435 if (munmap(mapbase, st.st_size) < 0) 436 err(EX_OSERR, "ERROR: Cannot unmap \"%s\"", path); 437 438 } 439 440 /* 441 * Locate an image descriptor given an interned path, adding a fresh 442 * descriptor to the cache if necessary. This function also finds a 443 * suitable name for this image's sample file. 444 */ 445 446 static struct pmcstat_image * 447 pmcstat_image_from_path(const char *internedpath) 448 { 449 int count, hash, nlen; 450 struct pmcstat_image *pi; 451 char *sn; 452 char name[NAME_MAX]; 453 454 hash = pmcstat_string_compute_hash(internedpath); 455 456 /* Look for an existing entry. */ 457 LIST_FOREACH(pi, &pmcstat_image_hash[hash], pi_next) 458 if (pi->pi_internedpath == internedpath) { 459 /* move descriptor to the head of the lru list */ 460 TAILQ_REMOVE(&pmcstat_image_lru, pi, pi_lru); 461 TAILQ_INSERT_HEAD(&pmcstat_image_lru, pi, pi_lru); 462 return pi; 463 } 464 465 /* 466 * Allocate a new entry and place at the head of the hash and 467 * LRU lists. 468 */ 469 pi = malloc(sizeof(*pi)); 470 if (pi == NULL) 471 return NULL; 472 473 pi->pi_type = PMCSTAT_IMAGE_UNKNOWN; 474 pi->pi_internedpath = internedpath; 475 pi->pi_start = ~0; 476 pi->pi_entry = ~0; 477 pi->pi_end = 0; 478 479 /* 480 * Look for a suitable name for the sample files associated 481 * with this image: if `basename(path)`+".gmon" is available, 482 * we use that, otherwise we try iterating through 483 * `basename(path)`+ "~" + NNN + ".gmon" till we get a free 484 * entry. 485 */ 486 if ((sn = basename(internedpath)) == NULL) 487 err(EX_OSERR, "ERROR: Cannot process \"%s\"", internedpath); 488 489 nlen = strlen(sn); 490 nlen = min(nlen, (int) sizeof(name) - 6); /* ".gmon\0" */ 491 492 snprintf(name, sizeof(name), "%.*s.gmon", nlen, sn); 493 494 if (pmcstat_string_lookup(name) == NULL) 495 pi->pi_samplename = pmcstat_string_intern(name); 496 else { 497 nlen = strlen(sn); 498 nlen = min(nlen, (int) sizeof(name)-10); /* "~ddd.gmon\0" */ 499 count = 0; 500 do { 501 count++; 502 snprintf(name, sizeof(name), "%.*s~%3.3d", 503 nlen, sn, count); 504 if (pmcstat_string_lookup(name) == NULL) { 505 pi->pi_samplename = pmcstat_string_intern(name); 506 count = 0; 507 } 508 } while (count > 0); 509 } 510 511 LIST_INIT(&pi->pi_gmlist); 512 513 LIST_INSERT_HEAD(&pmcstat_image_hash[hash], pi, pi_next); 514 TAILQ_INSERT_HEAD(&pmcstat_image_lru, pi, pi_lru); 515 516 return pi; 517 } 518 519 /* 520 * Given an open file, determine its file type. 521 */ 522 523 static enum pmcstat_image_type 524 pmcstat_image_get_type(const char *path) 525 { 526 int fd; 527 Elf_Ehdr eh; 528 struct exec ex; 529 ssize_t nbytes; 530 char buffer[DEFAULT_BUFFER_SIZE]; 531 532 if ((fd = open(path, O_RDONLY)) < 0) 533 err(EX_OSERR, "ERROR: Cannot open \"%s\"", path); 534 535 nbytes = max(sizeof(eh), sizeof(ex)); 536 if ((nbytes = pread(fd, buffer, nbytes, 0)) < 0) 537 err(EX_OSERR, "ERROR: Cannot read \"%s\"", path); 538 539 (void) close(fd); 540 541 /* check if its an ELF file */ 542 if ((unsigned) nbytes >= sizeof(Elf_Ehdr)) { 543 bcopy(buffer, &eh, sizeof(eh)); 544 if (IS_ELF(eh)) 545 return PMCSTAT_IMAGE_ELF; 546 } 547 548 /* Look for an A.OUT header */ 549 if ((unsigned) nbytes >= sizeof(struct exec)) { 550 bcopy(buffer, &ex, sizeof(ex)); 551 if (!N_BADMAG(ex)) 552 return PMCSTAT_IMAGE_AOUT; 553 } 554 555 return PMCSTAT_IMAGE_UNKNOWN; 556 } 557 558 /* 559 * Increment the bucket in the gmon.out file corresponding to 'pmcid' 560 * and 'pc'. 561 */ 562 563 static void 564 pmcstat_image_increment_bucket(struct pmcstat_pcmap *map, uintfptr_t pc, 565 pmc_id_t pmcid, struct pmcstat_args *a) 566 { 567 struct pmcstat_image *image; 568 struct pmcstat_gmonfile *pgf; 569 uintfptr_t bucket; 570 HISTCOUNTER *hc; 571 572 assert(pc >= map->ppm_lowpc && pc < map->ppm_highpc); 573 574 /* 575 * Find the gmon file corresponding to 'pmcid', creating it if 576 * needed. 577 */ 578 579 image = map->ppm_image; 580 581 LIST_FOREACH(pgf, &image->pi_gmlist, pgf_next) 582 if (pgf->pgf_pmcid == pmcid) 583 break; 584 585 /* If we don't have a gmon.out file for this PMCid, create one */ 586 if (pgf == NULL) { 587 if ((pgf = calloc(1, sizeof(*pgf))) == NULL) 588 err(EX_OSERR, "ERROR:"); 589 590 pgf->pgf_gmondata = NULL; /* mark as unmapped */ 591 pgf->pgf_name = pmcstat_gmon_create_name(a->pa_samplesdir, 592 image, pmcid); 593 pgf->pgf_pmcid = pmcid; 594 assert(image->pi_end > image->pi_start); 595 pgf->pgf_nbuckets = (image->pi_end - image->pi_start) / 596 FUNCTION_ALIGNMENT; /* see <machine/profile.h> */ 597 pgf->pgf_ndatabytes = sizeof(struct gmonhdr) + 598 pgf->pgf_nbuckets * sizeof(HISTCOUNTER); 599 600 pmcstat_gmon_create_file(pgf, image); 601 602 LIST_INSERT_HEAD(&image->pi_gmlist, pgf, pgf_next); 603 } 604 605 /* 606 * Map the gmon file in if needed. It may have been mapped 607 * out under memory pressure. 608 */ 609 if (pgf->pgf_gmondata == NULL) 610 pmcstat_gmon_map_file(pgf); 611 612 bucket = (pc - map->ppm_lowpc) / FUNCTION_ALIGNMENT; 613 614 assert(bucket < pgf->pgf_nbuckets); 615 616 hc = (HISTCOUNTER *) ((uintptr_t) pgf->pgf_gmondata + 617 sizeof(struct gmonhdr)); 618 619 /* saturating add */ 620 if (hc[bucket] < 0xFFFF) 621 hc[bucket]++; 622 623 } 624 625 /* 626 * Record the fact that PC values from 'lowpc' to 'highpc' come from 627 * image 'image'. 628 */ 629 630 static void 631 pmcstat_image_link(struct pmcstat_process *pp, struct pmcstat_image *image, 632 uintfptr_t lowpc, uintfptr_t highpc) 633 { 634 struct pmcstat_pcmap *pcm, *pcmnew; 635 636 if ((pcmnew = malloc(sizeof(*pcmnew))) == NULL) 637 err(EX_OSERR, "ERROR: "); 638 639 pcmnew->ppm_lowpc = lowpc; 640 pcmnew->ppm_highpc = highpc; 641 pcmnew->ppm_image = image; 642 643 TAILQ_FOREACH(pcm, &pp->pp_map, ppm_next) 644 if (pcm->ppm_lowpc < lowpc) 645 break; 646 647 if (pcm == NULL) 648 TAILQ_INSERT_TAIL(&pp->pp_map, pcmnew, ppm_next); 649 else 650 TAILQ_INSERT_BEFORE(pcm, pcmnew, ppm_next); 651 } 652 653 /* 654 * Add a {pmcid,name} mapping. 655 */ 656 657 static void 658 pmcstat_pmcid_add(pmc_id_t pmcid, const char *name, struct pmcstat_args *a) 659 { 660 struct pmcstat_pmcrecord *pr; 661 struct stat st; 662 char fullpath[PATH_MAX]; 663 664 LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) 665 if (pr->pr_pmcid == pmcid) { 666 pr->pr_pmcname = name; 667 return; 668 } 669 670 if ((pr = malloc(sizeof(*pr))) == NULL) 671 err(EX_OSERR, "ERROR: Cannot allocate pmc record"); 672 673 pr->pr_pmcid = pmcid; 674 pr->pr_pmcname = name; 675 LIST_INSERT_HEAD(&pmcstat_pmcs, pr, pr_next); 676 677 (void) snprintf(fullpath, sizeof(fullpath), "%s/%s", a->pa_samplesdir, 678 name); 679 680 /* If the path name exists, it should be a directory */ 681 if (stat(fullpath, &st) == 0 && S_ISDIR(st.st_mode)) 682 return; 683 684 if (mkdir(fullpath, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) < 0) 685 err(EX_OSERR, "ERROR: Cannot create directory \"%s\"", 686 fullpath); 687 } 688 689 /* 690 * Given a pmcid in use, find its human-readable name, or a 691 */ 692 693 static const char * 694 pmcstat_pmcid_to_name(pmc_id_t pmcid) 695 { 696 struct pmcstat_pmcrecord *pr; 697 char fullpath[PATH_MAX]; 698 699 LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) 700 if (pr->pr_pmcid == pmcid) 701 return pr->pr_pmcname; 702 703 /* create a default name and add this entry */ 704 if ((pr = malloc(sizeof(*pr))) == NULL) 705 err(EX_OSERR, "ERROR: "); 706 pr->pr_pmcid = pmcid; 707 708 (void) snprintf(fullpath, sizeof(fullpath), "%X", (unsigned int) pmcid); 709 pr->pr_pmcname = pmcstat_string_intern(fullpath); 710 711 LIST_INSERT_HEAD(&pmcstat_pmcs, pr, pr_next); 712 713 return pr->pr_pmcname; 714 } 715 716 /* 717 * Associate an ELF image with a process. Argument 'path' names the 718 * executable while 'fd' is an already open descriptor to it. 719 */ 720 721 static void 722 pmcstat_process_add_elf_image(struct pmcstat_process *pp, const char *path, 723 uintfptr_t entryaddr) 724 { 725 size_t linelen; 726 FILE *rf; 727 char *line; 728 uintmax_t libstart; 729 struct pmcstat_image *image, *rtldimage; 730 char libname[PATH_MAX], libpath[PATH_MAX]; 731 char command[PATH_MAX + sizeof(PMCSTAT_LDD_COMMAND) + 1]; 732 733 /* Look up path in the cache. */ 734 if ((image = pmcstat_image_from_path(path)) == NULL) 735 return; 736 737 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) 738 pmcstat_image_get_elf_params(image); 739 740 /* Create a map entry for the base executable. */ 741 pmcstat_image_link(pp, image, image->pi_start, image->pi_end); 742 743 /* 744 * For dynamically linked executables we need to: 745 * (a) find where the dynamic linker was mapped to for this 746 * process, 747 * (b) find all the executable objects that the dynamic linker 748 * brought in. 749 */ 750 if (image->pi_isdynamic) { 751 752 /* 753 * The runtime loader gets loaded just after the maximum 754 * possible heap address. Like so: 755 * 756 * [ TEXT DATA BSS HEAP -->*RTLD SHLIBS <--STACK] 757 * ^ ^ 758 * 0 VM_MAXUSER_ADDRESS 759 * 760 * The exact address where the loader gets mapped in 761 * will vary according to the size of the executable 762 * and the limits on the size of the process'es data 763 * segment at the time of exec(). The entry address 764 * recorded at process exec time corresponds to the 765 * 'start' address inside the dynamic linker. From 766 * this we can figure out the address where the 767 * runtime loader's file object had been mapped to. 768 */ 769 rtldimage = pmcstat_image_from_path(image->pi_dynlinkerpath); 770 if (rtldimage == NULL) 771 err(EX_OSERR, "ERROR: Cannot find image for " 772 "\"%s\"", image->pi_dynlinkerpath); 773 if (rtldimage->pi_type == PMCSTAT_IMAGE_UNKNOWN) 774 pmcstat_image_get_elf_params(rtldimage); 775 776 libstart = entryaddr - rtldimage->pi_entry; 777 pmcstat_image_link(pp, rtldimage, libstart, 778 libstart + rtldimage->pi_end - rtldimage->pi_start); 779 780 /* Process all other objects loaded by this executable. */ 781 (void) snprintf(command, sizeof(command), "%s %s", 782 PMCSTAT_LDD_COMMAND, path); 783 784 if ((rf = popen(command, "r")) == NULL) 785 err(EX_OSERR, "ERROR: Cannot create pipe"); 786 787 (void) fgetln(rf, &linelen); 788 789 while (!feof(rf) && !ferror(rf)) { 790 791 if ((line = fgetln(rf, &linelen)) == NULL) 792 continue; 793 line[linelen-1] = '\0'; 794 795 libstart = 0; 796 libpath[0] = libname[0] = '\0'; 797 if (sscanf(line, "%s \"%[^\"]\" %jx", 798 libname, libpath, &libstart) != 3) 799 continue; 800 801 if (libstart == 0) { 802 warnx("WARNING: object \"%s\" was not found " 803 "for program \"%s\".", libname, path); 804 continue; 805 } 806 807 image = pmcstat_image_from_path( 808 pmcstat_string_intern(libpath)); 809 if (image == NULL) 810 err(EX_OSERR, "ERROR: Cannot process " 811 "\"%s\"", libpath); 812 813 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) 814 pmcstat_image_get_elf_params(image); 815 816 pmcstat_image_link(pp, image, libstart + image->pi_start, 817 libstart + image->pi_end); 818 } 819 820 (void) pclose(rf); 821 822 } 823 } 824 825 /* 826 * Find the process descriptor corresponding to a PID. If 'allocate' 827 * is zero, we return a NULL if a pid descriptor could not be found or 828 * a process descriptor process. If 'allocate' is non-zero, then we 829 * will attempt to allocate a fresh process descriptor. Zombie 830 * process descriptors are only removed if a fresh allocation for the 831 * same PID is requested. 832 */ 833 834 static struct pmcstat_process * 835 pmcstat_process_lookup(pid_t pid, int allocate) 836 { 837 uint32_t hash; 838 struct pmcstat_pcmap *ppm, *ppmtmp; 839 struct pmcstat_process *pp, *pptmp; 840 841 hash = (uint32_t) pid & PMCSTAT_HASH_MASK; /* simplicity wins */ 842 843 LIST_FOREACH_SAFE(pp, &pmcstat_process_hash[hash], pp_next, pptmp) 844 if (pp->pp_pid == pid) { 845 /* Found a descriptor, check and process zombies */ 846 if (allocate && !pp->pp_isactive) { 847 /* remove maps */ 848 TAILQ_FOREACH_SAFE(ppm, &pp->pp_map, ppm_next, 849 ppmtmp) { 850 TAILQ_REMOVE(&pp->pp_map, ppm, ppm_next); 851 free(ppm); 852 } 853 /* remove process entry */ 854 LIST_REMOVE(pp, pp_next); 855 free(pp); 856 break; 857 } 858 return pp; 859 } 860 861 if (!allocate) 862 return NULL; 863 864 if ((pp = malloc(sizeof(*pp))) == NULL) 865 err(EX_OSERR, "ERROR: Cannot allocate pid descriptor"); 866 867 pp->pp_pid = pid; 868 pp->pp_isactive = 1; 869 870 TAILQ_INIT(&pp->pp_map); 871 872 LIST_INSERT_HEAD(&pmcstat_process_hash[hash], pp, pp_next); 873 return pp; 874 } 875 876 /* 877 * Associate an image and a process. 878 */ 879 880 static void 881 pmcstat_process_exec(struct pmcstat_process *pp, const char *path, 882 uintfptr_t entryaddr) 883 { 884 enum pmcstat_image_type filetype; 885 struct pmcstat_image *image; 886 887 if ((image = pmcstat_image_from_path(path)) == NULL) 888 return; 889 890 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) 891 filetype = pmcstat_image_get_type(path); 892 else 893 filetype = image->pi_type; 894 895 switch (filetype) { 896 case PMCSTAT_IMAGE_ELF: 897 pmcstat_process_add_elf_image(pp, path, entryaddr); 898 break; 899 900 case PMCSTAT_IMAGE_AOUT: 901 break; 902 903 default: 904 err(EX_SOFTWARE, "ERROR: Unsupported executable type for " 905 "\"%s\"", path); 906 } 907 } 908 909 910 /* 911 * Find the map entry associated with process 'p' at PC value 'pc'. 912 */ 913 914 static struct pmcstat_pcmap * 915 pmcstat_process_find_map(struct pmcstat_process *p, uintfptr_t pc) 916 { 917 struct pmcstat_pcmap *ppm; 918 919 TAILQ_FOREACH(ppm, &p->pp_map, ppm_next) 920 if (pc >= ppm->ppm_lowpc && pc < ppm->ppm_highpc) 921 return ppm; 922 923 return NULL; 924 } 925 926 927 /* 928 * Compute a 'hash' value for a string. 929 */ 930 931 static int 932 pmcstat_string_compute_hash(const char *s) 933 { 934 int hash; 935 936 for (hash = 0; *s; s++) 937 hash ^= *s; 938 939 return hash & PMCSTAT_HASH_MASK; 940 } 941 942 /* 943 * Intern a copy of string 's', and return a pointer to it. 944 */ 945 946 static const char * 947 pmcstat_string_intern(const char *s) 948 { 949 struct pmcstat_string *ps; 950 int hash, len; 951 952 hash = pmcstat_string_compute_hash(s); 953 len = strlen(s); 954 955 if ((ps = pmcstat_string_lookup(s)) != NULL) 956 return ps->ps_string; 957 958 if ((ps = malloc(sizeof(*ps))) == NULL) 959 err(EX_OSERR, "ERROR: Could not intern string"); 960 ps->ps_len = len; 961 ps->ps_hash = hash; 962 ps->ps_string = strdup(s); 963 LIST_INSERT_HEAD(&pmcstat_string_hash[hash], ps, ps_next); 964 return ps->ps_string; 965 } 966 967 static struct pmcstat_string * 968 pmcstat_string_lookup(const char *s) 969 { 970 struct pmcstat_string *ps; 971 int hash, len; 972 973 hash = pmcstat_string_compute_hash(s); 974 len = strlen(s); 975 976 LIST_FOREACH(ps, &pmcstat_string_hash[hash], ps_next) 977 if (ps->ps_len == len && ps->ps_hash == hash && 978 strcmp(ps->ps_string, s) == 0) 979 return ps; 980 return NULL; 981 } 982 983 /* 984 * Public Interfaces. 985 */ 986 987 /* 988 * Close a logfile, after first flushing all in-module queued data. 989 */ 990 991 int 992 pmcstat_close_log(struct pmcstat_args *a) 993 { 994 if (pmc_flush_logfile() < 0 || 995 pmc_configure_logfile(-1) < 0) 996 err(EX_OSERR, "ERROR: logging failed"); 997 a->pa_flags &= ~(FLAG_HAS_OUTPUT_LOGFILE | FLAG_HAS_PIPE); 998 return a->pa_flags & FLAG_HAS_PIPE ? PMCSTAT_EXITING : 999 PMCSTAT_FINISHED; 1000 } 1001 1002 1003 int 1004 pmcstat_convert_log(struct pmcstat_args *a) 1005 { 1006 uintfptr_t pc; 1007 struct pmcstat_process *pp, *ppnew; 1008 struct pmcstat_pcmap *ppm, *ppmtmp; 1009 struct pmclog_ev ev; 1010 const char *image_path; 1011 1012 while (pmclog_read(a->pa_logparser, &ev) == 0) { 1013 assert(ev.pl_state == PMCLOG_OK); 1014 1015 switch (ev.pl_type) { 1016 case PMCLOG_TYPE_MAPPINGCHANGE: 1017 /* 1018 * Introduce an address range mapping for a 1019 * process. 1020 */ 1021 break; 1022 1023 case PMCLOG_TYPE_PCSAMPLE: 1024 1025 /* 1026 * We bring in the gmon file for the image 1027 * currently associated with the PMC & pid 1028 * pair and increment the appropriate entry 1029 * bin inside this. 1030 */ 1031 pc = ev.pl_u.pl_s.pl_pc; 1032 pp = pmcstat_process_lookup(ev.pl_u.pl_s.pl_pid, 1); 1033 if ((ppm = pmcstat_process_find_map(pp, pc)) == NULL && 1034 (ppm = pmcstat_process_find_map(pmcstat_kernproc, 1035 pc)) == NULL) 1036 break; /* unknown process,offset pair */ 1037 1038 pmcstat_image_increment_bucket(ppm, pc, 1039 ev.pl_u.pl_s.pl_pmcid, a); 1040 1041 break; 1042 1043 case PMCLOG_TYPE_PMCALLOCATE: 1044 /* 1045 * Record the association pmc id between this 1046 * PMC and its name. 1047 */ 1048 pmcstat_pmcid_add(ev.pl_u.pl_a.pl_pmcid, 1049 pmcstat_string_intern(ev.pl_u.pl_a.pl_evname), a); 1050 break; 1051 1052 case PMCLOG_TYPE_PROCEXEC: 1053 1054 /* 1055 * Change the executable image associated with 1056 * a process. 1057 */ 1058 pp = pmcstat_process_lookup(ev.pl_u.pl_x.pl_pid, 1); 1059 1060 /* delete the current process map */ 1061 TAILQ_FOREACH_SAFE(ppm, &pp->pp_map, ppm_next, ppmtmp) { 1062 TAILQ_REMOVE(&pp->pp_map, ppm, ppm_next); 1063 free(ppm); 1064 } 1065 1066 /* locate the descriptor for the new 'base' image */ 1067 image_path = pmcstat_string_intern( 1068 ev.pl_u.pl_x.pl_pathname); 1069 1070 /* link to the new image */ 1071 pmcstat_process_exec(pp, image_path, 1072 ev.pl_u.pl_x.pl_entryaddr); 1073 break; 1074 1075 case PMCLOG_TYPE_PROCEXIT: 1076 1077 /* 1078 * Due to the way the log is generated, the 1079 * last few samples corresponding to a process 1080 * may appear in the log after the process 1081 * exit event is recorded. Thus we keep the 1082 * process' descriptor and associated data 1083 * structures around, but mark the process as 1084 * having exited. 1085 */ 1086 pp = pmcstat_process_lookup(ev.pl_u.pl_e.pl_pid, 0); 1087 if (pp == NULL) 1088 break; 1089 pp->pp_isactive = 0; /* make a zombie */ 1090 break; 1091 1092 case PMCLOG_TYPE_SYSEXIT: 1093 pp = pmcstat_process_lookup(ev.pl_u.pl_se.pl_pid, 0); 1094 if (pp == NULL) 1095 break; 1096 pp->pp_isactive = 0; /* make a zombie */ 1097 break; 1098 1099 case PMCLOG_TYPE_PROCFORK: 1100 1101 /* 1102 * If we had been tracking 'oldpid', then clone 1103 * its pid descriptor. 1104 */ 1105 pp = pmcstat_process_lookup(ev.pl_u.pl_f.pl_oldpid, 0); 1106 if (pp == NULL) 1107 break; 1108 1109 ppnew = 1110 pmcstat_process_lookup(ev.pl_u.pl_f.pl_newpid, 1); 1111 1112 /* copy the old process' address maps */ 1113 TAILQ_FOREACH(ppm, &pp->pp_map, ppm_next) 1114 pmcstat_image_link(ppnew, ppm->ppm_image, 1115 ppm->ppm_lowpc, ppm->ppm_highpc); 1116 break; 1117 1118 default: /* other types of entries are not relevant */ 1119 break; 1120 } 1121 } 1122 1123 if (ev.pl_state == PMCLOG_EOF) 1124 return PMCSTAT_FINISHED; 1125 else if (ev.pl_state == PMCLOG_REQUIRE_DATA) 1126 return PMCSTAT_RUNNING; 1127 1128 err(EX_DATAERR, "ERROR: event parsing failed (record %jd, " 1129 "offset 0x%jx)", (uintmax_t) ev.pl_count + 1, ev.pl_offset); 1130 } 1131 1132 1133 /* 1134 * Open a log file, for reading or writing. 1135 * 1136 * The function returns the fd of a successfully opened log or -1 in 1137 * case of failure. 1138 */ 1139 1140 int 1141 pmcstat_open(const char *path, int mode) 1142 { 1143 int fd; 1144 1145 /* 1146 * If 'path' is "-" then open one of stdin or stdout depending 1147 * on the value of 'mode'. Otherwise, treat 'path' as a file 1148 * name and open that. 1149 */ 1150 if (path[0] == '-' && path[1] == '\0') 1151 fd = (mode == PMCSTAT_OPEN_FOR_READ) ? 0 : 1; 1152 else 1153 fd = open(path, mode == PMCSTAT_OPEN_FOR_READ ? 1154 O_RDONLY : (O_WRONLY|O_CREAT|O_TRUNC), 1155 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); 1156 1157 return fd; 1158 } 1159 1160 /* 1161 * Print log entries as text. 1162 */ 1163 1164 int 1165 pmcstat_print_log(struct pmcstat_args *a) 1166 { 1167 struct pmclog_ev ev; 1168 1169 while (pmclog_read(a->pa_logparser, &ev) == 0) { 1170 assert(ev.pl_state == PMCLOG_OK); 1171 switch (ev.pl_type) { 1172 case PMCLOG_TYPE_CLOSELOG: 1173 PMCSTAT_PRINT_ENTRY(a,"closelog",); 1174 break; 1175 case PMCLOG_TYPE_DROPNOTIFY: 1176 PMCSTAT_PRINT_ENTRY(a,"drop",); 1177 break; 1178 case PMCLOG_TYPE_INITIALIZE: 1179 PMCSTAT_PRINT_ENTRY(a,"initlog","0x%x \"%s\"", 1180 ev.pl_u.pl_i.pl_version, 1181 pmc_name_of_cputype(ev.pl_u.pl_i.pl_arch)); 1182 break; 1183 case PMCLOG_TYPE_MAPPINGCHANGE: 1184 PMCSTAT_PRINT_ENTRY(a,"mapping","%s %d %p %p \"%s\"", 1185 ev.pl_u.pl_m.pl_type == PMCLOG_MAPPING_INSERT ? 1186 "insert" : "delete", 1187 ev.pl_u.pl_m.pl_pid, 1188 (void *) ev.pl_u.pl_m.pl_start, 1189 (void *) ev.pl_u.pl_m.pl_end, 1190 ev.pl_u.pl_m.pl_pathname); 1191 break; 1192 case PMCLOG_TYPE_PCSAMPLE: 1193 PMCSTAT_PRINT_ENTRY(a,"sample","0x%x %d %p %c", 1194 ev.pl_u.pl_s.pl_pmcid, 1195 ev.pl_u.pl_s.pl_pid, 1196 (void *) ev.pl_u.pl_s.pl_pc, 1197 ev.pl_u.pl_s.pl_usermode ? 'u' : 's'); 1198 break; 1199 case PMCLOG_TYPE_PMCALLOCATE: 1200 PMCSTAT_PRINT_ENTRY(a,"allocate","0x%x \"%s\" 0x%x", 1201 ev.pl_u.pl_a.pl_pmcid, 1202 ev.pl_u.pl_a.pl_evname, 1203 ev.pl_u.pl_a.pl_flags); 1204 break; 1205 case PMCLOG_TYPE_PMCATTACH: 1206 PMCSTAT_PRINT_ENTRY(a,"attach","0x%x %d \"%s\"", 1207 ev.pl_u.pl_t.pl_pmcid, 1208 ev.pl_u.pl_t.pl_pid, 1209 ev.pl_u.pl_t.pl_pathname); 1210 break; 1211 case PMCLOG_TYPE_PMCDETACH: 1212 PMCSTAT_PRINT_ENTRY(a,"detach","0x%x %d", 1213 ev.pl_u.pl_d.pl_pmcid, 1214 ev.pl_u.pl_d.pl_pid); 1215 break; 1216 case PMCLOG_TYPE_PROCCSW: 1217 PMCSTAT_PRINT_ENTRY(a,"cswval","0x%x %d %jd", 1218 ev.pl_u.pl_c.pl_pmcid, 1219 ev.pl_u.pl_c.pl_pid, 1220 ev.pl_u.pl_c.pl_value); 1221 break; 1222 case PMCLOG_TYPE_PROCEXEC: 1223 PMCSTAT_PRINT_ENTRY(a,"exec","0x%x %d %p \"%s\"", 1224 ev.pl_u.pl_x.pl_pmcid, 1225 ev.pl_u.pl_x.pl_pid, 1226 (void *) ev.pl_u.pl_x.pl_entryaddr, 1227 ev.pl_u.pl_x.pl_pathname); 1228 break; 1229 case PMCLOG_TYPE_PROCEXIT: 1230 PMCSTAT_PRINT_ENTRY(a,"exitval","0x%x %d %jd", 1231 ev.pl_u.pl_e.pl_pmcid, 1232 ev.pl_u.pl_e.pl_pid, 1233 ev.pl_u.pl_e.pl_value); 1234 break; 1235 case PMCLOG_TYPE_PROCFORK: 1236 PMCSTAT_PRINT_ENTRY(a,"fork","%d %d", 1237 ev.pl_u.pl_f.pl_oldpid, 1238 ev.pl_u.pl_f.pl_newpid); 1239 break; 1240 case PMCLOG_TYPE_USERDATA: 1241 PMCSTAT_PRINT_ENTRY(a,"userdata","0x%x", 1242 ev.pl_u.pl_u.pl_userdata); 1243 break; 1244 case PMCLOG_TYPE_SYSEXIT: 1245 PMCSTAT_PRINT_ENTRY(a,"exit","%d", 1246 ev.pl_u.pl_se.pl_pid); 1247 break; 1248 default: 1249 fprintf(a->pa_printfile, "unknown %d", 1250 ev.pl_type); 1251 } 1252 } 1253 1254 if (ev.pl_state == PMCLOG_EOF) 1255 return PMCSTAT_FINISHED; 1256 else if (ev.pl_state == PMCLOG_REQUIRE_DATA) 1257 return PMCSTAT_RUNNING; 1258 1259 err(EX_DATAERR, "ERROR: event parsing failed " 1260 "(record %jd, offset 0x%jx)", 1261 (uintmax_t) ev.pl_count + 1, ev.pl_offset); 1262 /*NOTREACHED*/ 1263 } 1264 1265 /* 1266 * Process a log file in offline analysis mode. 1267 */ 1268 1269 int 1270 pmcstat_process_log(struct pmcstat_args *a) 1271 { 1272 1273 /* 1274 * If gprof style profiles haven't been asked for, just print the 1275 * log to the current output file. 1276 */ 1277 if (a->pa_flags & FLAG_DO_PRINT) 1278 return pmcstat_print_log(a); 1279 else 1280 /* convert the log to gprof compatible profiles */ 1281 return pmcstat_convert_log(a); 1282 } 1283 1284 void 1285 pmcstat_initialize_logging(struct pmcstat_args *a) 1286 { 1287 int i; 1288 const char *kernpath; 1289 struct pmcstat_image *img; 1290 1291 /* use a convenient format for 'ldd' output */ 1292 if (setenv("LD_TRACE_LOADED_OBJECTS_FMT1","%o \"%p\" %x\n",1) != 0) 1293 goto error; 1294 1295 /* Initialize hash tables */ 1296 for (i = 0; i < PMCSTAT_NHASH; i++) { 1297 LIST_INIT(&pmcstat_image_hash[i]); 1298 LIST_INIT(&pmcstat_process_hash[i]); 1299 LIST_INIT(&pmcstat_string_hash[i]); 1300 } 1301 1302 /* create a fake 'process' entry for the kernel with pid == -1 */ 1303 if ((pmcstat_kernproc = pmcstat_process_lookup((pid_t) -1, 1)) == NULL) 1304 goto error; 1305 1306 if ((kernpath = pmcstat_string_intern(a->pa_kernel)) == NULL) 1307 goto error; 1308 1309 img = pmcstat_image_from_path(kernpath); 1310 1311 pmcstat_image_get_elf_params(img); 1312 pmcstat_image_link(pmcstat_kernproc, img, img->pi_start, img->pi_end); 1313 1314 return; 1315 1316 error: 1317 err(EX_OSERR, "ERROR: Cannot initialize logging"); 1318 } 1319 1320 void 1321 pmcstat_shutdown_logging(void) 1322 { 1323 int i; 1324 struct pmcstat_gmonfile *pgf, *pgftmp; 1325 struct pmcstat_image *pi, *pitmp; 1326 struct pmcstat_process *pp, *pptmp; 1327 struct pmcstat_string *ps, *pstmp; 1328 1329 for (i = 0; i < PMCSTAT_NHASH; i++) { 1330 LIST_FOREACH_SAFE(pi, &pmcstat_image_hash[i], pi_next, pitmp) { 1331 /* flush gmon.out data to disk */ 1332 LIST_FOREACH_SAFE(pgf, &pi->pi_gmlist, pgf_next, 1333 pgftmp) { 1334 pmcstat_gmon_unmap_file(pgf); 1335 LIST_REMOVE(pgf, pgf_next); 1336 free(pgf); 1337 } 1338 1339 LIST_REMOVE(pi, pi_next); 1340 free(pi); 1341 } 1342 LIST_FOREACH_SAFE(pp, &pmcstat_process_hash[i], pp_next, 1343 pptmp) { 1344 LIST_REMOVE(pp, pp_next); 1345 free(pp); 1346 } 1347 LIST_FOREACH_SAFE(ps, &pmcstat_string_hash[i], ps_next, 1348 pstmp) { 1349 LIST_REMOVE(ps, ps_next); 1350 free(ps); 1351 } 1352 } 1353 } 1354