pmcstat_log.c (153710) | pmcstat_log.c (157144) |
---|---|
1/*- | 1/*- |
2 * Copyright (c) 2005, Joseph Koshy | 2 * Copyright (c) 2005-2006, 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 --- 8 unchanged lines hidden (view full) --- 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 | 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 --- 8 unchanged lines hidden (view full) --- 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: head/usr.sbin/pmcstat/pmcstat_log.c 153710 2005-12-25 05:11:29Z jkoshy $"); 29 | |
30/* | 27/* |
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. | 28 * Transform a hwpmc(4) log into human readable form, and into 29 * gprof(1) compatible profiles. |
46 */ 47 | 30 */ 31 |
32#include <sys/cdefs.h> 33__FBSDID("$FreeBSD: head/usr.sbin/pmcstat/pmcstat_log.c 157144 2006-03-26 12:20:54Z jkoshy $"); 34 |
|
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> --- 17 unchanged lines hidden (view full) --- 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/* | 35#include <sys/param.h> 36#include <sys/endian.h> 37#include <sys/gmon.h> 38#include <sys/imgact_aout.h> 39#include <sys/imgact_elf.h> 40#include <sys/mman.h> 41#include <sys/pmc.h> 42#include <sys/queue.h> --- 17 unchanged lines hidden (view full) --- 60#include <unistd.h> 61 62#include "pmcstat.h" 63 64#define min(A,B) ((A) < (B) ? (A) : (B)) 65#define max(A,B) ((A) > (B) ? (A) : (B)) 66 67/* |
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(). | 68 * PUBLIC INTERFACES 69 * 70 * pmcstat_initialize_logging() initialize this module, called first 71 * pmcstat_shutdown_logging() orderly shutdown, called last 72 * pmcstat_open_log() open an eventlog for processing 73 * pmcstat_process_log() print/convert an event log 74 * pmcstat_close_log() finish processing an event log 75 * 76 * IMPLEMENTATION OF GMON OUTPUT 77 * 78 * We correlate each 'sample' seen in the event log back to an 79 * executable object in the system. Executable objects include: 80 * - program executables, 81 * - shared libraries loaded by the runtime loader, 82 * - dlopen()'ed objects loaded by the program, 83 * - the runtime loader itself, 84 * - the kernel and kernel modules. 85 * 86 * Each such executable object gets one 'gmon.out' profile, per PMC in 87 * use. Creation of 'gmon.out' profiles is done lazily. The 88 * 'gmon.out' profiles generated for a given sampling PMC are 89 * aggregates of all the samples for that particular executable 90 * object. 91 * 92 * Each process that we know about is treated as a set of regions that 93 * map to executable objects. Processes are described by 94 * 'pmcstat_process' structures. Executable objects are tracked by 95 * 'pmcstat_image' structures. The kernel and kernel modules are 96 * common to all processes (they reside at the same virtual addresses 97 * for all processes). Individual processes can have their text 98 * segments and shared libraries loaded at process-specific locations. 99 * 100 * A given executable object can be in use by multiple processes 101 * (e.g., libc.so) and loaded at a different address in each. 102 * pmcstat_pcmap structures track per-image mappings. 103 * 104 * The sample log could have samples from multiple PMCs; we 105 * generate one 'gmon.out' profile per PMC. |
85 */ | 106 */ |
86struct 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 | 107 |
93static LIST_HEAD(,pmcstat_string) pmcstat_string_hash[PMCSTAT_NHASH]; | 108typedef const void *pmcstat_interned_string; |
94 95/* 96 * 'pmcstat_pmcrecord' is a mapping from PMC ids to human-readable 97 * names. 98 */ 99 100struct pmcstat_pmcrecord { 101 LIST_ENTRY(pmcstat_pmcrecord) pr_next; | 109 110/* 111 * 'pmcstat_pmcrecord' is a mapping from PMC ids to human-readable 112 * names. 113 */ 114 115struct pmcstat_pmcrecord { 116 LIST_ENTRY(pmcstat_pmcrecord) pr_next; |
102 pmc_id_t pr_pmcid; 103 const char *pr_pmcname; | 117 pmc_id_t pr_pmcid; 118 pmcstat_interned_string pr_pmcname; |
104}; 105 106static 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 115struct pmcstat_gmonfile { 116 LIST_ENTRY(pmcstat_gmonfile) pgf_next; /* list of entries */ | 119}; 120 121static LIST_HEAD(,pmcstat_pmcrecord) pmcstat_pmcs = 122 LIST_HEAD_INITIALIZER(&pmcstat_pmcs); 123 124 125/* 126 * struct pmcstat_gmonfile tracks a given 'gmon.out' file. These 127 * files are mmap()'ed in as needed. 128 */ 129 130struct pmcstat_gmonfile { 131 LIST_ENTRY(pmcstat_gmonfile) pgf_next; /* list of entries */ |
132 int pgf_overflow; /* whether a count overflowed */ |
|
117 pmc_id_t pgf_pmcid; /* id of the associated pmc */ 118 size_t pgf_nbuckets; /* #buckets in this gmon.out */ | 133 pmc_id_t pgf_pmcid; /* id of the associated pmc */ 134 size_t pgf_nbuckets; /* #buckets in this gmon.out */ |
119 const char *pgf_name; /* pathname of gmon.out file */ | 135 pmcstat_interned_string 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 | 136 size_t pgf_ndatabytes; /* number of bytes mapped */ 137 void *pgf_gmondata; /* pointer to mmap'ed data */ 138}; 139 |
124static TAILQ_HEAD(,pmcstat_gmonfile) pmcstat_gmonfiles = 125 TAILQ_HEAD_INITIALIZER(pmcstat_gmonfiles); 126 | |
127/* 128 * A 'pmcstat_image' structure describes an executable program on | 140/* 141 * A 'pmcstat_image' structure describes an executable program on |
129 * disk. 'pi_internedpath' is a cookie representing the pathname of | 142 * disk. 'pi_execpath' 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 136enum pmcstat_image_type { | 143 * the executable. 'pi_start' and 'pi_end' are the least and greatest 144 * virtual addresses for the text segments in the executable. 145 * 'pi_gmonlist' contains a linked list of gmon.out files associated 146 * with this image. 147 */ 148 149enum pmcstat_image_type { |
137 PMCSTAT_IMAGE_UNKNOWN = 0, 138 PMCSTAT_IMAGE_ELF, 139 PMCSTAT_IMAGE_AOUT | 150 PMCSTAT_IMAGE_UNKNOWN = 0, /* never looked at the image */ 151 PMCSTAT_IMAGE_INDETERMINABLE, /* can't tell what the image is */ 152 PMCSTAT_IMAGE_ELF32, /* ELF 32 bit object */ 153 PMCSTAT_IMAGE_ELF64, /* ELF 64 bit object */ 154 PMCSTAT_IMAGE_AOUT /* AOUT object */ |
140}; 141 142struct pmcstat_image { 143 LIST_ENTRY(pmcstat_image) pi_next; /* hash link */ 144 TAILQ_ENTRY(pmcstat_image) pi_lru; /* LRU list */ | 155}; 156 157struct pmcstat_image { 158 LIST_ENTRY(pmcstat_image) pi_next; /* hash link */ 159 TAILQ_ENTRY(pmcstat_image) pi_lru; /* LRU list */ |
145 const char *pi_internedpath; /* cookie */ 146 const char *pi_samplename; /* sample path name */ | 160 pmcstat_interned_string pi_execpath;/* cookie */ 161 pmcstat_interned_string pi_samplename; /* sample path name */ |
147 148 enum pmcstat_image_type pi_type; /* executable type */ | 162 163 enum pmcstat_image_type pi_type; /* executable type */ |
164 165 /* 166 * Executables have pi_start and pi_end; these are zero 167 * for shared libraries. 168 */ |
|
149 uintfptr_t pi_start; /* start address (inclusive) */ 150 uintfptr_t pi_end; /* end address (exclusive) */ 151 uintfptr_t pi_entry; /* entry address */ | 169 uintfptr_t pi_start; /* start address (inclusive) */ 170 uintfptr_t pi_end; /* end address (exclusive) */ 171 uintfptr_t pi_entry; /* entry address */ |
152 int pi_isdynamic; /* whether a dynamic object */ 153 const char *pi_dynlinkerpath; /* path in .interp section */ | 172 uintfptr_t pi_vaddr; /* virtual address where loaded */ 173 int pi_isdynamic; /* whether a dynamic 174 * object */ 175 int pi_iskernelmodule; 176 pmcstat_interned_string pi_dynlinkerpath; /* path in .interp */ |
154 | 177 |
178 /* 179 * An image can be associated with one or more gmon.out files; 180 * one per PMC. 181 */ |
|
155 LIST_HEAD(,pmcstat_gmonfile) pi_gmlist; 156}; 157 | 182 LIST_HEAD(,pmcstat_gmonfile) pi_gmlist; 183}; 184 |
185/* 186 * All image descriptors are kept in a hash table. 187 */ |
|
158static LIST_HEAD(,pmcstat_image) pmcstat_image_hash[PMCSTAT_NHASH]; 159static TAILQ_HEAD(,pmcstat_image) pmcstat_image_lru = 160 TAILQ_HEAD_INITIALIZER(pmcstat_image_lru); 161 | 188static LIST_HEAD(,pmcstat_image) pmcstat_image_hash[PMCSTAT_NHASH]; 189static TAILQ_HEAD(,pmcstat_image) pmcstat_image_lru = 190 TAILQ_HEAD_INITIALIZER(pmcstat_image_lru); 191 |
192/* 193 * A 'pmcstat_pcmap' structure maps a virtual address range to an 194 * underlying 'pmcstat_image' descriptor. 195 */ |
|
162struct 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/* | 196struct pmcstat_pcmap { 197 TAILQ_ENTRY(pmcstat_pcmap) ppm_next; 198 uintfptr_t ppm_lowpc; 199 uintfptr_t ppm_highpc; 200 struct pmcstat_image *ppm_image; 201}; 202 203/* |
170 * A 'pmcstat_process' structure tracks processes. | 204 * A 'pmcstat_process' structure models processes. Each process is 205 * associated with a set of pmcstat_pcmap structures that map 206 * addresses inside it to executable objects. This set is implemented 207 * as a list, kept sorted in ascending order of mapped addresses. 208 * 209 * 'pp_pid' holds the pid of the process. When a process exits, the 210 * 'pp_isactive' field is set to zero, but the process structure is 211 * not immediately reclaimed because there may still be samples in the 212 * log for this process. |
171 */ 172 173struct 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 | 213 */ 214 215struct pmcstat_process { 216 LIST_ENTRY(pmcstat_process) pp_next; /* hash-next */ 217 pid_t pp_pid; /* associated pid */ 218 int pp_isactive; /* whether active */ 219 uintfptr_t pp_entryaddr; /* entry address */ 220 TAILQ_HEAD(,pmcstat_pcmap) pp_map; /* address range map */ 221}; 222 |
223#define PMCSTAT_ALLOCATE 1 224 225/* 226 * All process descriptors are kept in a hash table. 227 */ |
|
181static LIST_HEAD(,pmcstat_process) pmcstat_process_hash[PMCSTAT_NHASH]; 182 183static struct pmcstat_process *pmcstat_kernproc; /* kernel 'process' */ 184 | 228static LIST_HEAD(,pmcstat_process) pmcstat_process_hash[PMCSTAT_NHASH]; 229 230static struct pmcstat_process *pmcstat_kernproc; /* kernel 'process' */ 231 |
232/* Misc. statistics */ 233static struct pmcstat_stats { 234 int ps_exec_aout; /* # a.out executables seen */ 235 int ps_exec_elf; /* # elf executables seen */ 236 int ps_exec_errors; /* # errors processing executables */ 237 int ps_exec_indeterminable; /* # unknown executables seen */ 238 int ps_samples_total; /* total number of samples processed */ 239 int ps_samples_unknown_offset; /* #samples not in any map */ 240 int ps_samples_indeterminable; /* #samples in indeterminable images */ 241} pmcstat_stats; 242 |
|
185/* 186 * Prototypes 187 */ 188 189static void pmcstat_gmon_create_file(struct pmcstat_gmonfile *_pgf, 190 struct pmcstat_image *_image); | 243/* 244 * Prototypes 245 */ 246 247static void pmcstat_gmon_create_file(struct pmcstat_gmonfile *_pgf, 248 struct pmcstat_image *_image); |
191static const char *pmcstat_gmon_create_name(const char *_sd, | 249static pmcstat_interned_string pmcstat_gmon_create_name(const char *_sd, |
192 struct pmcstat_image *_img, pmc_id_t _pmcid); 193static void pmcstat_gmon_map_file(struct pmcstat_gmonfile *_pgf); 194static void pmcstat_gmon_unmap_file(struct pmcstat_gmonfile *_pgf); 195 | 250 struct pmcstat_image *_img, pmc_id_t _pmcid); 251static void pmcstat_gmon_map_file(struct pmcstat_gmonfile *_pgf); 252static void pmcstat_gmon_unmap_file(struct pmcstat_gmonfile *_pgf); 253 |
196static struct pmcstat_image *pmcstat_image_from_path(const char *_path); 197static enum pmcstat_image_type pmcstat_image_get_type(const char *_p); 198static void pmcstat_image_get_elf_params(struct pmcstat_image *_image); | 254static void pmcstat_image_determine_type(struct pmcstat_image *_image, 255 struct pmcstat_args *_a); 256static struct pmcstat_image *pmcstat_image_from_path(pmcstat_interned_string 257 _path, int _iskernelmodule); 258static void pmcstat_image_get_aout_params(struct pmcstat_image *_image, 259 struct pmcstat_args *_a); 260static void pmcstat_image_get_elf_params(struct pmcstat_image *_image, 261 struct pmcstat_args *_a); |
199static void pmcstat_image_increment_bucket(struct pmcstat_pcmap *_pcm, 200 uintfptr_t _pc, pmc_id_t _pmcid, struct pmcstat_args *_a); 201static void pmcstat_image_link(struct pmcstat_process *_pp, | 262static void pmcstat_image_increment_bucket(struct pmcstat_pcmap *_pcm, 263 uintfptr_t _pc, pmc_id_t _pmcid, struct pmcstat_args *_a); 264static void pmcstat_image_link(struct pmcstat_process *_pp, |
202 struct pmcstat_image *_i, uintfptr_t _lpc, uintfptr_t _hpc); | 265 struct pmcstat_image *_i, uintfptr_t _lpc); |
203 | 266 |
204static void pmcstat_pmcid_add(pmc_id_t _pmcid, const char *_name, 205 struct pmcstat_args *_a); | 267static void pmcstat_pmcid_add(pmc_id_t _pmcid, 268 pmcstat_interned_string _name, struct pmcstat_args *_a); |
206static const char *pmcstat_pmcid_to_name(pmc_id_t _pmcid); 207 | 269static const char *pmcstat_pmcid_to_name(pmc_id_t _pmcid); 270 |
208static void pmcstat_process_add_elf_image(struct pmcstat_process *_pp, 209 const char *_path, uintfptr_t _entryaddr); | 271static void pmcstat_process_aout_exec(struct pmcstat_process *_pp, 272 struct pmcstat_image *_image, uintfptr_t _entryaddr, 273 struct pmcstat_args *_a); 274static void pmcstat_process_elf_exec(struct pmcstat_process *_pp, 275 struct pmcstat_image *_image, uintfptr_t _entryaddr, 276 struct pmcstat_args *_a); |
210static void pmcstat_process_exec(struct pmcstat_process *_pp, | 277static void pmcstat_process_exec(struct pmcstat_process *_pp, |
211 const char *_path, uintfptr_t _entryaddr); 212static struct pmcstat_process *pmcstat_process_lookup(pid_t _pid, int _allocate); | 278 pmcstat_interned_string _path, uintfptr_t _entryaddr, 279 struct pmcstat_args *_ao); 280static struct pmcstat_process *pmcstat_process_lookup(pid_t _pid, 281 int _allocate); |
213static struct pmcstat_pcmap *pmcstat_process_find_map( 214 struct pmcstat_process *_p, uintfptr_t _pc); 215 216static int pmcstat_string_compute_hash(const char *_string); | 282static struct pmcstat_pcmap *pmcstat_process_find_map( 283 struct pmcstat_process *_p, uintfptr_t _pc); 284 285static int pmcstat_string_compute_hash(const char *_string); |
217static const char *pmcstat_string_intern(const char *_s); 218static struct pmcstat_string *pmcstat_string_lookup(const char *_s); | 286static void pmcstat_string_initialize(void); 287static pmcstat_interned_string pmcstat_string_intern(const char *_s); 288static pmcstat_interned_string pmcstat_string_lookup(const char *_s); 289static int pmcstat_string_lookup_hash(pmcstat_interned_string _is); 290static void pmcstat_string_shutdown(void); 291static const char *pmcstat_string_unintern(pmcstat_interned_string _is); |
219 220 221/* | 292 293 294/* |
295 * A simple implementation of interned strings. Each interned string 296 * is assigned a unique address, so that subsequent string compares 297 * can be done by a simple pointer comparision instead of using 298 * strcmp(). This speeds up hash table lookups and saves memory if 299 * duplicate strings are the norm. 300 */ 301struct pmcstat_string { 302 LIST_ENTRY(pmcstat_string) ps_next; /* hash link */ 303 int ps_len; 304 int ps_hash; 305 char *ps_string; 306}; 307 308static LIST_HEAD(,pmcstat_string) pmcstat_string_hash[PMCSTAT_NHASH]; 309 310/* 311 * Compute a 'hash' value for a string. 312 */ 313 314static int 315pmcstat_string_compute_hash(const char *s) 316{ 317 int hash; 318 319 for (hash = 0; *s; s++) 320 hash ^= *s; 321 322 return (hash & PMCSTAT_HASH_MASK); 323} 324 325/* 326 * Intern a copy of string 's', and return a pointer to the 327 * interned structure. 328 */ 329 330static pmcstat_interned_string 331pmcstat_string_intern(const char *s) 332{ 333 struct pmcstat_string *ps; 334 const struct pmcstat_string *cps; 335 int hash, len; 336 337 if ((cps = pmcstat_string_lookup(s)) != NULL) 338 return (cps); 339 340 hash = pmcstat_string_compute_hash(s); 341 len = strlen(s); 342 343 if ((ps = malloc(sizeof(*ps))) == NULL) 344 err(EX_OSERR, "ERROR: Could not intern string"); 345 ps->ps_len = len; 346 ps->ps_hash = hash; 347 ps->ps_string = strdup(s); 348 LIST_INSERT_HEAD(&pmcstat_string_hash[hash], ps, ps_next); 349 return ((pmcstat_interned_string) ps); 350} 351 352static const char * 353pmcstat_string_unintern(pmcstat_interned_string str) 354{ 355 const char *s; 356 357 s = ((const struct pmcstat_string *) str)->ps_string; 358 return (s); 359} 360 361static pmcstat_interned_string 362pmcstat_string_lookup(const char *s) 363{ 364 struct pmcstat_string *ps; 365 int hash, len; 366 367 hash = pmcstat_string_compute_hash(s); 368 len = strlen(s); 369 370 LIST_FOREACH(ps, &pmcstat_string_hash[hash], ps_next) 371 if (ps->ps_len == len && ps->ps_hash == hash && 372 strcmp(ps->ps_string, s) == 0) 373 return (ps); 374 return (NULL); 375} 376 377static int 378pmcstat_string_lookup_hash(pmcstat_interned_string s) 379{ 380 const struct pmcstat_string *ps; 381 382 ps = (const struct pmcstat_string *) s; 383 return (ps->ps_hash); 384} 385 386/* 387 * Initialize the string interning facility. 388 */ 389 390static void 391pmcstat_string_initialize(void) 392{ 393 int i; 394 395 for (i = 0; i < PMCSTAT_NHASH; i++) 396 LIST_INIT(&pmcstat_string_hash[i]); 397} 398 399/* 400 * Destroy the string table, free'ing up space. 401 */ 402 403static void 404pmcstat_string_shutdown(void) 405{ 406 int i; 407 struct pmcstat_string *ps, *pstmp; 408 409 for (i = 0; i < PMCSTAT_NHASH; i++) 410 LIST_FOREACH_SAFE(ps, &pmcstat_string_hash[i], ps_next, 411 pstmp) { 412 LIST_REMOVE(ps, ps_next); 413 free(ps->ps_string); 414 free(ps); 415 } 416} 417 418/* |
|
222 * Create a gmon.out file and size it. 223 */ 224 225static void 226pmcstat_gmon_create_file(struct pmcstat_gmonfile *pgf, 227 struct pmcstat_image *image) 228{ 229 int fd; 230 size_t count; 231 struct gmonhdr gm; | 419 * Create a gmon.out file and size it. 420 */ 421 422static void 423pmcstat_gmon_create_file(struct pmcstat_gmonfile *pgf, 424 struct pmcstat_image *image) 425{ 426 int fd; 427 size_t count; 428 struct gmonhdr gm; |
429 const char *pathname; |
|
232 char buffer[DEFAULT_BUFFER_SIZE]; 233 | 430 char buffer[DEFAULT_BUFFER_SIZE]; 431 |
234 if ((fd = open(pgf->pgf_name, O_RDWR|O_NOFOLLOW|O_CREAT, | 432 pathname = pmcstat_string_unintern(pgf->pgf_name); 433 if ((fd = open(pathname, O_RDWR|O_NOFOLLOW|O_CREAT, |
235 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) | 434 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) |
236 err(EX_OSERR, "ERROR: Cannot open \"%s\"", pgf->pgf_name); | 435 err(EX_OSERR, "ERROR: Cannot open \"%s\"", pathname); |
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() */ --- 11 unchanged lines hidden (view full) --- 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 | 436 437 gm.lpc = image->pi_start; 438 gm.hpc = image->pi_end; 439 gm.ncnt = (pgf->pgf_nbuckets * sizeof(HISTCOUNTER)) + 440 sizeof(struct gmonhdr); 441 gm.version = GMONVERSION; 442 gm.profrate = 0; /* use ticks */ 443 gm.histcounter_type = 0; /* compatibility with moncontrol() */ --- 11 unchanged lines hidden (view full) --- 455 if (write(fd, &buffer, sizeof(buffer)) < 0) 456 goto error; 457 count -= sizeof(buffer); 458 } 459 460 if (write(fd, &buffer, count) < 0) 461 goto error; 462 |
463 /* TODO size the arc table */ 464 |
|
264 (void) close(fd); 265 266 return; 267 268 error: | 465 (void) close(fd); 466 467 return; 468 469 error: |
269 err(EX_OSERR, "ERROR: Cannot write \"%s\"", pgf->pgf_name); | 470 err(EX_OSERR, "ERROR: Cannot write \"%s\"", pathname); |
270} 271 | 471} 472 |
272const char * | 473/* 474 * Determine the full pathname of a gmon.out file for a given 475 * (image,pmcid) combination. Return the interned string. 476 */ 477 478pmcstat_interned_string |
273pmcstat_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), | 479pmcstat_gmon_create_name(const char *samplesdir, struct pmcstat_image *image, 480 pmc_id_t pmcid) 481{ 482 const char *pmcname; 483 char fullpath[PATH_MAX]; 484 485 pmcname = pmcstat_pmcid_to_name(pmcid); 486 487 (void) snprintf(fullpath, sizeof(fullpath), |
282 "%s/%s/%s", samplesdir, pmcname, image->pi_samplename); | 488 "%s/%s/%s", samplesdir, pmcname, 489 pmcstat_string_unintern(image->pi_samplename)); |
283 | 490 |
284 return pmcstat_string_intern(fullpath); | 491 return (pmcstat_string_intern(fullpath)); |
285} 286 287 | 492} 493 494 |
495/* 496 * Mmap in a gmon.out file for processing. 497 */ 498 |
|
288static void 289pmcstat_gmon_map_file(struct pmcstat_gmonfile *pgf) 290{ 291 int fd; | 499static void 500pmcstat_gmon_map_file(struct pmcstat_gmonfile *pgf) 501{ 502 int fd; |
503 const char *pathname; |
|
292 | 504 |
505 pathname = pmcstat_string_unintern(pgf->pgf_name); 506 |
|
293 /* the gmon.out file must already exist */ | 507 /* 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); | 508 if ((fd = open(pathname, O_RDWR | O_NOFOLLOW, 0)) < 0) 509 err(EX_OSERR, "ERROR: cannot open \"%s\"", pathname); |
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) | 510 511 pgf->pgf_gmondata = mmap(NULL, pgf->pgf_ndatabytes, 512 PROT_READ|PROT_WRITE, MAP_NOSYNC|MAP_SHARED, fd, 0); 513 514 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); | 515 err(EX_OSERR, "ERROR: cannot map \"%s\"", pathname); |
304 305 (void) close(fd); 306} 307 308/* | 516 517 (void) close(fd); 518} 519 520/* |
309 * Unmap the data mapped from a gmon.out file. | 521 * Unmap a gmon.out file after sync'ing its data to disk. |
310 */ 311 312static void 313pmcstat_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 | 522 */ 523 524static void 525pmcstat_gmon_unmap_file(struct pmcstat_gmonfile *pgf) 526{ 527 (void) msync(pgf->pgf_gmondata, pgf->pgf_ndatabytes, 528 MS_SYNC); 529 (void) munmap(pgf->pgf_gmondata, pgf->pgf_ndatabytes); 530 pgf->pgf_gmondata = NULL; 531} 532 |
533/* 534 * Determine whether a given executable image is an A.OUT object, and 535 * if so, fill in its parameters from the text file. 536 * Sets image->pi_type. 537 */ 538 |
|
321static void | 539static void |
322pmcstat_image_get_elf_params(struct pmcstat_image *image) | 540pmcstat_image_get_aout_params(struct pmcstat_image *image, 541 struct pmcstat_args *a) |
323{ | 542{ |
543 int fd; 544 ssize_t nbytes; 545 struct exec ex; 546 const char *path; 547 char buffer[PATH_MAX]; 548 549 path = pmcstat_string_unintern(image->pi_execpath); 550 assert(path != NULL); 551 552 if (image->pi_iskernelmodule) 553 errx(EX_SOFTWARE, "ERROR: a.out kernel modules are " 554 "unsupported \"%s\"", path); 555 556 (void) snprintf(buffer, sizeof(buffer), "%s%s", 557 a->pa_fsroot, path); 558 559 if ((fd = open(buffer, O_RDONLY, 0)) < 0 || 560 (nbytes = read(fd, &ex, sizeof(ex))) < 0) { 561 warn("WARNING: Cannot determine type of \"%s\"", path); 562 image->pi_type = PMCSTAT_IMAGE_INDETERMINABLE; 563 if (fd != -1) 564 (void) close(fd); 565 return; 566 } 567 568 (void) close(fd); 569 570 if ((unsigned) nbytes != sizeof(ex) || 571 N_BADMAG(ex)) 572 return; 573 574 image->pi_type = PMCSTAT_IMAGE_AOUT; 575 576 /* TODO: the rest of a.out processing */ 577 578 return; 579} 580 581/* 582 * Examine an ELF file to determine the size of its text segment. 583 * Sets image->pi_type if anything conclusive can be determined about 584 * this image. 585 */ 586 587static void 588pmcstat_image_get_elf_params(struct pmcstat_image *image, 589 struct pmcstat_args *a) 590{ |
|
324 int fd, i; | 591 int fd, i; |
325 struct stat st; | 592 const char *path; |
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 | 593 void *mapbase; 594 uintfptr_t minva, maxva; 595 const Elf_Ehdr *h; 596 const Elf_Phdr *ph; 597 const Elf_Shdr *sh; 598#if defined(__amd64__) 599 const Elf32_Ehdr *h32; 600 const Elf32_Phdr *ph32; 601 const Elf32_Shdr *sh32; 602#endif |
336 const char *path; | 603 enum pmcstat_image_type image_type; 604 struct stat st; 605 char buffer[PATH_MAX]; |
337 338 assert(image->pi_type == PMCSTAT_IMAGE_UNKNOWN); 339 340 minva = ~(uintfptr_t) 0; 341 maxva = (uintfptr_t) 0; | 606 607 assert(image->pi_type == PMCSTAT_IMAGE_UNKNOWN); 608 609 minva = ~(uintfptr_t) 0; 610 maxva = (uintfptr_t) 0; |
342 path = image->pi_internedpath; | 611 path = pmcstat_string_unintern(image->pi_execpath); |
343 | 612 |
344 if ((fd = open(path, O_RDONLY, 0)) < 0) 345 err(EX_OSERR, "ERROR: Cannot open \"%s\"", path); | 613 assert(path != NULL); |
346 | 614 |
347 if (fstat(fd, &st) < 0) 348 err(EX_OSERR, "ERROR: Cannot stat \"%s\"", path); | 615 /* 616 * Look for kernel modules under FSROOT/KERNELPATH/NAME, 617 * and user mode executable objects under FSROOT/PATHNAME. 618 */ 619 if (image->pi_iskernelmodule) 620 (void) snprintf(buffer, sizeof(buffer), "%s%s/%s", 621 a->pa_fsroot, a->pa_kernel, path); 622 else 623 (void) snprintf(buffer, sizeof(buffer), "%s%s", 624 a->pa_fsroot, path); |
349 | 625 |
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); | 626 if ((fd = open(buffer, O_RDONLY, 0)) < 0 || 627 fstat(fd, &st) < 0 || 628 (mapbase = mmap(0, st.st_size, PROT_READ, MAP_SHARED, 629 fd, 0)) == MAP_FAILED) { 630 warn("WARNING: Cannot determine type of \"%s\"", buffer); 631 image->pi_type = PMCSTAT_IMAGE_INDETERMINABLE; 632 if (fd != -1) 633 (void) close(fd); 634 return; 635 } |
353 354 (void) close(fd); 355 | 636 637 (void) close(fd); 638 |
639 /* Punt on non-ELF objects */ |
|
356 h = (const Elf_Ehdr *) mapbase; 357 if (!IS_ELF(*h)) | 640 h = (const Elf_Ehdr *) mapbase; 641 if (!IS_ELF(*h)) |
358 err(EX_SOFTWARE, "ERROR: \"%s\" not an ELF file", path); | 642 return; |
359 | 643 |
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); | 644 /* 645 * We only handle executable ELF objects and kernel 646 * modules. 647 */ 648 if (h->e_type != ET_EXEC && h->e_type != ET_DYN && 649 !(image->pi_iskernelmodule && h->e_type == ET_REL)) 650 return; |
364 | 651 |
652 image->pi_isdynamic = 0; 653 image->pi_dynlinkerpath = NULL; 654 image->pi_vaddr = 0; 655 |
|
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( \ | 656#define GET_VA(H, SH, MINVA, MAXVA) do { \ 657 for (i = 0; i < (H)->e_shnum; i++) \ 658 if ((SH)[i].sh_flags & SHF_EXECINSTR) { \ 659 (MINVA) = min((MINVA),(SH)[i].sh_addr); \ 660 (MAXVA) = max((MAXVA),(SH)[i].sh_addr + \ 661 (SH)[i].sh_size); \ 662 } \ 663 } while (0) 664 665 666#define GET_PHDR_INFO(H, PH, IMAGE) do { \ 667 for (i = 0; i < (H)->e_phnum; i++) { \ 668 switch ((PH)[i].p_type) { \ 669 case PT_DYNAMIC: \ 670 image->pi_isdynamic = 1; \ 671 break; \ 672 case PT_INTERP: \ 673 image->pi_dynlinkerpath = \ 674 pmcstat_string_intern( \ |
384 (char *) mapbase + \ | 675 (char *) mapbase + \ |
385 (PH)[i].p_offset); \ 386 break; \ | 676 (PH)[i].p_offset); \ 677 break; \ |
678 case PT_LOAD: \ 679 if ((PH)[i].p_offset == 0) \ 680 image->pi_vaddr = \ 681 (PH)[i].p_vaddr; \ 682 break; \ |
|
387 } \ 388 } \ 389 } while (0) 390 | 683 } \ 684 } \ 685 } while (0) 686 |
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 } | 687 switch (h->e_machine) { 688 case EM_386: 689 case EM_486: 690#if defined(__amd64__) 691 /* a 32 bit executable */ 692 h32 = (const Elf32_Ehdr *) h; 693 sh32 = (const Elf32_Shdr *)((uintptr_t) mapbase + h32->e_shoff); 694 695 GET_VA(h32, sh32, minva, maxva); 696 697 image->pi_entry = h32->e_entry; 698 699 if (h32->e_type == ET_EXEC) { 700 ph32 = (const Elf32_Phdr *)((uintptr_t) mapbase + 701 h32->e_phoff); 702 GET_PHDR_INFO(h32, ph32, image); 703 } |
704 image_type = PMCSTAT_IMAGE_ELF32; |
|
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 } | 705 break; 706#endif 707 default: 708 sh = (const Elf_Shdr *)((uintptr_t) mapbase + h->e_shoff); 709 710 GET_VA(h, sh, minva, maxva); 711 712 image->pi_entry = h->e_entry; 713 714 if (h->e_type == ET_EXEC) { 715 ph = (const Elf_Phdr *)((uintptr_t) mapbase + 716 h->e_phoff); 717 GET_PHDR_INFO(h, ph, image); 718 } |
719 image_type = PMCSTAT_IMAGE_ELF64; |
|
426 break; 427 } 428 429#undef GET_PHDR_INFO 430#undef GET_VA 431 432 image->pi_start = minva; | 720 break; 721 } 722 723#undef GET_PHDR_INFO 724#undef GET_VA 725 726 image->pi_start = minva; |
433 image->pi_end = maxva; | 727 image->pi_end = maxva; 728 image->pi_type = image_type; |
434 435 if (munmap(mapbase, st.st_size) < 0) 436 err(EX_OSERR, "ERROR: Cannot unmap \"%s\"", path); | 729 730 if (munmap(mapbase, st.st_size) < 0) 731 err(EX_OSERR, "ERROR: Cannot unmap \"%s\"", path); |
732 return; 733} |
|
437 | 734 |
735/* 736 * Given an image descriptor, determine whether it is an ELF, or AOUT. 737 * If no handler claims the image, set its type to 'INDETERMINABLE'. 738 */ 739 740static void 741pmcstat_image_determine_type(struct pmcstat_image *image, 742 struct pmcstat_args *a) 743{ 744 assert(image->pi_type == PMCSTAT_IMAGE_UNKNOWN); 745 746 /* Try each kind of handler in turn */ 747 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) 748 pmcstat_image_get_elf_params(image, a); 749 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) 750 pmcstat_image_get_aout_params(image, a); 751 752 /* 753 * Otherwise, remember that we tried to determine 754 * the object's type and had failed. 755 */ 756 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) 757 image->pi_type = PMCSTAT_IMAGE_INDETERMINABLE; |
|
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. | 758} 759 760/* 761 * Locate an image descriptor given an interned path, adding a fresh 762 * descriptor to the cache if necessary. This function also finds a 763 * suitable name for this image's sample file. |
764 * 765 * We defer filling in the file format specific parts of the image 766 * structure till the time we actually see a sample that would fall 767 * into this image. |
|
444 */ 445 446static struct pmcstat_image * | 768 */ 769 770static struct pmcstat_image * |
447pmcstat_image_from_path(const char *internedpath) | 771pmcstat_image_from_path(pmcstat_interned_string internedpath, 772 int iskernelmodule) |
448{ 449 int count, hash, nlen; 450 struct pmcstat_image *pi; 451 char *sn; 452 char name[NAME_MAX]; 453 | 773{ 774 int count, hash, nlen; 775 struct pmcstat_image *pi; 776 char *sn; 777 char name[NAME_MAX]; 778 |
454 hash = pmcstat_string_compute_hash(internedpath); | 779 hash = pmcstat_string_lookup_hash(internedpath); |
455 | 780 |
456 /* Look for an existing entry. */ | 781 /* First, look for an existing entry. */ |
457 LIST_FOREACH(pi, &pmcstat_image_hash[hash], pi_next) | 782 LIST_FOREACH(pi, &pmcstat_image_hash[hash], pi_next) |
458 if (pi->pi_internedpath == internedpath) { | 783 if (pi->pi_execpath == internedpath && 784 pi->pi_iskernelmodule == iskernelmodule) { |
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); | 785 /* move descriptor to the head of the lru list */ 786 TAILQ_REMOVE(&pmcstat_image_lru, pi, pi_lru); 787 TAILQ_INSERT_HEAD(&pmcstat_image_lru, pi, pi_lru); |
462 return pi; | 788 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) | 789 } 790 791 /* 792 * Allocate a new entry and place at the head of the hash and 793 * LRU lists. 794 */ 795 pi = malloc(sizeof(*pi)); 796 if (pi == NULL) |
471 return NULL; | 797 return (NULL); |
472 473 pi->pi_type = PMCSTAT_IMAGE_UNKNOWN; | 798 799 pi->pi_type = PMCSTAT_IMAGE_UNKNOWN; |
474 pi->pi_internedpath = internedpath; | 800 pi->pi_execpath = internedpath; |
475 pi->pi_start = ~0; 476 pi->pi_entry = ~0; 477 pi->pi_end = 0; | 801 pi->pi_start = ~0; 802 pi->pi_entry = ~0; 803 pi->pi_end = 0; |
804 pi->pi_iskernelmodule = iskernelmodule; |
|
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 */ | 805 806 /* 807 * Look for a suitable name for the sample files associated 808 * with this image: if `basename(path)`+".gmon" is available, 809 * we use that, otherwise we try iterating through 810 * `basename(path)`+ "~" + NNN + ".gmon" till we get a free 811 * entry. 812 */ |
486 if ((sn = basename(internedpath)) == NULL) 487 err(EX_OSERR, "ERROR: Cannot process \"%s\"", internedpath); | 813 if ((sn = basename(pmcstat_string_unintern(internedpath))) == NULL) 814 err(EX_OSERR, "ERROR: Cannot process \"%s\"", 815 pmcstat_string_unintern(internedpath)); |
488 489 nlen = strlen(sn); | 816 817 nlen = strlen(sn); |
490 nlen = min(nlen, (int) sizeof(name) - 6); /* ".gmon\0" */ | 818 nlen = min(nlen, (int) (sizeof(name) - sizeof(".gmon"))); |
491 492 snprintf(name, sizeof(name), "%.*s.gmon", nlen, sn); 493 | 819 820 snprintf(name, sizeof(name), "%.*s.gmon", nlen, sn); 821 |
822 /* try use the unabridged name first */ |
|
494 if (pmcstat_string_lookup(name) == NULL) 495 pi->pi_samplename = pmcstat_string_intern(name); 496 else { | 823 if (pmcstat_string_lookup(name) == NULL) 824 pi->pi_samplename = pmcstat_string_intern(name); 825 else { |
826 /* 827 * Otherwise use a prefix from the original name and 828 * upto 3 digits. 829 */ |
|
497 nlen = strlen(sn); | 830 nlen = strlen(sn); |
498 nlen = min(nlen, (int) sizeof(name)-10); /* "~ddd.gmon\0" */ | 831 nlen = min(nlen, (int) (sizeof(name)-sizeof("~NNN.gmon"))); |
499 count = 0; 500 do { | 832 count = 0; 833 do { |
501 count++; 502 snprintf(name, sizeof(name), "%.*s~%3.3d", | 834 if (++count > 999) 835 errx(EX_CANTCREAT, "ERROR: cannot create a gmon " 836 "file for \"%s\"", name); 837 snprintf(name, sizeof(name), "%.*s~%3.3d.gmon", |
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 | 838 nlen, sn, count); 839 if (pmcstat_string_lookup(name) == NULL) { 840 pi->pi_samplename = pmcstat_string_intern(name); 841 count = 0; 842 } 843 } while (count > 0); 844 } 845 |
846 |
|
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 | 847 LIST_INIT(&pi->pi_gmlist); 848 849 LIST_INSERT_HEAD(&pmcstat_image_hash[hash], pi, pi_next); 850 TAILQ_INSERT_HEAD(&pmcstat_image_lru, pi, pi_lru); 851 |
516 return pi; | 852 return (pi); |
517} 518 519/* | 853} 854 855/* |
520 * Given an open file, determine its file type. 521 */ 522 523static enum pmcstat_image_type 524pmcstat_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 563static void 564pmcstat_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 | 856 * Increment the bucket in the gmon.out file corresponding to 'pmcid' 857 * and 'pc'. 858 */ 859 860static void 861pmcstat_image_increment_bucket(struct pmcstat_pcmap *map, uintfptr_t pc, 862 pmc_id_t pmcid, struct pmcstat_args *a) 863{ 864 struct pmcstat_image *image; 865 struct pmcstat_gmonfile *pgf; 866 uintfptr_t bucket; 867 HISTCOUNTER *hc; 868 869 assert(pc >= map->ppm_lowpc && pc < map->ppm_highpc); 870 |
871 image = map->ppm_image; 872 |
|
574 /* | 873 /* |
575 * Find the gmon file corresponding to 'pmcid', creating it if 576 * needed. | 874 * If this is the first time we are seeing a sample for 875 * this executable image, try determine its parameters. |
577 */ | 876 */ |
877 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) 878 pmcstat_image_determine_type(image, a); |
|
578 | 879 |
579 image = map->ppm_image; | 880 assert(image->pi_type != PMCSTAT_IMAGE_UNKNOWN); |
580 | 881 |
882 /* Ignore samples in images that we know nothing about. */ 883 if (image->pi_type == PMCSTAT_IMAGE_INDETERMINABLE) { 884 pmcstat_stats.ps_samples_indeterminable++; 885 return; 886 } 887 888 /* 889 * Find the gmon file corresponding to 'pmcid', creating it if 890 * needed. 891 */ |
|
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:"); --- 15 unchanged lines hidden (view full) --- 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 | 892 LIST_FOREACH(pgf, &image->pi_gmlist, pgf_next) 893 if (pgf->pgf_pmcid == pmcid) 894 break; 895 896 /* If we don't have a gmon.out file for this PMCid, create one */ 897 if (pgf == NULL) { 898 if ((pgf = calloc(1, sizeof(*pgf))) == NULL) 899 err(EX_OSERR, "ERROR:"); --- 15 unchanged lines hidden (view full) --- 915 916 /* 917 * Map the gmon file in if needed. It may have been mapped 918 * out under memory pressure. 919 */ 920 if (pgf->pgf_gmondata == NULL) 921 pmcstat_gmon_map_file(pgf); 922 |
923 assert(pgf->pgf_gmondata != NULL); 924 925 /* 926 * 927 */ 928 |
|
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 */ | 929 bucket = (pc - map->ppm_lowpc) / FUNCTION_ALIGNMENT; 930 931 assert(bucket < pgf->pgf_nbuckets); 932 933 hc = (HISTCOUNTER *) ((uintptr_t) pgf->pgf_gmondata + 934 sizeof(struct gmonhdr)); 935 936 /* saturating add */ |
620 if (hc[bucket] < 0xFFFF) | 937 if (hc[bucket] < 0xFFFFU) /* XXX tie this to sizeof(HISTCOUNTER) */ |
621 hc[bucket]++; | 938 hc[bucket]++; |
622 | 939 else /* mark that an overflow occurred */ 940 pgf->pgf_overflow = 1; |
623} 624 625/* | 941} 942 943/* |
626 * Record the fact that PC values from 'lowpc' to 'highpc' come from | 944 * Record the fact that PC values from 'start' to 'end' come from |
627 * image 'image'. 628 */ 629 630static void 631pmcstat_image_link(struct pmcstat_process *pp, struct pmcstat_image *image, | 945 * image 'image'. 946 */ 947 948static void 949pmcstat_image_link(struct pmcstat_process *pp, struct pmcstat_image *image, |
632 uintfptr_t lowpc, uintfptr_t highpc) | 950 uintfptr_t start) |
633{ 634 struct pmcstat_pcmap *pcm, *pcmnew; | 951{ 952 struct pmcstat_pcmap *pcm, *pcmnew; |
953 uintfptr_t offset; |
|
635 | 954 |
955 assert(image->pi_type != PMCSTAT_IMAGE_UNKNOWN && 956 image->pi_type != PMCSTAT_IMAGE_INDETERMINABLE); 957 |
|
636 if ((pcmnew = malloc(sizeof(*pcmnew))) == NULL) | 958 if ((pcmnew = malloc(sizeof(*pcmnew))) == NULL) |
637 err(EX_OSERR, "ERROR: "); | 959 err(EX_OSERR, "ERROR: Cannot create a map entry"); |
638 | 960 |
639 pcmnew->ppm_lowpc = lowpc; 640 pcmnew->ppm_highpc = highpc; | 961 /* 962 * Adjust the map entry to only cover the text portion 963 * of the object. 964 */ 965 966 offset = start - image->pi_vaddr; 967 pcmnew->ppm_lowpc = image->pi_start + offset; 968 pcmnew->ppm_highpc = image->pi_end + offset; |
641 pcmnew->ppm_image = image; 642 | 969 pcmnew->ppm_image = image; 970 |
971 assert(pcmnew->ppm_lowpc < pcmnew->ppm_highpc); 972 973 /* Overlapped mmap()'s are assumed to never occur. */ |
|
643 TAILQ_FOREACH(pcm, &pp->pp_map, ppm_next) | 974 TAILQ_FOREACH(pcm, &pp->pp_map, ppm_next) |
644 if (pcm->ppm_lowpc < lowpc) | 975 if (pcm->ppm_lowpc >= pcmnew->ppm_highpc) |
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/* | 976 break; 977 978 if (pcm == NULL) 979 TAILQ_INSERT_TAIL(&pp->pp_map, pcmnew, ppm_next); 980 else 981 TAILQ_INSERT_BEFORE(pcm, pcmnew, ppm_next); 982} 983 984/* |
985 * Unmap images in the range [start..end) associated with process 986 * 'pp'. 987 */ 988 989static void 990pmcstat_image_unmap(struct pmcstat_process *pp, uintfptr_t start, 991 uintfptr_t end) 992{ 993 struct pmcstat_pcmap *pcm, *pcmtmp, *pcmnew; 994 995 assert(pp != NULL); 996 assert(start < end); 997 998 /* 999 * Cases: 1000 * - we could have the range completely in the middle of an 1001 * existing pcmap; in this case we have to split the pcmap 1002 * structure into two (i.e., generate a 'hole'). 1003 * - we could have the range covering multiple pcmaps; these 1004 * will have to be removed. 1005 * - we could have either 'start' or 'end' falling in the 1006 * middle of a pcmap; in this case shorten the entry. 1007 */ 1008 1009 TAILQ_FOREACH_SAFE(pcm, &pp->pp_map, ppm_next, pcmtmp) { 1010 assert(pcm->ppm_lowpc < pcm->ppm_highpc); 1011 if (pcm->ppm_highpc <= start) 1012 continue; 1013 if (pcm->ppm_lowpc > end) 1014 return; 1015 if (pcm->ppm_lowpc >= start && pcm->ppm_highpc <= end) { 1016 /* 1017 * The current pcmap is completely inside the 1018 * unmapped range: remove it entirely. 1019 */ 1020 TAILQ_REMOVE(&pp->pp_map, pcm, ppm_next); 1021 free(pcm); 1022 } else if (pcm->ppm_lowpc < start && pcm->ppm_highpc > end) { 1023 /* 1024 * Split this pcmap into two; curtail the 1025 * current map to end at [start-1], and start 1026 * the new one at [end]. 1027 */ 1028 if ((pcmnew = malloc(sizeof(*pcmnew))) == NULL) 1029 err(EX_OSERR, "ERROR: Cannot split a map " 1030 "entry"); 1031 1032 pcmnew->ppm_image = pcm->ppm_image; 1033 1034 pcmnew->ppm_lowpc = end; 1035 pcmnew->ppm_highpc = pcm->ppm_highpc; 1036 1037 pcm->ppm_highpc = start; 1038 1039 TAILQ_INSERT_AFTER(&pp->pp_map, pcm, pcmnew, ppm_next); 1040 1041 return; 1042 } else if (pcm->ppm_lowpc < start) 1043 pcm->ppm_lowpc = start; 1044 else if (pcm->ppm_highpc > end) 1045 pcm->ppm_highpc = end; 1046 else 1047 assert(0); 1048 } 1049} 1050 1051/* |
|
654 * Add a {pmcid,name} mapping. 655 */ 656 657static void | 1052 * Add a {pmcid,name} mapping. 1053 */ 1054 1055static void |
658pmcstat_pmcid_add(pmc_id_t pmcid, const char *name, struct pmcstat_args *a) | 1056pmcstat_pmcid_add(pmc_id_t pmcid, pmcstat_interned_string ps, 1057 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) { | 1058{ 1059 struct pmcstat_pmcrecord *pr; 1060 struct stat st; 1061 char fullpath[PATH_MAX]; 1062 1063 LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) 1064 if (pr->pr_pmcid == pmcid) { |
666 pr->pr_pmcname = name; | 1065 pr->pr_pmcname = ps; |
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; | 1066 return; 1067 } 1068 1069 if ((pr = malloc(sizeof(*pr))) == NULL) 1070 err(EX_OSERR, "ERROR: Cannot allocate pmc record"); 1071 1072 pr->pr_pmcid = pmcid; |
674 pr->pr_pmcname = name; | 1073 pr->pr_pmcname = ps; |
675 LIST_INSERT_HEAD(&pmcstat_pmcs, pr, pr_next); 676 677 (void) snprintf(fullpath, sizeof(fullpath), "%s/%s", a->pa_samplesdir, | 1074 LIST_INSERT_HEAD(&pmcstat_pmcs, pr, pr_next); 1075 1076 (void) snprintf(fullpath, sizeof(fullpath), "%s/%s", a->pa_samplesdir, |
678 name); | 1077 pmcstat_string_unintern(ps)); |
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/* | 1078 1079 /* If the path name exists, it should be a directory */ 1080 if (stat(fullpath, &st) == 0 && S_ISDIR(st.st_mode)) 1081 return; 1082 1083 if (mkdir(fullpath, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) < 0) 1084 err(EX_OSERR, "ERROR: Cannot create directory \"%s\"", 1085 fullpath); 1086} 1087 1088/* |
690 * Given a pmcid in use, find its human-readable name, or a | 1089 * Given a pmcid in use, find its human-readable name. |
691 */ 692 693static const char * 694pmcstat_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) | 1090 */ 1091 1092static const char * 1093pmcstat_pmcid_to_name(pmc_id_t pmcid) 1094{ 1095 struct pmcstat_pmcrecord *pr; 1096 char fullpath[PATH_MAX]; 1097 1098 LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) 1099 if (pr->pr_pmcid == pmcid) |
701 return pr->pr_pmcname; | 1100 return (pmcstat_string_unintern(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 | 1101 1102 /* create a default name and add this entry */ 1103 if ((pr = malloc(sizeof(*pr))) == NULL) 1104 err(EX_OSERR, "ERROR: "); 1105 pr->pr_pmcid = pmcid; 1106 1107 (void) snprintf(fullpath, sizeof(fullpath), "%X", (unsigned int) pmcid); 1108 pr->pr_pmcname = pmcstat_string_intern(fullpath); 1109 1110 LIST_INSERT_HEAD(&pmcstat_pmcs, pr, pr_next); 1111 |
713 return pr->pr_pmcname; | 1112 return (pmcstat_string_unintern(pr->pr_pmcname)); |
714} 715 716/* | 1113} 1114 1115/* |
717 * Associate an ELF image with a process. Argument 'path' names the 718 * executable while 'fd' is an already open descriptor to it. | 1116 * Associate an AOUT image with a process. |
719 */ 720 721static void | 1117 */ 1118 1119static void |
722pmcstat_process_add_elf_image(struct pmcstat_process *pp, const char *path, 723 uintfptr_t entryaddr) | 1120pmcstat_process_aout_exec(struct pmcstat_process *pp, 1121 struct pmcstat_image *image, uintfptr_t entryaddr, 1122 struct pmcstat_args *a) |
724{ | 1123{ |
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]; | 1124 (void) pp; 1125 (void) image; 1126 (void) entryaddr; 1127 (void) a; 1128 /* TODO Implement a.out handling */ 1129} |
732 | 1130 |
733 /* Look up path in the cache. */ 734 if ((image = pmcstat_image_from_path(path)) == NULL) 735 return; | 1131/* 1132 * Associate an ELF image with a process. 1133 */ |
736 | 1134 |
737 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) 738 pmcstat_image_get_elf_params(image); | 1135static void 1136pmcstat_process_elf_exec(struct pmcstat_process *pp, 1137 struct pmcstat_image *image, uintfptr_t entryaddr, 1138 struct pmcstat_args *a) 1139{ 1140 uintmax_t libstart; 1141 struct pmcstat_image *rtldimage; |
739 | 1142 |
1143 assert(image->pi_type == PMCSTAT_IMAGE_ELF32 || 1144 image->pi_type == PMCSTAT_IMAGE_ELF64); 1145 |
|
740 /* Create a map entry for the base executable. */ | 1146 /* Create a map entry for the base executable. */ |
741 pmcstat_image_link(pp, image, image->pi_start, image->pi_end); | 1147 pmcstat_image_link(pp, image, image->pi_vaddr); |
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 */ | 1148 1149 /* 1150 * For dynamically linked executables we need to: 1151 * (a) find where the dynamic linker was mapped to for this 1152 * process, 1153 * (b) find all the executable objects that the dynamic linker 1154 * brought in. 1155 */ |
1156 |
|
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 | 1157 if (image->pi_isdynamic) { 1158 1159 /* 1160 * The runtime loader gets loaded just after the maximum 1161 * possible heap address. Like so: 1162 * 1163 * [ TEXT DATA BSS HEAP -->*RTLD SHLIBS <--STACK] 1164 * ^ ^ 1165 * 0 VM_MAXUSER_ADDRESS |
1166 |
|
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 */ | 1167 * 1168 * The exact address where the loader gets mapped in 1169 * will vary according to the size of the executable 1170 * and the limits on the size of the process'es data 1171 * segment at the time of exec(). The entry address 1172 * recorded at process exec time corresponds to the 1173 * 'start' address inside the dynamic linker. From 1174 * this we can figure out the address where the 1175 * runtime loader's file object had been mapped to. 1176 */ |
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); | 1177 rtldimage = pmcstat_image_from_path(image->pi_dynlinkerpath, 1178 0); 1179 if (rtldimage == NULL) { 1180 warnx("WARNING: Cannot find image for \"%s\".", 1181 pmcstat_string_unintern(image->pi_dynlinkerpath)); 1182 pmcstat_stats.ps_exec_errors++; 1183 return; 1184 } 1185 |
773 if (rtldimage->pi_type == PMCSTAT_IMAGE_UNKNOWN) | 1186 if (rtldimage->pi_type == PMCSTAT_IMAGE_UNKNOWN) |
774 pmcstat_image_get_elf_params(rtldimage); | 1187 pmcstat_image_get_elf_params(rtldimage, a); |
775 | 1188 |
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); | 1189 if (rtldimage->pi_type != PMCSTAT_IMAGE_ELF32 && 1190 rtldimage->pi_type != PMCSTAT_IMAGE_ELF64) { 1191 warnx("WARNING: rtld not an ELF object \"%s\".", 1192 pmcstat_string_unintern(image->pi_dynlinkerpath)); 1193 return; |
818 } 819 | 1194 } 1195 |
820 (void) pclose(rf); 821 | 1196 libstart = entryaddr - rtldimage->pi_entry; 1197 pmcstat_image_link(pp, rtldimage, libstart); |
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 --- 8 unchanged lines hidden (view full) --- 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 */ | 1198 } 1199} 1200 1201/* 1202 * Find the process descriptor corresponding to a PID. If 'allocate' 1203 * is zero, we return a NULL if a pid descriptor could not be found or 1204 * a process descriptor process. If 'allocate' is non-zero, then we 1205 * will attempt to allocate a fresh process descriptor. Zombie --- 8 unchanged lines hidden (view full) --- 1214 struct pmcstat_pcmap *ppm, *ppmtmp; 1215 struct pmcstat_process *pp, *pptmp; 1216 1217 hash = (uint32_t) pid & PMCSTAT_HASH_MASK; /* simplicity wins */ 1218 1219 LIST_FOREACH_SAFE(pp, &pmcstat_process_hash[hash], pp_next, pptmp) 1220 if (pp->pp_pid == pid) { 1221 /* Found a descriptor, check and process zombies */ |
846 if (allocate && !pp->pp_isactive) { | 1222 if (allocate && pp->pp_isactive == 0) { |
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 } | 1223 /* remove maps */ 1224 TAILQ_FOREACH_SAFE(ppm, &pp->pp_map, ppm_next, 1225 ppmtmp) { 1226 TAILQ_REMOVE(&pp->pp_map, ppm, ppm_next); 1227 free(ppm); 1228 } 1229 /* remove process entry */ 1230 LIST_REMOVE(pp, pp_next); 1231 free(pp); 1232 break; 1233 } |
858 return pp; | 1234 return (pp); |
859 } 860 861 if (!allocate) | 1235 } 1236 1237 if (!allocate) |
862 return NULL; | 1238 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); | 1239 1240 if ((pp = malloc(sizeof(*pp))) == NULL) 1241 err(EX_OSERR, "ERROR: Cannot allocate pid descriptor"); 1242 1243 pp->pp_pid = pid; 1244 pp->pp_isactive = 1; 1245 1246 TAILQ_INIT(&pp->pp_map); 1247 1248 LIST_INSERT_HEAD(&pmcstat_process_hash[hash], pp, pp_next); |
873 return pp; | 1249 return (pp); |
874} 875 876/* 877 * Associate an image and a process. 878 */ 879 880static void | 1250} 1251 1252/* 1253 * Associate an image and a process. 1254 */ 1255 1256static void |
881pmcstat_process_exec(struct pmcstat_process *pp, const char *path, 882 uintfptr_t entryaddr) | 1257pmcstat_process_exec(struct pmcstat_process *pp, 1258 pmcstat_interned_string path, uintfptr_t entryaddr, 1259 struct pmcstat_args *a) |
883{ | 1260{ |
884 enum pmcstat_image_type filetype; | |
885 struct pmcstat_image *image; 886 | 1261 struct pmcstat_image *image; 1262 |
887 if ((image = pmcstat_image_from_path(path)) == NULL) | 1263 if ((image = pmcstat_image_from_path(path, 0)) == NULL) { 1264 pmcstat_stats.ps_exec_errors++; |
888 return; | 1265 return; |
1266 } |
|
889 890 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) | 1267 1268 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) |
891 filetype = pmcstat_image_get_type(path); 892 else 893 filetype = image->pi_type; | 1269 pmcstat_image_determine_type(image, a); |
894 | 1270 |
895 switch (filetype) { 896 case PMCSTAT_IMAGE_ELF: 897 pmcstat_process_add_elf_image(pp, path, entryaddr); | 1271 assert(image->pi_type != PMCSTAT_IMAGE_UNKNOWN); 1272 1273 switch (image->pi_type) { 1274 case PMCSTAT_IMAGE_ELF32: 1275 case PMCSTAT_IMAGE_ELF64: 1276 pmcstat_stats.ps_exec_elf++; 1277 pmcstat_process_elf_exec(pp, image, entryaddr, a); |
898 break; 899 900 case PMCSTAT_IMAGE_AOUT: | 1278 break; 1279 1280 case PMCSTAT_IMAGE_AOUT: |
1281 pmcstat_stats.ps_exec_aout++; 1282 pmcstat_process_aout_exec(pp, image, entryaddr, a); |
|
901 break; 902 | 1283 break; 1284 |
1285 case PMCSTAT_IMAGE_INDETERMINABLE: 1286 pmcstat_stats.ps_exec_indeterminable++; 1287 break; 1288 |
|
903 default: 904 err(EX_SOFTWARE, "ERROR: Unsupported executable type for " | 1289 default: 1290 err(EX_SOFTWARE, "ERROR: Unsupported executable type for " |
905 "\"%s\"", path); | 1291 "\"%s\"", pmcstat_string_unintern(path)); |
906 } 907} 908 909 910/* 911 * Find the map entry associated with process 'p' at PC value 'pc'. 912 */ 913 914static struct pmcstat_pcmap * 915pmcstat_process_find_map(struct pmcstat_process *p, uintfptr_t pc) 916{ 917 struct pmcstat_pcmap *ppm; 918 | 1292 } 1293} 1294 1295 1296/* 1297 * Find the map entry associated with process 'p' at PC value 'pc'. 1298 */ 1299 1300static struct pmcstat_pcmap * 1301pmcstat_process_find_map(struct pmcstat_process *p, uintfptr_t pc) 1302{ 1303 struct pmcstat_pcmap *ppm; 1304 |
919 TAILQ_FOREACH(ppm, &p->pp_map, ppm_next) 920 if (pc >= ppm->ppm_lowpc && pc < ppm->ppm_highpc) 921 return ppm; | 1305 TAILQ_FOREACH(ppm, &p->pp_map, ppm_next) { 1306 if (pc >= ppm->ppm_lowpc && pc < ppm->ppm_highpc) 1307 return (ppm); 1308 if (pc < ppm->ppm_lowpc) 1309 return (NULL); 1310 } |
922 | 1311 |
923 return NULL; | 1312 return (NULL); |
924} 925 926 | 1313} 1314 1315 |
927/* 928 * Compute a 'hash' value for a string. 929 */ | |
930 931static int | 1316 1317static int |
932pmcstat_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 946static const char * 947pmcstat_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 967static struct pmcstat_string * 968pmcstat_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 991int 992pmcstat_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 1003int | |
1004pmcstat_convert_log(struct pmcstat_args *a) 1005{ 1006 uintfptr_t pc; | 1318pmcstat_convert_log(struct pmcstat_args *a) 1319{ 1320 uintfptr_t pc; |
1321 pid_t pid; 1322 struct pmcstat_image *image; |
|
1007 struct pmcstat_process *pp, *ppnew; 1008 struct pmcstat_pcmap *ppm, *ppmtmp; 1009 struct pmclog_ev ev; | 1323 struct pmcstat_process *pp, *ppnew; 1324 struct pmcstat_pcmap *ppm, *ppmtmp; 1325 struct pmclog_ev ev; |
1010 const char *image_path; | 1326 pmcstat_interned_string 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) { | 1327 1328 while (pmclog_read(a->pa_logparser, &ev) == 0) { 1329 assert(ev.pl_state == PMCLOG_OK); 1330 1331 switch (ev.pl_type) { |
1016 case PMCLOG_TYPE_MAPPINGCHANGE: | 1332 case PMCLOG_TYPE_INITIALIZE: 1333 if ((ev.pl_u.pl_i.pl_version & 0xFF000000) != 1334 PMC_VERSION_MAJOR << 24 && a->pa_verbosity > 0) 1335 warnx("WARNING: Log version 0x%x does not " 1336 "match compiled version 0x%x.", 1337 ev.pl_u.pl_i.pl_version, 1338 PMC_VERSION_MAJOR); 1339 break; 1340 case PMCLOG_TYPE_MAP_IN: |
1017 /* 1018 * Introduce an address range mapping for a | 1341 /* 1342 * Introduce an address range mapping for a |
1019 * process. | 1343 * userland process or the kernel (pid == -1). 1344 * 1345 * We always allocate a process descriptor so 1346 * that subsequent samples seen for this 1347 * address range are mapped to the current 1348 * object being mapped in. |
1020 */ | 1349 */ |
1350 pid = ev.pl_u.pl_mi.pl_pid; 1351 if (pid == -1) 1352 pp = pmcstat_kernproc; 1353 else 1354 pp = pmcstat_process_lookup(pid, 1355 PMCSTAT_ALLOCATE); 1356 1357 assert(pp != NULL); 1358 1359 image_path = pmcstat_string_intern(ev.pl_u.pl_mi. 1360 pl_pathname); 1361 image = pmcstat_image_from_path(image_path, pid == -1); 1362 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) 1363 pmcstat_image_determine_type(image, a); 1364 if (image->pi_type != PMCSTAT_IMAGE_INDETERMINABLE) 1365 pmcstat_image_link(pp, image, 1366 ev.pl_u.pl_mi.pl_start); |
|
1021 break; 1022 | 1367 break; 1368 |
1369 case PMCLOG_TYPE_MAP_OUT: 1370 /* 1371 * Remove an address map. 1372 */ 1373 pid = ev.pl_u.pl_mo.pl_pid; 1374 if (pid == -1) 1375 pp = pmcstat_kernproc; 1376 else 1377 pp = pmcstat_process_lookup(pid, 0); 1378 1379 if (pp == NULL) /* unknown process */ 1380 break; 1381 1382 pmcstat_image_unmap(pp, ev.pl_u.pl_mo.pl_start, 1383 ev.pl_u.pl_mo.pl_end); 1384 break; 1385 |
|
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 */ | 1386 case PMCLOG_TYPE_PCSAMPLE: 1387 1388 /* 1389 * We bring in the gmon file for the image 1390 * currently associated with the PMC & pid 1391 * pair and increment the appropriate entry 1392 * bin inside this. 1393 */ |
1394 pmcstat_stats.ps_samples_total++; 1395 |
|
1031 pc = ev.pl_u.pl_s.pl_pc; | 1396 pc = ev.pl_u.pl_s.pl_pc; |
1032 pp = pmcstat_process_lookup(ev.pl_u.pl_s.pl_pid, 1); | 1397 pp = pmcstat_process_lookup(ev.pl_u.pl_s.pl_pid, 1398 PMCSTAT_ALLOCATE); |
1033 if ((ppm = pmcstat_process_find_map(pp, pc)) == NULL && 1034 (ppm = pmcstat_process_find_map(pmcstat_kernproc, | 1399 if ((ppm = pmcstat_process_find_map(pp, pc)) == NULL && 1400 (ppm = pmcstat_process_find_map(pmcstat_kernproc, |
1035 pc)) == NULL) 1036 break; /* unknown process,offset pair */ | 1401 pc)) == NULL) { /* unknown process,offset pair */ 1402 pmcstat_stats.ps_samples_unknown_offset++; 1403 break; 1404 } |
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 /* --- 5 unchanged lines hidden (view full) --- 1050 break; 1051 1052 case PMCLOG_TYPE_PROCEXEC: 1053 1054 /* 1055 * Change the executable image associated with 1056 * a process. 1057 */ | 1405 1406 pmcstat_image_increment_bucket(ppm, pc, 1407 ev.pl_u.pl_s.pl_pmcid, a); 1408 1409 break; 1410 1411 case PMCLOG_TYPE_PMCALLOCATE: 1412 /* --- 5 unchanged lines hidden (view full) --- 1418 break; 1419 1420 case PMCLOG_TYPE_PROCEXEC: 1421 1422 /* 1423 * Change the executable image associated with 1424 * a process. 1425 */ |
1058 pp = pmcstat_process_lookup(ev.pl_u.pl_x.pl_pid, 1); | 1426 pp = pmcstat_process_lookup(ev.pl_u.pl_x.pl_pid, 1427 PMCSTAT_ALLOCATE); |
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 | 1428 1429 /* delete the current process map */ 1430 TAILQ_FOREACH_SAFE(ppm, &pp->pp_map, ppm_next, ppmtmp) { 1431 TAILQ_REMOVE(&pp->pp_map, ppm, ppm_next); 1432 free(ppm); 1433 } 1434 |
1066 /* locate the descriptor for the new 'base' image */ | 1435 /* associate this process image */ |
1067 image_path = pmcstat_string_intern( 1068 ev.pl_u.pl_x.pl_pathname); | 1436 image_path = pmcstat_string_intern( 1437 ev.pl_u.pl_x.pl_pathname); |
1069 1070 /* link to the new image */ | 1438 assert(image_path != NULL); |
1071 pmcstat_process_exec(pp, image_path, | 1439 pmcstat_process_exec(pp, image_path, |
1072 ev.pl_u.pl_x.pl_entryaddr); | 1440 ev.pl_u.pl_x.pl_entryaddr, a); |
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; | 1441 break; 1442 1443 case PMCLOG_TYPE_PROCEXIT: 1444 1445 /* 1446 * Due to the way the log is generated, the 1447 * last few samples corresponding to a process 1448 * may appear in the log after the process 1449 * exit event is recorded. Thus we keep the 1450 * process' descriptor and associated data 1451 * structures around, but mark the process as 1452 * having exited. 1453 */ 1454 pp = pmcstat_process_lookup(ev.pl_u.pl_e.pl_pid, 0); 1455 if (pp == NULL) 1456 break; |
1089 pp->pp_isactive = 0; /* make a zombie */ | 1457 pp->pp_isactive = 0; /* mark as 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 /* | 1458 break; 1459 1460 case PMCLOG_TYPE_SYSEXIT: 1461 pp = pmcstat_process_lookup(ev.pl_u.pl_se.pl_pid, 0); 1462 if (pp == NULL) 1463 break; 1464 pp->pp_isactive = 0; /* make a zombie */ 1465 break; 1466 1467 case PMCLOG_TYPE_PROCFORK: 1468 1469 /* |
1102 * If we had been tracking 'oldpid', then clone 1103 * its pid descriptor. | 1470 * Allocate a process descriptor for the new 1471 * (child) process. |
1104 */ | 1472 */ |
1473 ppnew = 1474 pmcstat_process_lookup(ev.pl_u.pl_f.pl_newpid, 1475 PMCSTAT_ALLOCATE); 1476 1477 /* 1478 * If we had been tracking the parent, clone 1479 * its address maps. 1480 */ |
|
1105 pp = pmcstat_process_lookup(ev.pl_u.pl_f.pl_oldpid, 0); 1106 if (pp == NULL) 1107 break; | 1481 pp = pmcstat_process_lookup(ev.pl_u.pl_f.pl_oldpid, 0); 1482 if (pp == NULL) 1483 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, | 1484 TAILQ_FOREACH(ppm, &pp->pp_map, ppm_next) 1485 pmcstat_image_link(ppnew, ppm->ppm_image, |
1115 ppm->ppm_lowpc, ppm->ppm_highpc); | 1486 ppm->ppm_lowpc); |
1116 break; 1117 1118 default: /* other types of entries are not relevant */ 1119 break; 1120 } 1121 } 1122 1123 if (ev.pl_state == PMCLOG_EOF) | 1487 break; 1488 1489 default: /* other types of entries are not relevant */ 1490 break; 1491 } 1492 } 1493 1494 if (ev.pl_state == PMCLOG_EOF) |
1124 return PMCSTAT_FINISHED; | 1495 return (PMCSTAT_FINISHED); |
1125 else if (ev.pl_state == PMCLOG_REQUIRE_DATA) | 1496 else if (ev.pl_state == PMCLOG_REQUIRE_DATA) |
1126 return PMCSTAT_RUNNING; | 1497 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 | 1498 1499 err(EX_DATAERR, "ERROR: event parsing failed (record %jd, " 1500 "offset 0x%jx)", (uintmax_t) ev.pl_count + 1, ev.pl_offset); 1501} 1502 |
1132 | |
1133/* | 1503/* |
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 1140int 1141pmcstat_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 | 1504 * Print log entries as text. 1505 */ 1506 |
1164int | 1507static int |
1165pmcstat_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; | 1508pmcstat_print_log(struct pmcstat_args *a) 1509{ 1510 struct pmclog_ev ev; 1511 1512 while (pmclog_read(a->pa_logparser, &ev) == 0) { 1513 assert(ev.pl_state == PMCLOG_OK); 1514 switch (ev.pl_type) { 1515 case PMCLOG_TYPE_CLOSELOG: 1516 PMCSTAT_PRINT_ENTRY(a,"closelog",); 1517 break; 1518 case PMCLOG_TYPE_DROPNOTIFY: 1519 PMCSTAT_PRINT_ENTRY(a,"drop",); 1520 break; 1521 case PMCLOG_TYPE_INITIALIZE: 1522 PMCSTAT_PRINT_ENTRY(a,"initlog","0x%x \"%s\"", 1523 ev.pl_u.pl_i.pl_version, 1524 pmc_name_of_cputype(ev.pl_u.pl_i.pl_arch)); 1525 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); | 1526 case PMCLOG_TYPE_MAP_IN: 1527 PMCSTAT_PRINT_ENTRY(a,"map-in","%d %p \"%s\"", 1528 ev.pl_u.pl_mi.pl_pid, 1529 (void *) ev.pl_u.pl_mi.pl_start, 1530 ev.pl_u.pl_mi.pl_pathname); |
1191 break; | 1531 break; |
1532 case PMCLOG_TYPE_MAP_OUT: 1533 PMCSTAT_PRINT_ENTRY(a,"map-out","%d %p %p", 1534 ev.pl_u.pl_mo.pl_pid, 1535 (void *) ev.pl_u.pl_mo.pl_start, 1536 (void *) ev.pl_u.pl_mo.pl_end); 1537 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: --- 47 unchanged lines hidden (view full) --- 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) | 1538 case PMCLOG_TYPE_PCSAMPLE: 1539 PMCSTAT_PRINT_ENTRY(a,"sample","0x%x %d %p %c", 1540 ev.pl_u.pl_s.pl_pmcid, 1541 ev.pl_u.pl_s.pl_pid, 1542 (void *) ev.pl_u.pl_s.pl_pc, 1543 ev.pl_u.pl_s.pl_usermode ? 'u' : 's'); 1544 break; 1545 case PMCLOG_TYPE_PMCALLOCATE: --- 47 unchanged lines hidden (view full) --- 1593 break; 1594 default: 1595 fprintf(a->pa_printfile, "unknown %d", 1596 ev.pl_type); 1597 } 1598 } 1599 1600 if (ev.pl_state == PMCLOG_EOF) |
1255 return PMCSTAT_FINISHED; | 1601 return (PMCSTAT_FINISHED); |
1256 else if (ev.pl_state == PMCLOG_REQUIRE_DATA) | 1602 else if (ev.pl_state == PMCLOG_REQUIRE_DATA) |
1257 return PMCSTAT_RUNNING; | 1603 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/* | 1604 1605 err(EX_DATAERR, "ERROR: event parsing failed " 1606 "(record %jd, offset 0x%jx)", 1607 (uintmax_t) ev.pl_count + 1, ev.pl_offset); 1608 /*NOTREACHED*/ 1609} 1610 1611/* |
1612 * Public Interfaces. 1613 */ 1614 1615/* 1616 * Close a logfile, after first flushing all in-module queued data. 1617 */ 1618 1619int 1620pmcstat_close_log(struct pmcstat_args *a) 1621{ 1622 if (pmc_flush_logfile() < 0 || 1623 pmc_configure_logfile(-1) < 0) 1624 err(EX_OSERR, "ERROR: logging failed"); 1625 a->pa_flags &= ~(FLAG_HAS_OUTPUT_LOGFILE | FLAG_HAS_PIPE); 1626 return (a->pa_flags & FLAG_HAS_PIPE ? PMCSTAT_EXITING : 1627 PMCSTAT_FINISHED); 1628} 1629 1630 1631 1632/* 1633 * Open a log file, for reading or writing. 1634 * 1635 * The function returns the fd of a successfully opened log or -1 in 1636 * case of failure. 1637 */ 1638 1639int 1640pmcstat_open_log(const char *path, int mode) 1641{ 1642 int fd; 1643 1644 /* 1645 * If 'path' is "-" then open one of stdin or stdout depending 1646 * on the value of 'mode'. Otherwise, treat 'path' as a file 1647 * name and open that. 1648 */ 1649 if (path[0] == '-' && path[1] == '\0') 1650 fd = (mode == PMCSTAT_OPEN_FOR_READ) ? 0 : 1; 1651 else 1652 fd = open(path, mode == PMCSTAT_OPEN_FOR_READ ? 1653 O_RDONLY : (O_WRONLY|O_CREAT|O_TRUNC), 1654 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); 1655 1656 return (fd); 1657} 1658 1659/* |
|
1266 * Process a log file in offline analysis mode. 1267 */ 1268 1269int 1270pmcstat_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) | 1660 * Process a log file in offline analysis mode. 1661 */ 1662 1663int 1664pmcstat_process_log(struct pmcstat_args *a) 1665{ 1666 1667 /* 1668 * If gprof style profiles haven't been asked for, just print the 1669 * log to the current output file. 1670 */ 1671 if (a->pa_flags & FLAG_DO_PRINT) |
1278 return pmcstat_print_log(a); | 1672 return (pmcstat_print_log(a)); |
1279 else 1280 /* convert the log to gprof compatible profiles */ | 1673 else 1674 /* convert the log to gprof compatible profiles */ |
1281 return pmcstat_convert_log(a); | 1675 return (pmcstat_convert_log(a)); |
1282} 1283 | 1676} 1677 |
1678/* 1679 * Initialize module. 1680 */ 1681 |
|
1284void 1285pmcstat_initialize_logging(struct pmcstat_args *a) 1286{ 1287 int i; | 1682void 1683pmcstat_initialize_logging(struct pmcstat_args *a) 1684{ 1685 int i; |
1288 const char *kernpath; 1289 struct pmcstat_image *img; | |
1290 | 1686 |
1687 (void) a; 1688 |
|
1291 /* use a convenient format for 'ldd' output */ 1292 if (setenv("LD_TRACE_LOADED_OBJECTS_FMT1","%o \"%p\" %x\n",1) != 0) | 1689 /* use a convenient format for 'ldd' output */ 1690 if (setenv("LD_TRACE_LOADED_OBJECTS_FMT1","%o \"%p\" %x\n",1) != 0) |
1293 goto error; | 1691 err(EX_OSERR, "ERROR: Cannot setenv"); |
1294 1295 /* Initialize hash tables */ | 1692 1693 /* Initialize hash tables */ |
1694 pmcstat_string_initialize(); |
|
1296 for (i = 0; i < PMCSTAT_NHASH; i++) { 1297 LIST_INIT(&pmcstat_image_hash[i]); 1298 LIST_INIT(&pmcstat_process_hash[i]); | 1695 for (i = 0; i < PMCSTAT_NHASH; i++) { 1696 LIST_INIT(&pmcstat_image_hash[i]); 1697 LIST_INIT(&pmcstat_process_hash[i]); |
1299 LIST_INIT(&pmcstat_string_hash[i]); | |
1300 } 1301 | 1698 } 1699 |
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"); | 1700 /* 1701 * Create a fake 'process' entry for the kernel with pid -1. 1702 * hwpmc(4) will subsequently inform us about where the kernel 1703 * and any loaded kernel modules are mapped. 1704 */ 1705 if ((pmcstat_kernproc = pmcstat_process_lookup((pid_t) -1, 1706 PMCSTAT_ALLOCATE)) == NULL) 1707 err(EX_OSERR, "ERROR: Cannot initialize logging"); |
1318} 1319 | 1708} 1709 |
1710/* 1711 * Shutdown module. 1712 */ 1713 |
|
1320void | 1714void |
1321pmcstat_shutdown_logging(void) | 1715pmcstat_shutdown_logging(struct pmcstat_args *a) |
1322{ 1323 int i; | 1716{ 1717 int i; |
1718 FILE *mf; |
|
1324 struct pmcstat_gmonfile *pgf, *pgftmp; 1325 struct pmcstat_image *pi, *pitmp; 1326 struct pmcstat_process *pp, *pptmp; | 1719 struct pmcstat_gmonfile *pgf, *pgftmp; 1720 struct pmcstat_image *pi, *pitmp; 1721 struct pmcstat_process *pp, *pptmp; |
1327 struct pmcstat_string *ps, *pstmp; | |
1328 | 1722 |
1723 /* determine where to send the map file */ 1724 mf = NULL; 1725 if (a->pa_mapfilename != NULL) 1726 mf = (strcmp(a->pa_mapfilename, "-") == 0) ? 1727 a->pa_printfile : fopen(a->pa_mapfilename, "w"); 1728 1729 if (mf == NULL && a->pa_flags & FLAG_DO_GPROF && 1730 a->pa_verbosity >= 2) 1731 mf = a->pa_printfile; 1732 1733 if (mf) 1734 (void) fprintf(mf, "MAP:\n"); 1735 |
|
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) { | 1736 for (i = 0; i < PMCSTAT_NHASH; i++) { 1737 LIST_FOREACH_SAFE(pi, &pmcstat_image_hash[i], pi_next, pitmp) { 1738 /* flush gmon.out data to disk */ 1739 LIST_FOREACH_SAFE(pgf, &pi->pi_gmlist, pgf_next, 1740 pgftmp) { |
1334 pmcstat_gmon_unmap_file(pgf); 1335 LIST_REMOVE(pgf, pgf_next); 1336 free(pgf); | 1741 pmcstat_gmon_unmap_file(pgf); 1742 LIST_REMOVE(pgf, pgf_next); 1743 1744 if (pgf->pgf_overflow && a->pa_verbosity >= 1) 1745 warnx("WARNING: profile \"%s\" " 1746 "overflowed.", 1747 pmcstat_string_unintern(pgf->pgf_name)); 1748 free(pgf); |
1337 } | 1749 } |
1750 if (mf) 1751 (void) fprintf(mf, " \"%s\" -> \"%s\"\n", 1752 pmcstat_string_unintern(pi->pi_execpath), 1753 pmcstat_string_unintern(pi->pi_samplename)); |
|
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 } | 1754 1755 LIST_REMOVE(pi, pi_next); 1756 free(pi); 1757 } 1758 LIST_FOREACH_SAFE(pp, &pmcstat_process_hash[i], pp_next, 1759 pptmp) { 1760 LIST_REMOVE(pp, pp_next); 1761 free(pp); 1762 } |
1347 LIST_FOREACH_SAFE(ps, &pmcstat_string_hash[i], ps_next, 1348 pstmp) { 1349 LIST_REMOVE(ps, ps_next); 1350 free(ps); 1351 } | |
1352 } | 1763 } |
1764 1765 pmcstat_string_shutdown(); 1766 1767 /* 1768 * Print errors unless -q was specified. Print all statistics 1769 * if verbosity > 1. 1770 */ 1771#define PRINT(N,V,A) do { \ 1772 if (pmcstat_stats.ps_##V || (A)->pa_verbosity >= 2) \ 1773 (void) fprintf((A)->pa_printfile, " %-40s %d\n",\ 1774 N, pmcstat_stats.ps_##V); \ 1775 } while (0) 1776 1777 if (a->pa_verbosity >= 1 && a->pa_flags & FLAG_DO_GPROF) { 1778 (void) fprintf(a->pa_printfile, "CONVERSION STATISTICS:\n"); 1779 PRINT("#exec/a.out", exec_aout, a); 1780 PRINT("#exec/elf", exec_elf, a); 1781 PRINT("#exec/unknown", exec_indeterminable, a); 1782 PRINT("#exec handling errors", exec_errors, a); 1783 PRINT("#samples/total", samples_total, a); 1784 PRINT("#samples/unclaimed", samples_unknown_offset, a); 1785 PRINT("#samples/unknown-object", samples_indeterminable, a); 1786 } 1787 1788 if (mf) 1789 (void) fclose(mf); |
|
1353} | 1790} |