pmcstat_log.c (201145) | pmcstat_log.c (203790) |
---|---|
1/*- 2 * Copyright (c) 2005-2007, Joseph Koshy 3 * Copyright (c) 2007 The FreeBSD Foundation 4 * All rights reserved. 5 * 6 * Portions of this software were developed by A. Joseph Koshy under 7 * sponsorship from the FreeBSD Foundation and Google, Inc. 8 * --- 20 unchanged lines hidden (view full) --- 29 */ 30 31/* 32 * Transform a hwpmc(4) log into human readable form, and into 33 * gprof(1) compatible profiles. 34 */ 35 36#include <sys/cdefs.h> | 1/*- 2 * Copyright (c) 2005-2007, Joseph Koshy 3 * Copyright (c) 2007 The FreeBSD Foundation 4 * All rights reserved. 5 * 6 * Portions of this software were developed by A. Joseph Koshy under 7 * sponsorship from the FreeBSD Foundation and Google, Inc. 8 * --- 20 unchanged lines hidden (view full) --- 29 */ 30 31/* 32 * Transform a hwpmc(4) log into human readable form, and into 33 * gprof(1) compatible profiles. 34 */ 35 36#include <sys/cdefs.h> |
37__FBSDID("$FreeBSD: head/usr.sbin/pmcstat/pmcstat_log.c 201145 2009-12-28 22:56:30Z antoine $"); | 37__FBSDID("$FreeBSD: head/usr.sbin/pmcstat/pmcstat_log.c 203790 2010-02-11 22:51:44Z fabient $"); |
38 39#include <sys/param.h> 40#include <sys/endian.h> 41#include <sys/gmon.h> 42#include <sys/imgact_aout.h> 43#include <sys/imgact_elf.h> 44#include <sys/mman.h> 45#include <sys/pmc.h> 46#include <sys/queue.h> 47#include <sys/socket.h> 48#include <sys/stat.h> 49#include <sys/wait.h> 50 51#include <netinet/in.h> 52 53#include <assert.h> | 38 39#include <sys/param.h> 40#include <sys/endian.h> 41#include <sys/gmon.h> 42#include <sys/imgact_aout.h> 43#include <sys/imgact_elf.h> 44#include <sys/mman.h> 45#include <sys/pmc.h> 46#include <sys/queue.h> 47#include <sys/socket.h> 48#include <sys/stat.h> 49#include <sys/wait.h> 50 51#include <netinet/in.h> 52 53#include <assert.h> |
54#include <curses.h> |
|
54#include <err.h> 55#include <errno.h> 56#include <fcntl.h> 57#include <gelf.h> 58#include <libgen.h> 59#include <limits.h> 60#include <netdb.h> 61#include <pmc.h> 62#include <pmclog.h> 63#include <sysexits.h> 64#include <stdint.h> 65#include <stdio.h> 66#include <stdlib.h> 67#include <string.h> 68#include <unistd.h> 69 70#include "pmcstat.h" | 55#include <err.h> 56#include <errno.h> 57#include <fcntl.h> 58#include <gelf.h> 59#include <libgen.h> 60#include <limits.h> 61#include <netdb.h> 62#include <pmc.h> 63#include <pmclog.h> 64#include <sysexits.h> 65#include <stdint.h> 66#include <stdio.h> 67#include <stdlib.h> 68#include <string.h> 69#include <unistd.h> 70 71#include "pmcstat.h" |
72#include "pmcstat_log.h" 73#include "pmcstat_top.h" |
|
71 | 74 |
72#define min(A,B) ((A) < (B) ? (A) : (B)) 73#define max(A,B) ((A) > (B) ? (A) : (B)) 74 | |
75#define PMCSTAT_ALLOCATE 1 76 77/* 78 * PUBLIC INTERFACES 79 * 80 * pmcstat_initialize_logging() initialize this module, called first 81 * pmcstat_shutdown_logging() orderly shutdown, called last 82 * pmcstat_open_log() open an eventlog for processing 83 * pmcstat_process_log() print/convert an event log | 75#define PMCSTAT_ALLOCATE 1 76 77/* 78 * PUBLIC INTERFACES 79 * 80 * pmcstat_initialize_logging() initialize this module, called first 81 * pmcstat_shutdown_logging() orderly shutdown, called last 82 * pmcstat_open_log() open an eventlog for processing 83 * pmcstat_process_log() print/convert an event log |
84 * pmcstat_display_log() top mode display for the log |
|
84 * pmcstat_close_log() finish processing an event log 85 * 86 * IMPLEMENTATION NOTES 87 * 88 * We correlate each 'callchain' or 'sample' entry seen in the event 89 * log back to an executable object in the system. Executable objects 90 * include: 91 * - program executables, --- 30 unchanged lines hidden (view full) --- 122 * Each active pmcid has its own callgraph structure, described by a 123 * 'struct pmcstat_callgraph'. Given a process id and a list of pc 124 * values, we map each pc value to a tuple (image, symbol), where 125 * 'image' denotes an executable object and 'symbol' is the closest 126 * symbol that precedes the pc value. Each pc value in the list is 127 * also given a 'rank' that reflects its depth in the call stack. 128 */ 129 | 85 * pmcstat_close_log() finish processing an event log 86 * 87 * IMPLEMENTATION NOTES 88 * 89 * We correlate each 'callchain' or 'sample' entry seen in the event 90 * log back to an executable object in the system. Executable objects 91 * include: 92 * - program executables, --- 30 unchanged lines hidden (view full) --- 123 * Each active pmcid has its own callgraph structure, described by a 124 * 'struct pmcstat_callgraph'. Given a process id and a list of pc 125 * values, we map each pc value to a tuple (image, symbol), where 126 * 'image' denotes an executable object and 'symbol' is the closest 127 * symbol that precedes the pc value. Each pc value in the list is 128 * also given a 'rank' that reflects its depth in the call stack. 129 */ 130 |
130typedef const void *pmcstat_interned_string; | 131struct pmcstat_pmcs pmcstat_pmcs = LIST_HEAD_INITIALIZER(pmcstat_pmcs); |
131 132/* | 132 133/* |
133 * 'pmcstat_pmcrecord' is a mapping from PMC ids to human-readable 134 * names. | 134 * All image descriptors are kept in a hash table. |
135 */ | 135 */ |
136struct pmcstat_image_hash_list pmcstat_image_hash[PMCSTAT_NHASH]; |
|
136 | 137 |
137struct pmcstat_pmcrecord { 138 LIST_ENTRY(pmcstat_pmcrecord) pr_next; 139 pmc_id_t pr_pmcid; 140 pmcstat_interned_string pr_pmcname; 141}; 142 143static LIST_HEAD(,pmcstat_pmcrecord) pmcstat_pmcs = 144 LIST_HEAD_INITIALIZER(pmcstat_pmcs); 145 146 | |
147/* | 138/* |
148 * struct pmcstat_gmonfile tracks a given 'gmon.out' file. These 149 * files are mmap()'ed in as needed. | 139 * All process descriptors are kept in a hash table. |
150 */ | 140 */ |
141struct pmcstat_process_hash_list pmcstat_process_hash[PMCSTAT_NHASH]; |
|
151 | 142 |
152struct pmcstat_gmonfile { 153 LIST_ENTRY(pmcstat_gmonfile) pgf_next; /* list of entries */ 154 int pgf_overflow; /* whether a count overflowed */ 155 pmc_id_t pgf_pmcid; /* id of the associated pmc */ 156 size_t pgf_nbuckets; /* #buckets in this gmon.out */ 157 unsigned int pgf_nsamples; /* #samples in this gmon.out */ 158 pmcstat_interned_string pgf_name; /* pathname of gmon.out file */ 159 size_t pgf_ndatabytes; /* number of bytes mapped */ 160 void *pgf_gmondata; /* pointer to mmap'ed data */ 161 FILE *pgf_file; /* used when writing gmon arcs */ 162}; | 143struct pmcstat_stats pmcstat_stats; /* statistics */ |
163 | 144 |
164/* 165 * A 'pmcstat_image' structure describes an executable program on 166 * disk. 'pi_execpath' is a cookie representing the pathname of 167 * the executable. 'pi_start' and 'pi_end' are the least and greatest 168 * virtual addresses for the text segments in the executable. 169 * 'pi_gmonlist' contains a linked list of gmon.out files associated 170 * with this image. 171 */ | 145struct pmcstat_process *pmcstat_kernproc; /* kernel 'process' */ |
172 | 146 |
173enum pmcstat_image_type { 174 PMCSTAT_IMAGE_UNKNOWN = 0, /* never looked at the image */ 175 PMCSTAT_IMAGE_INDETERMINABLE, /* can't tell what the image is */ 176 PMCSTAT_IMAGE_ELF32, /* ELF 32 bit object */ 177 PMCSTAT_IMAGE_ELF64, /* ELF 64 bit object */ 178 PMCSTAT_IMAGE_AOUT /* AOUT object */ 179}; | 147#include "pmcpl_gprof.h" 148#include "pmcpl_callgraph.h" 149#include "pmcpl_annotate.h" 150#include "pmcpl_calltree.h" |
180 | 151 |
181struct pmcstat_image { 182 LIST_ENTRY(pmcstat_image) pi_next; /* hash link */ 183 TAILQ_ENTRY(pmcstat_image) pi_lru; /* LRU list */ 184 pmcstat_interned_string pi_execpath; /* cookie */ 185 pmcstat_interned_string pi_samplename; /* sample path name */ 186 pmcstat_interned_string pi_fullpath; /* path to FS object */ | 152struct pmc_plugins { 153 const char *pl_name; /* name */ |
187 | 154 |
188 enum pmcstat_image_type pi_type; /* executable type */ | 155 /* configure */ 156 int (*pl_configure)(char *opt); |
189 | 157 |
190 /* 191 * Executables have pi_start and pi_end; these are zero 192 * for shared libraries. 193 */ 194 uintfptr_t pi_start; /* start address (inclusive) */ 195 uintfptr_t pi_end; /* end address (exclusive) */ 196 uintfptr_t pi_entry; /* entry address */ 197 uintfptr_t pi_vaddr; /* virtual address where loaded */ 198 int pi_isdynamic; /* whether a dynamic object */ 199 int pi_iskernelmodule; 200 pmcstat_interned_string pi_dynlinkerpath; /* path in .interp */ | 158 /* init and shutdown */ 159 int (*pl_init)(void); 160 void (*pl_shutdown)(FILE *mf); |
201 | 161 |
202 /* All symbols associated with this object. */ 203 struct pmcstat_symbol *pi_symbols; 204 size_t pi_symcount; | 162 /* sample processing */ 163 void (*pl_process)(struct pmcstat_process *pp, 164 struct pmcstat_pmcrecord *pmcr, uint32_t nsamples, 165 uintfptr_t *cc, int usermode, uint32_t cpu); |
205 | 166 |
206 /* 207 * An image can be associated with one or more gmon.out files; 208 * one per PMC. 209 */ 210 LIST_HEAD(,pmcstat_gmonfile) pi_gmlist; 211}; | 167 /* image */ 168 void (*pl_initimage)(struct pmcstat_image *pi); 169 void (*pl_shutdownimage)(struct pmcstat_image *pi); |
212 | 170 |
213/* 214 * All image descriptors are kept in a hash table. 215 */ 216static LIST_HEAD(,pmcstat_image) pmcstat_image_hash[PMCSTAT_NHASH]; | 171 /* pmc */ 172 void (*pl_newpmc)(pmcstat_interned_string ps, 173 struct pmcstat_pmcrecord *pr); 174 175 /* top display */ 176 void (*pl_topdisplay)(void); |
217 | 177 |
218/* 219 * A 'pmcstat_pcmap' structure maps a virtual address range to an 220 * underlying 'pmcstat_image' descriptor. 221 */ 222struct pmcstat_pcmap { 223 TAILQ_ENTRY(pmcstat_pcmap) ppm_next; 224 uintfptr_t ppm_lowpc; 225 uintfptr_t ppm_highpc; 226 struct pmcstat_image *ppm_image; 227}; | 178 /* top keypress */ 179 int (*pl_topkeypress)(int c, WINDOW *w); |
228 | 180 |
229/* 230 * A 'pmcstat_process' structure models processes. Each process is 231 * associated with a set of pmcstat_pcmap structures that map 232 * addresses inside it to executable objects. This set is implemented 233 * as a list, kept sorted in ascending order of mapped addresses. 234 * 235 * 'pp_pid' holds the pid of the process. When a process exits, the 236 * 'pp_isactive' field is set to zero, but the process structure is 237 * not immediately reclaimed because there may still be samples in the 238 * log for this process. 239 */ 240 241struct pmcstat_process { 242 LIST_ENTRY(pmcstat_process) pp_next; /* hash-next */ 243 pid_t pp_pid; /* associated pid */ 244 int pp_isactive; /* whether active */ 245 uintfptr_t pp_entryaddr; /* entry address */ 246 TAILQ_HEAD(,pmcstat_pcmap) pp_map; /* address range map */ | 181} plugins[] = { 182 { 183 .pl_name = "none", 184 }, 185 { 186 .pl_name = "callgraph", 187 .pl_init = pmcpl_cg_init, 188 .pl_shutdown = pmcpl_cg_shutdown, 189 .pl_process = pmcpl_cg_process, 190 .pl_topkeypress = pmcpl_cg_topkeypress, 191 .pl_topdisplay = pmcpl_cg_topdisplay 192 }, 193 { 194 .pl_name = "gprof", 195 .pl_shutdown = pmcpl_gmon_shutdown, 196 .pl_process = pmcpl_gmon_process, 197 .pl_initimage = pmcpl_gmon_initimage, 198 .pl_shutdownimage = pmcpl_gmon_shutdownimage, 199 .pl_newpmc = pmcpl_gmon_newpmc 200 }, 201 { 202 .pl_name = "annotate", 203 .pl_process = pmcpl_annotate_process 204 }, 205 { 206 .pl_name = "calltree", 207 .pl_configure = pmcpl_ct_configure, 208 .pl_init = pmcpl_ct_init, 209 .pl_shutdown = pmcpl_ct_shutdown, 210 .pl_process = pmcpl_ct_process, 211 .pl_topkeypress = pmcpl_ct_topkeypress, 212 .pl_topdisplay = pmcpl_ct_topdisplay 213 }, 214 { 215 .pl_name = NULL 216 } |
247}; 248 | 217}; 218 |
249/* 250 * All process descriptors are kept in a hash table. 251 */ 252static LIST_HEAD(,pmcstat_process) pmcstat_process_hash[PMCSTAT_NHASH]; | 219int pmcstat_mergepmc; |
253 | 220 |
254static struct pmcstat_process *pmcstat_kernproc; /* kernel 'process' */ | 221int pmcstat_pmcinfilter = 0; /* PMC filter for top mode. */ 222float pmcstat_threshold = 0.5; /* Cost filter for top mode. */ |
255 256/* | 223 224/* |
257 * Each function symbol tracked by pmcstat(8). 258 */ 259 260struct pmcstat_symbol { 261 pmcstat_interned_string ps_name; 262 uint64_t ps_start; 263 uint64_t ps_end; 264}; 265 266/* 267 * Each call graph node is tracked by a pmcstat_cgnode struct. 268 */ 269 270struct pmcstat_cgnode { 271 struct pmcstat_image *pcg_image; 272 uintfptr_t pcg_func; 273 uint32_t pcg_count; 274 uint32_t pcg_nchildren; 275 LIST_ENTRY(pmcstat_cgnode) pcg_sibling; 276 LIST_HEAD(,pmcstat_cgnode) pcg_children; 277}; 278 279struct pmcstat_cgnode_hash { 280 struct pmcstat_cgnode *pch_cgnode; 281 uint32_t pch_pmcid; 282 LIST_ENTRY(pmcstat_cgnode_hash) pch_next; 283}; 284 285static int pmcstat_cgnode_hash_count; 286static pmcstat_interned_string pmcstat_previous_filename_printed; 287 288/* 289 * The toplevel CG nodes (i.e., with rank == 0) are placed in a hash table. 290 */ 291 292static LIST_HEAD(,pmcstat_cgnode_hash) pmcstat_cgnode_hash[PMCSTAT_NHASH]; 293 294/* Misc. statistics */ 295static struct pmcstat_stats { 296 int ps_exec_aout; /* # a.out executables seen */ 297 int ps_exec_elf; /* # elf executables seen */ 298 int ps_exec_errors; /* # errors processing executables */ 299 int ps_exec_indeterminable; /* # unknown executables seen */ 300 int ps_samples_total; /* total number of samples processed */ 301 int ps_samples_skipped; /* #samples filtered out for any reason */ 302 int ps_samples_unknown_offset; /* #samples of rank 0 not in a map */ 303 int ps_samples_indeterminable; /* #samples in indeterminable images */ 304 int ps_callchain_dubious_frames;/* #dubious frame pointers seen */ 305} pmcstat_stats; 306 307 308/* | |
309 * Prototypes 310 */ 311 | 225 * Prototypes 226 */ 227 |
312static void pmcstat_gmon_create_file(struct pmcstat_gmonfile *_pgf, 313 struct pmcstat_image *_image); 314static pmcstat_interned_string pmcstat_gmon_create_name(const char *_sd, 315 struct pmcstat_image *_img, pmc_id_t _pmcid); 316static void pmcstat_gmon_map_file(struct pmcstat_gmonfile *_pgf); 317static void pmcstat_gmon_unmap_file(struct pmcstat_gmonfile *_pgf); 318 319static void pmcstat_image_determine_type(struct pmcstat_image *_image, 320 struct pmcstat_args *_a); 321static struct pmcstat_gmonfile *pmcstat_image_find_gmonfile(struct 322 pmcstat_image *_i, pmc_id_t _id); | |
323static struct pmcstat_image *pmcstat_image_from_path(pmcstat_interned_string 324 _path, int _iskernelmodule); | 228static struct pmcstat_image *pmcstat_image_from_path(pmcstat_interned_string 229 _path, int _iskernelmodule); |
325static void pmcstat_image_get_aout_params(struct pmcstat_image *_image, 326 struct pmcstat_args *_a); 327static void pmcstat_image_get_elf_params(struct pmcstat_image *_image, 328 struct pmcstat_args *_a); 329static void pmcstat_image_increment_bucket(struct pmcstat_pcmap *_pcm, 330 uintfptr_t _pc, pmc_id_t _pmcid, struct pmcstat_args *_a); | 230static void pmcstat_image_get_aout_params(struct pmcstat_image *_image); 231static void pmcstat_image_get_elf_params(struct pmcstat_image *_image); |
331static void pmcstat_image_link(struct pmcstat_process *_pp, 332 struct pmcstat_image *_i, uintfptr_t _lpc); 333 334static void pmcstat_pmcid_add(pmc_id_t _pmcid, | 232static void pmcstat_image_link(struct pmcstat_process *_pp, 233 struct pmcstat_image *_i, uintfptr_t _lpc); 234 235static void pmcstat_pmcid_add(pmc_id_t _pmcid, |
335 pmcstat_interned_string _name, struct pmcstat_args *_a); 336static const char *pmcstat_pmcid_to_name(pmc_id_t _pmcid); | 236 pmcstat_interned_string _name); |
337 338static void pmcstat_process_aout_exec(struct pmcstat_process *_pp, | 237 238static void pmcstat_process_aout_exec(struct pmcstat_process *_pp, |
339 struct pmcstat_image *_image, uintfptr_t _entryaddr, 340 struct pmcstat_args *_a); | 239 struct pmcstat_image *_image, uintfptr_t _entryaddr); |
341static void pmcstat_process_elf_exec(struct pmcstat_process *_pp, | 240static void pmcstat_process_elf_exec(struct pmcstat_process *_pp, |
342 struct pmcstat_image *_image, uintfptr_t _entryaddr, 343 struct pmcstat_args *_a); | 241 struct pmcstat_image *_image, uintfptr_t _entryaddr); |
344static void pmcstat_process_exec(struct pmcstat_process *_pp, | 242static void pmcstat_process_exec(struct pmcstat_process *_pp, |
345 pmcstat_interned_string _path, uintfptr_t _entryaddr, 346 struct pmcstat_args *_ao); | 243 pmcstat_interned_string _path, uintfptr_t _entryaddr); |
347static struct pmcstat_process *pmcstat_process_lookup(pid_t _pid, 348 int _allocate); | 244static struct pmcstat_process *pmcstat_process_lookup(pid_t _pid, 245 int _allocate); |
349static struct pmcstat_pcmap *pmcstat_process_find_map( 350 struct pmcstat_process *_p, uintfptr_t _pc); 351 | |
352static int pmcstat_string_compute_hash(const char *_string); 353static void pmcstat_string_initialize(void); | 246static int pmcstat_string_compute_hash(const char *_string); 247static void pmcstat_string_initialize(void); |
354static pmcstat_interned_string pmcstat_string_intern(const char *_s); 355static pmcstat_interned_string pmcstat_string_lookup(const char *_s); | |
356static int pmcstat_string_lookup_hash(pmcstat_interned_string _is); 357static void pmcstat_string_shutdown(void); | 248static int pmcstat_string_lookup_hash(pmcstat_interned_string _is); 249static void pmcstat_string_shutdown(void); |
358static const char *pmcstat_string_unintern(pmcstat_interned_string _is); | |
359 | 250 |
360 | |
361/* 362 * A simple implementation of interned strings. Each interned string 363 * is assigned a unique address, so that subsequent string compares 364 * can be done by a simple pointer comparision instead of using 365 * strcmp(). This speeds up hash table lookups and saves memory if 366 * duplicate strings are the norm. 367 */ 368struct pmcstat_string { 369 LIST_ENTRY(pmcstat_string) ps_next; /* hash link */ 370 int ps_len; 371 int ps_hash; 372 char *ps_string; 373}; 374 375static LIST_HEAD(,pmcstat_string) pmcstat_string_hash[PMCSTAT_NHASH]; 376 377/* | 251/* 252 * A simple implementation of interned strings. Each interned string 253 * is assigned a unique address, so that subsequent string compares 254 * can be done by a simple pointer comparision instead of using 255 * strcmp(). This speeds up hash table lookups and saves memory if 256 * duplicate strings are the norm. 257 */ 258struct pmcstat_string { 259 LIST_ENTRY(pmcstat_string) ps_next; /* hash link */ 260 int ps_len; 261 int ps_hash; 262 char *ps_string; 263}; 264 265static LIST_HEAD(,pmcstat_string) pmcstat_string_hash[PMCSTAT_NHASH]; 266 267/* |
268 * PMC count. 269 */ 270int pmcstat_npmcs; 271 272/* 273 * PMC Top mode pause state. 274 */ 275int pmcstat_pause; 276 277/* |
|
378 * Compute a 'hash' value for a string. 379 */ 380 381static int 382pmcstat_string_compute_hash(const char *s) 383{ 384 int hash; 385 386 for (hash = 0; *s; s++) 387 hash ^= *s; 388 389 return (hash & PMCSTAT_HASH_MASK); 390} 391 392/* 393 * Intern a copy of string 's', and return a pointer to the 394 * interned structure. 395 */ 396 | 278 * Compute a 'hash' value for a string. 279 */ 280 281static int 282pmcstat_string_compute_hash(const char *s) 283{ 284 int hash; 285 286 for (hash = 0; *s; s++) 287 hash ^= *s; 288 289 return (hash & PMCSTAT_HASH_MASK); 290} 291 292/* 293 * Intern a copy of string 's', and return a pointer to the 294 * interned structure. 295 */ 296 |
397static pmcstat_interned_string | 297pmcstat_interned_string |
398pmcstat_string_intern(const char *s) 399{ 400 struct pmcstat_string *ps; 401 const struct pmcstat_string *cps; 402 int hash, len; 403 404 if ((cps = pmcstat_string_lookup(s)) != NULL) 405 return (cps); --- 5 unchanged lines hidden (view full) --- 411 err(EX_OSERR, "ERROR: Could not intern string"); 412 ps->ps_len = len; 413 ps->ps_hash = hash; 414 ps->ps_string = strdup(s); 415 LIST_INSERT_HEAD(&pmcstat_string_hash[hash], ps, ps_next); 416 return ((pmcstat_interned_string) ps); 417} 418 | 298pmcstat_string_intern(const char *s) 299{ 300 struct pmcstat_string *ps; 301 const struct pmcstat_string *cps; 302 int hash, len; 303 304 if ((cps = pmcstat_string_lookup(s)) != NULL) 305 return (cps); --- 5 unchanged lines hidden (view full) --- 311 err(EX_OSERR, "ERROR: Could not intern string"); 312 ps->ps_len = len; 313 ps->ps_hash = hash; 314 ps->ps_string = strdup(s); 315 LIST_INSERT_HEAD(&pmcstat_string_hash[hash], ps, ps_next); 316 return ((pmcstat_interned_string) ps); 317} 318 |
419static const char * | 319const char * |
420pmcstat_string_unintern(pmcstat_interned_string str) 421{ 422 const char *s; 423 424 s = ((const struct pmcstat_string *) str)->ps_string; 425 return (s); 426} 427 | 320pmcstat_string_unintern(pmcstat_interned_string str) 321{ 322 const char *s; 323 324 s = ((const struct pmcstat_string *) str)->ps_string; 325 return (s); 326} 327 |
428static pmcstat_interned_string | 328pmcstat_interned_string |
429pmcstat_string_lookup(const char *s) 430{ 431 struct pmcstat_string *ps; 432 int hash, len; 433 434 hash = pmcstat_string_compute_hash(s); 435 len = strlen(s); 436 --- 41 unchanged lines hidden (view full) --- 478 pstmp) { 479 LIST_REMOVE(ps, ps_next); 480 free(ps->ps_string); 481 free(ps); 482 } 483} 484 485/* | 329pmcstat_string_lookup(const char *s) 330{ 331 struct pmcstat_string *ps; 332 int hash, len; 333 334 hash = pmcstat_string_compute_hash(s); 335 len = strlen(s); 336 --- 41 unchanged lines hidden (view full) --- 378 pstmp) { 379 LIST_REMOVE(ps, ps_next); 380 free(ps->ps_string); 381 free(ps); 382 } 383} 384 385/* |
486 * Create a gmon.out file and size it. 487 */ 488 489static void 490pmcstat_gmon_create_file(struct pmcstat_gmonfile *pgf, 491 struct pmcstat_image *image) 492{ 493 int fd; 494 size_t count; 495 struct gmonhdr gm; 496 const char *pathname; 497 char buffer[DEFAULT_BUFFER_SIZE]; 498 499 pathname = pmcstat_string_unintern(pgf->pgf_name); 500 if ((fd = open(pathname, O_RDWR|O_NOFOLLOW|O_CREAT, 501 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) 502 err(EX_OSERR, "ERROR: Cannot open \"%s\"", pathname); 503 504 gm.lpc = image->pi_start; 505 gm.hpc = image->pi_end; 506 gm.ncnt = (pgf->pgf_nbuckets * sizeof(HISTCOUNTER)) + 507 sizeof(struct gmonhdr); 508 gm.version = GMONVERSION; 509 gm.profrate = 0; /* use ticks */ 510 gm.histcounter_type = 0; /* compatibility with moncontrol() */ 511 gm.spare[0] = gm.spare[1] = 0; 512 513 /* Write out the gmon header */ 514 if (write(fd, &gm, sizeof(gm)) < 0) 515 goto error; 516 517 /* Zero fill the samples[] array */ 518 (void) memset(buffer, 0, sizeof(buffer)); 519 520 count = pgf->pgf_ndatabytes - sizeof(struct gmonhdr); 521 while (count > sizeof(buffer)) { 522 if (write(fd, &buffer, sizeof(buffer)) < 0) 523 goto error; 524 count -= sizeof(buffer); 525 } 526 527 if (write(fd, &buffer, count) < 0) 528 goto error; 529 530 (void) close(fd); 531 532 return; 533 534 error: 535 err(EX_OSERR, "ERROR: Cannot write \"%s\"", pathname); 536} 537 538/* 539 * Determine the full pathname of a gmon.out file for a given 540 * (image,pmcid) combination. Return the interned string. 541 */ 542 543pmcstat_interned_string 544pmcstat_gmon_create_name(const char *samplesdir, struct pmcstat_image *image, 545 pmc_id_t pmcid) 546{ 547 const char *pmcname; 548 char fullpath[PATH_MAX]; 549 550 pmcname = pmcstat_pmcid_to_name(pmcid); 551 552 (void) snprintf(fullpath, sizeof(fullpath), 553 "%s/%s/%s", samplesdir, pmcname, 554 pmcstat_string_unintern(image->pi_samplename)); 555 556 return (pmcstat_string_intern(fullpath)); 557} 558 559 560/* 561 * Mmap in a gmon.out file for processing. 562 */ 563 564static void 565pmcstat_gmon_map_file(struct pmcstat_gmonfile *pgf) 566{ 567 int fd; 568 const char *pathname; 569 570 pathname = pmcstat_string_unintern(pgf->pgf_name); 571 572 /* the gmon.out file must already exist */ 573 if ((fd = open(pathname, O_RDWR | O_NOFOLLOW, 0)) < 0) 574 err(EX_OSERR, "ERROR: cannot open \"%s\"", pathname); 575 576 pgf->pgf_gmondata = mmap(NULL, pgf->pgf_ndatabytes, 577 PROT_READ|PROT_WRITE, MAP_NOSYNC|MAP_SHARED, fd, 0); 578 579 if (pgf->pgf_gmondata == MAP_FAILED) 580 err(EX_OSERR, "ERROR: cannot map \"%s\"", pathname); 581 582 (void) close(fd); 583} 584 585/* 586 * Unmap a gmon.out file after sync'ing its data to disk. 587 */ 588 589static void 590pmcstat_gmon_unmap_file(struct pmcstat_gmonfile *pgf) 591{ 592 (void) msync(pgf->pgf_gmondata, pgf->pgf_ndatabytes, 593 MS_SYNC); 594 (void) munmap(pgf->pgf_gmondata, pgf->pgf_ndatabytes); 595 pgf->pgf_gmondata = NULL; 596} 597 598static void 599pmcstat_gmon_append_arc(struct pmcstat_image *image, pmc_id_t pmcid, 600 uintptr_t rawfrom, uintptr_t rawto, uint32_t count) 601{ 602 struct rawarc arc; /* from <sys/gmon.h> */ 603 const char *pathname; 604 struct pmcstat_gmonfile *pgf; 605 606 if ((pgf = pmcstat_image_find_gmonfile(image, pmcid)) == NULL) 607 return; 608 609 if (pgf->pgf_file == NULL) { 610 pathname = pmcstat_string_unintern(pgf->pgf_name); 611 if ((pgf->pgf_file = fopen(pathname, "a")) == NULL) 612 return; 613 } 614 615 arc.raw_frompc = rawfrom + image->pi_vaddr; 616 arc.raw_selfpc = rawto + image->pi_vaddr; 617 arc.raw_count = count; 618 619 (void) fwrite(&arc, sizeof(arc), 1, pgf->pgf_file); 620 621} 622 623static struct pmcstat_gmonfile * 624pmcstat_image_find_gmonfile(struct pmcstat_image *image, pmc_id_t pmcid) 625{ 626 struct pmcstat_gmonfile *pgf; 627 LIST_FOREACH(pgf, &image->pi_gmlist, pgf_next) 628 if (pgf->pgf_pmcid == pmcid) 629 return (pgf); 630 return (NULL); 631} 632 633 634/* | |
635 * Determine whether a given executable image is an A.OUT object, and 636 * if so, fill in its parameters from the text file. 637 * Sets image->pi_type. 638 */ 639 640static void | 386 * Determine whether a given executable image is an A.OUT object, and 387 * if so, fill in its parameters from the text file. 388 * Sets image->pi_type. 389 */ 390 391static void |
641pmcstat_image_get_aout_params(struct pmcstat_image *image, 642 struct pmcstat_args *a) | 392pmcstat_image_get_aout_params(struct pmcstat_image *image) |
643{ 644 int fd; 645 ssize_t nbytes; 646 struct exec ex; 647 const char *path; 648 char buffer[PATH_MAX]; 649 650 path = pmcstat_string_unintern(image->pi_execpath); 651 assert(path != NULL); 652 653 if (image->pi_iskernelmodule) 654 errx(EX_SOFTWARE, "ERROR: a.out kernel modules are " 655 "unsupported \"%s\"", path); 656 657 (void) snprintf(buffer, sizeof(buffer), "%s%s", | 393{ 394 int fd; 395 ssize_t nbytes; 396 struct exec ex; 397 const char *path; 398 char buffer[PATH_MAX]; 399 400 path = pmcstat_string_unintern(image->pi_execpath); 401 assert(path != NULL); 402 403 if (image->pi_iskernelmodule) 404 errx(EX_SOFTWARE, "ERROR: a.out kernel modules are " 405 "unsupported \"%s\"", path); 406 407 (void) snprintf(buffer, sizeof(buffer), "%s%s", |
658 a->pa_fsroot, path); | 408 args.pa_fsroot, path); |
659 660 if ((fd = open(buffer, O_RDONLY, 0)) < 0 || 661 (nbytes = read(fd, &ex, sizeof(ex))) < 0) { 662 warn("WARNING: Cannot determine type of \"%s\"", path); 663 image->pi_type = PMCSTAT_IMAGE_INDETERMINABLE; 664 if (fd != -1) 665 (void) close(fd); 666 return; --- 30 unchanged lines hidden (view full) --- 697 return (1); 698 return (0); 699} 700 701/* 702 * Map an address to a symbol in an image. 703 */ 704 | 409 410 if ((fd = open(buffer, O_RDONLY, 0)) < 0 || 411 (nbytes = read(fd, &ex, sizeof(ex))) < 0) { 412 warn("WARNING: Cannot determine type of \"%s\"", path); 413 image->pi_type = PMCSTAT_IMAGE_INDETERMINABLE; 414 if (fd != -1) 415 (void) close(fd); 416 return; --- 30 unchanged lines hidden (view full) --- 447 return (1); 448 return (0); 449} 450 451/* 452 * Map an address to a symbol in an image. 453 */ 454 |
705static struct pmcstat_symbol * | 455struct pmcstat_symbol * |
706pmcstat_symbol_search(struct pmcstat_image *image, uintfptr_t addr) 707{ 708 struct pmcstat_symbol sym; 709 710 if (image->pi_symbols == NULL) 711 return (NULL); 712 713 sym.ps_name = NULL; --- 106 unchanged lines hidden (view full) --- 820 821/* 822 * Examine an ELF file to determine the size of its text segment. 823 * Sets image->pi_type if anything conclusive can be determined about 824 * this image. 825 */ 826 827static void | 456pmcstat_symbol_search(struct pmcstat_image *image, uintfptr_t addr) 457{ 458 struct pmcstat_symbol sym; 459 460 if (image->pi_symbols == NULL) 461 return (NULL); 462 463 sym.ps_name = NULL; --- 106 unchanged lines hidden (view full) --- 570 571/* 572 * Examine an ELF file to determine the size of its text segment. 573 * Sets image->pi_type if anything conclusive can be determined about 574 * this image. 575 */ 576 577static void |
828pmcstat_image_get_elf_params(struct pmcstat_image *image, 829 struct pmcstat_args *a) | 578pmcstat_image_get_elf_params(struct pmcstat_image *image) |
830{ 831 int fd; 832 size_t i, nph, nsh; 833 const char *path, *elfbase; | 579{ 580 int fd; 581 size_t i, nph, nsh; 582 const char *path, *elfbase; |
583 char *p, *endp; |
|
834 uintfptr_t minva, maxva; 835 Elf *e; 836 Elf_Scn *scn; 837 GElf_Ehdr eh; 838 GElf_Phdr ph; 839 GElf_Shdr sh; 840 enum pmcstat_image_type image_type; 841 char buffer[PATH_MAX]; --- 11 unchanged lines hidden (view full) --- 853 assert(path != NULL); 854 855 /* 856 * Look for kernel modules under FSROOT/KERNELPATH/NAME, 857 * and user mode executable objects under FSROOT/PATHNAME. 858 */ 859 if (image->pi_iskernelmodule) 860 (void) snprintf(buffer, sizeof(buffer), "%s%s/%s", | 584 uintfptr_t minva, maxva; 585 Elf *e; 586 Elf_Scn *scn; 587 GElf_Ehdr eh; 588 GElf_Phdr ph; 589 GElf_Shdr sh; 590 enum pmcstat_image_type image_type; 591 char buffer[PATH_MAX]; --- 11 unchanged lines hidden (view full) --- 603 assert(path != NULL); 604 605 /* 606 * Look for kernel modules under FSROOT/KERNELPATH/NAME, 607 * and user mode executable objects under FSROOT/PATHNAME. 608 */ 609 if (image->pi_iskernelmodule) 610 (void) snprintf(buffer, sizeof(buffer), "%s%s/%s", |
861 a->pa_fsroot, a->pa_kernel, path); | 611 args.pa_fsroot, args.pa_kernel, path); |
862 else 863 (void) snprintf(buffer, sizeof(buffer), "%s%s", | 612 else 613 (void) snprintf(buffer, sizeof(buffer), "%s%s", |
864 a->pa_fsroot, path); | 614 args.pa_fsroot, path); |
865 866 e = NULL; 867 if ((fd = open(buffer, O_RDONLY, 0)) < 0 || 868 (e = elf_begin(fd, ELF_C_READ, NULL)) == NULL || 869 (elf_kind(e) != ELF_K_ELF)) { 870 warnx("WARNING: Cannot determine the type of \"%s\".", 871 buffer); 872 goto done; --- 82 unchanged lines hidden (view full) --- 955 pmcstat_image_add_symbols(image, e, scn, &sh); 956 } 957 958 image->pi_start = minva; 959 image->pi_end = maxva; 960 image->pi_type = image_type; 961 image->pi_fullpath = pmcstat_string_intern(buffer); 962 | 615 616 e = NULL; 617 if ((fd = open(buffer, O_RDONLY, 0)) < 0 || 618 (e = elf_begin(fd, ELF_C_READ, NULL)) == NULL || 619 (elf_kind(e) != ELF_K_ELF)) { 620 warnx("WARNING: Cannot determine the type of \"%s\".", 621 buffer); 622 goto done; --- 82 unchanged lines hidden (view full) --- 705 pmcstat_image_add_symbols(image, e, scn, &sh); 706 } 707 708 image->pi_start = minva; 709 image->pi_end = maxva; 710 image->pi_type = image_type; 711 image->pi_fullpath = pmcstat_string_intern(buffer); 712 |
713 /* Build display name 714 */ 715 endp = buffer; 716 for (p = buffer; *p; p++) 717 if (*p == '/') 718 endp = p+1; 719 image->pi_name = pmcstat_string_intern(endp); 720 |
|
963 done: 964 (void) elf_end(e); 965 if (fd >= 0) 966 (void) close(fd); 967 return; 968} 969 970/* 971 * Given an image descriptor, determine whether it is an ELF, or AOUT. 972 * If no handler claims the image, set its type to 'INDETERMINABLE'. 973 */ 974 | 721 done: 722 (void) elf_end(e); 723 if (fd >= 0) 724 (void) close(fd); 725 return; 726} 727 728/* 729 * Given an image descriptor, determine whether it is an ELF, or AOUT. 730 * If no handler claims the image, set its type to 'INDETERMINABLE'. 731 */ 732 |
975static void 976pmcstat_image_determine_type(struct pmcstat_image *image, 977 struct pmcstat_args *a) | 733void 734pmcstat_image_determine_type(struct pmcstat_image *image) |
978{ 979 assert(image->pi_type == PMCSTAT_IMAGE_UNKNOWN); 980 981 /* Try each kind of handler in turn */ 982 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) | 735{ 736 assert(image->pi_type == PMCSTAT_IMAGE_UNKNOWN); 737 738 /* Try each kind of handler in turn */ 739 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) |
983 pmcstat_image_get_elf_params(image, a); | 740 pmcstat_image_get_elf_params(image); |
984 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) | 741 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) |
985 pmcstat_image_get_aout_params(image, a); | 742 pmcstat_image_get_aout_params(image); |
986 987 /* 988 * Otherwise, remember that we tried to determine 989 * the object's type and had failed. 990 */ 991 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) 992 image->pi_type = PMCSTAT_IMAGE_INDETERMINABLE; 993} --- 7 unchanged lines hidden (view full) --- 1001 * structure till the time we actually see a sample that would fall 1002 * into this image. 1003 */ 1004 1005static struct pmcstat_image * 1006pmcstat_image_from_path(pmcstat_interned_string internedpath, 1007 int iskernelmodule) 1008{ | 743 744 /* 745 * Otherwise, remember that we tried to determine 746 * the object's type and had failed. 747 */ 748 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) 749 image->pi_type = PMCSTAT_IMAGE_INDETERMINABLE; 750} --- 7 unchanged lines hidden (view full) --- 758 * structure till the time we actually see a sample that would fall 759 * into this image. 760 */ 761 762static struct pmcstat_image * 763pmcstat_image_from_path(pmcstat_interned_string internedpath, 764 int iskernelmodule) 765{ |
1009 int count, hash, nlen; | 766 int hash; |
1010 struct pmcstat_image *pi; | 767 struct pmcstat_image *pi; |
1011 char *sn; 1012 char name[NAME_MAX]; | |
1013 1014 hash = pmcstat_string_lookup_hash(internedpath); 1015 1016 /* First, look for an existing entry. */ 1017 LIST_FOREACH(pi, &pmcstat_image_hash[hash], pi_next) 1018 if (pi->pi_execpath == internedpath && 1019 pi->pi_iskernelmodule == iskernelmodule) 1020 return (pi); --- 12 unchanged lines hidden (view full) --- 1033 pi->pi_end = 0; 1034 pi->pi_entry = 0; 1035 pi->pi_vaddr = 0; 1036 pi->pi_isdynamic = 0; 1037 pi->pi_iskernelmodule = iskernelmodule; 1038 pi->pi_dynlinkerpath = NULL; 1039 pi->pi_symbols = NULL; 1040 pi->pi_symcount = 0; | 768 769 hash = pmcstat_string_lookup_hash(internedpath); 770 771 /* First, look for an existing entry. */ 772 LIST_FOREACH(pi, &pmcstat_image_hash[hash], pi_next) 773 if (pi->pi_execpath == internedpath && 774 pi->pi_iskernelmodule == iskernelmodule) 775 return (pi); --- 12 unchanged lines hidden (view full) --- 788 pi->pi_end = 0; 789 pi->pi_entry = 0; 790 pi->pi_vaddr = 0; 791 pi->pi_isdynamic = 0; 792 pi->pi_iskernelmodule = iskernelmodule; 793 pi->pi_dynlinkerpath = NULL; 794 pi->pi_symbols = NULL; 795 pi->pi_symcount = 0; |
796 pi->pi_addr2line = NULL; |
|
1041 | 797 |
1042 /* 1043 * Look for a suitable name for the sample files associated 1044 * with this image: if `basename(path)`+".gmon" is available, 1045 * we use that, otherwise we try iterating through 1046 * `basename(path)`+ "~" + NNN + ".gmon" till we get a free 1047 * entry. 1048 */ 1049 if ((sn = basename(pmcstat_string_unintern(internedpath))) == NULL) 1050 err(EX_OSERR, "ERROR: Cannot process \"%s\"", 1051 pmcstat_string_unintern(internedpath)); | 798 if (plugins[args.pa_pplugin].pl_initimage != NULL) 799 plugins[args.pa_pplugin].pl_initimage(pi); 800 if (plugins[args.pa_plugin].pl_initimage != NULL) 801 plugins[args.pa_plugin].pl_initimage(pi); |
1052 | 802 |
1053 nlen = strlen(sn); 1054 nlen = min(nlen, (int) (sizeof(name) - sizeof(".gmon"))); 1055 1056 snprintf(name, sizeof(name), "%.*s.gmon", nlen, sn); 1057 1058 /* try use the unabridged name first */ 1059 if (pmcstat_string_lookup(name) == NULL) 1060 pi->pi_samplename = pmcstat_string_intern(name); 1061 else { 1062 /* 1063 * Otherwise use a prefix from the original name and 1064 * upto 3 digits. 1065 */ 1066 nlen = strlen(sn); 1067 nlen = min(nlen, (int) (sizeof(name)-sizeof("~NNN.gmon"))); 1068 count = 0; 1069 do { 1070 if (++count > 999) 1071 errx(EX_CANTCREAT, "ERROR: cannot create a " 1072 "gmon file for \"%s\"", name); 1073 snprintf(name, sizeof(name), "%.*s~%3.3d.gmon", 1074 nlen, sn, count); 1075 if (pmcstat_string_lookup(name) == NULL) { 1076 pi->pi_samplename = 1077 pmcstat_string_intern(name); 1078 count = 0; 1079 } 1080 } while (count > 0); 1081 } 1082 1083 1084 LIST_INIT(&pi->pi_gmlist); 1085 | |
1086 LIST_INSERT_HEAD(&pmcstat_image_hash[hash], pi, pi_next); 1087 1088 return (pi); 1089} 1090 1091/* | 803 LIST_INSERT_HEAD(&pmcstat_image_hash[hash], pi, pi_next); 804 805 return (pi); 806} 807 808/* |
1092 * Increment the bucket in the gmon.out file corresponding to 'pmcid' 1093 * and 'pc'. 1094 */ 1095 1096static void 1097pmcstat_image_increment_bucket(struct pmcstat_pcmap *map, uintfptr_t pc, 1098 pmc_id_t pmcid, struct pmcstat_args *a) 1099{ 1100 struct pmcstat_image *image; 1101 struct pmcstat_gmonfile *pgf; 1102 uintfptr_t bucket; 1103 HISTCOUNTER *hc; 1104 1105 assert(pc >= map->ppm_lowpc && pc < map->ppm_highpc); 1106 1107 image = map->ppm_image; 1108 1109 /* 1110 * If this is the first time we are seeing a sample for 1111 * this executable image, try determine its parameters. 1112 */ 1113 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) 1114 pmcstat_image_determine_type(image, a); 1115 1116 assert(image->pi_type != PMCSTAT_IMAGE_UNKNOWN); 1117 1118 /* Ignore samples in images that we know nothing about. */ 1119 if (image->pi_type == PMCSTAT_IMAGE_INDETERMINABLE) { 1120 pmcstat_stats.ps_samples_indeterminable++; 1121 return; 1122 } 1123 1124 /* 1125 * Find the gmon file corresponding to 'pmcid', creating it if 1126 * needed. 1127 */ 1128 pgf = pmcstat_image_find_gmonfile(image, pmcid); 1129 if (pgf == NULL) { 1130 if ((pgf = calloc(1, sizeof(*pgf))) == NULL) 1131 err(EX_OSERR, "ERROR:"); 1132 1133 pgf->pgf_gmondata = NULL; /* mark as unmapped */ 1134 pgf->pgf_name = pmcstat_gmon_create_name(a->pa_samplesdir, 1135 image, pmcid); 1136 pgf->pgf_pmcid = pmcid; 1137 assert(image->pi_end > image->pi_start); 1138 pgf->pgf_nbuckets = (image->pi_end - image->pi_start) / 1139 FUNCTION_ALIGNMENT; /* see <machine/profile.h> */ 1140 pgf->pgf_ndatabytes = sizeof(struct gmonhdr) + 1141 pgf->pgf_nbuckets * sizeof(HISTCOUNTER); 1142 pgf->pgf_nsamples = 0; 1143 pgf->pgf_file = NULL; 1144 1145 pmcstat_gmon_create_file(pgf, image); 1146 1147 LIST_INSERT_HEAD(&image->pi_gmlist, pgf, pgf_next); 1148 } 1149 1150 /* 1151 * Map the gmon file in if needed. It may have been mapped 1152 * out under memory pressure. 1153 */ 1154 if (pgf->pgf_gmondata == NULL) 1155 pmcstat_gmon_map_file(pgf); 1156 1157 assert(pgf->pgf_gmondata != NULL); 1158 1159 /* 1160 * 1161 */ 1162 1163 bucket = (pc - map->ppm_lowpc) / FUNCTION_ALIGNMENT; 1164 1165 assert(bucket < pgf->pgf_nbuckets); 1166 1167 hc = (HISTCOUNTER *) ((uintptr_t) pgf->pgf_gmondata + 1168 sizeof(struct gmonhdr)); 1169 1170 /* saturating add */ 1171 if (hc[bucket] < 0xFFFFU) /* XXX tie this to sizeof(HISTCOUNTER) */ 1172 hc[bucket]++; 1173 else /* mark that an overflow occurred */ 1174 pgf->pgf_overflow = 1; 1175 1176 pgf->pgf_nsamples++; 1177} 1178 1179/* | |
1180 * Record the fact that PC values from 'start' to 'end' come from 1181 * image 'image'. 1182 */ 1183 1184static void 1185pmcstat_image_link(struct pmcstat_process *pp, struct pmcstat_image *image, 1186 uintfptr_t start) 1187{ --- 91 unchanged lines hidden (view full) --- 1279 else if (pcm->ppm_lowpc >= start && pcm->ppm_highpc > end) 1280 pcm->ppm_lowpc = end; 1281 else 1282 assert(0); 1283 } 1284} 1285 1286/* | 809 * Record the fact that PC values from 'start' to 'end' come from 810 * image 'image'. 811 */ 812 813static void 814pmcstat_image_link(struct pmcstat_process *pp, struct pmcstat_image *image, 815 uintfptr_t start) 816{ --- 91 unchanged lines hidden (view full) --- 908 else if (pcm->ppm_lowpc >= start && pcm->ppm_highpc > end) 909 pcm->ppm_lowpc = end; 910 else 911 assert(0); 912 } 913} 914 915/* |
916 * Resolve file name and line number for the given address. 917 */ 918int 919pmcstat_image_addr2line(struct pmcstat_image *image, uintfptr_t addr, 920 char *sourcefile, size_t sourcefile_len, unsigned *sourceline, 921 char *funcname, size_t funcname_len) 922{ 923 static int addr2line_warn = 0; 924 925 char *sep, cmdline[PATH_MAX], imagepath[PATH_MAX]; 926 int fd; 927 928 if (image->pi_addr2line == NULL) { 929 snprintf(imagepath, sizeof(imagepath), "%s.symbols", 930 pmcstat_string_unintern(image->pi_fullpath)); 931 fd = open(imagepath, O_RDONLY); 932 if (fd < 0) { 933 snprintf(imagepath, sizeof(imagepath), "%s", 934 pmcstat_string_unintern(image->pi_fullpath)); 935 } else 936 close(fd); 937 snprintf(cmdline, sizeof(cmdline), "addr2line -Cfe \"%s\"", 938 imagepath); 939 image->pi_addr2line = popen(cmdline, "r+"); 940 if (image->pi_addr2line == NULL) { 941 if (!addr2line_warn) { 942 addr2line_warn = 1; 943 warnx("WARNING: addr2line is needed" 944 "for source code information."); 945 } 946 return (0); 947 } 948 } 949 950 if (feof(image->pi_addr2line) || ferror(image->pi_addr2line)) { 951 warnx("WARNING: addr2line pipe error"); 952 pclose(image->pi_addr2line); 953 image->pi_addr2line = NULL; 954 return (0); 955 } 956 957 fprintf(image->pi_addr2line, "%p\n", (void *)addr); 958 959 if (fgets(funcname, funcname_len, image->pi_addr2line) == NULL) { 960 warnx("WARNING: addr2line function name read error"); 961 return (0); 962 } 963 sep = strchr(funcname, '\n'); 964 if (sep != NULL) 965 *sep = '\0'; 966 967 if (fgets(sourcefile, sourcefile_len, image->pi_addr2line) == NULL) { 968 warnx("WARNING: addr2line source file read error"); 969 return (0); 970 } 971 sep = strchr(sourcefile, ':'); 972 if (sep == NULL) { 973 warnx("WARNING: addr2line source line separator missing"); 974 return (0); 975 } 976 *sep = '\0'; 977 *sourceline = atoi(sep+1); 978 if (*sourceline == 0) 979 return (0); 980 981 return (1); 982} 983 984/* |
|
1287 * Add a {pmcid,name} mapping. 1288 */ 1289 1290static void | 985 * Add a {pmcid,name} mapping. 986 */ 987 988static void |
1291pmcstat_pmcid_add(pmc_id_t pmcid, pmcstat_interned_string ps, 1292 struct pmcstat_args *a) | 989pmcstat_pmcid_add(pmc_id_t pmcid, pmcstat_interned_string ps) |
1293{ | 990{ |
1294 struct pmcstat_pmcrecord *pr; 1295 struct stat st; 1296 char fullpath[PATH_MAX]; | 991 struct pmcstat_pmcrecord *pr, *prm; |
1297 1298 /* Replace an existing name for the PMC. */ | 992 993 /* Replace an existing name for the PMC. */ |
994 prm = NULL; |
|
1299 LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) | 995 LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) |
1300 if (pr->pr_pmcid == pmcid) { 1301 pr->pr_pmcname = ps; 1302 return; 1303 } | 996 if (pr->pr_pmcid == pmcid) { 997 pr->pr_pmcname = ps; 998 return; 999 } else if (pr->pr_pmcname == ps) 1000 prm = pr; |
1304 1305 /* | 1001 1002 /* |
1306 * Otherwise, allocate a new descriptor and create the 1307 * appropriate directory to hold gmon.out files. | 1003 * Otherwise, allocate a new descriptor and call the 1004 * plugins hook. |
1308 */ 1309 if ((pr = malloc(sizeof(*pr))) == NULL) 1310 err(EX_OSERR, "ERROR: Cannot allocate pmc record"); 1311 1312 pr->pr_pmcid = pmcid; 1313 pr->pr_pmcname = ps; | 1005 */ 1006 if ((pr = malloc(sizeof(*pr))) == NULL) 1007 err(EX_OSERR, "ERROR: Cannot allocate pmc record"); 1008 1009 pr->pr_pmcid = pmcid; 1010 pr->pr_pmcname = ps; |
1011 pr->pr_pmcin = pmcstat_npmcs++; 1012 pr->pr_merge = prm == NULL ? pr : prm; 1013 |
|
1314 LIST_INSERT_HEAD(&pmcstat_pmcs, pr, pr_next); 1315 | 1014 LIST_INSERT_HEAD(&pmcstat_pmcs, pr, pr_next); 1015 |
1316 (void) snprintf(fullpath, sizeof(fullpath), "%s/%s", a->pa_samplesdir, 1317 pmcstat_string_unintern(ps)); 1318 1319 /* If the path name exists, it should be a directory */ 1320 if (stat(fullpath, &st) == 0 && S_ISDIR(st.st_mode)) 1321 return; 1322 1323 if (mkdir(fullpath, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) < 0) 1324 err(EX_OSERR, "ERROR: Cannot create directory \"%s\"", 1325 fullpath); | 1016 if (plugins[args.pa_pplugin].pl_newpmc != NULL) 1017 plugins[args.pa_pplugin].pl_newpmc(ps, pr); 1018 if (plugins[args.pa_plugin].pl_newpmc != NULL) 1019 plugins[args.pa_plugin].pl_newpmc(ps, pr); |
1326} 1327 1328/* 1329 * Given a pmcid in use, find its human-readable name. 1330 */ 1331 | 1020} 1021 1022/* 1023 * Given a pmcid in use, find its human-readable name. 1024 */ 1025 |
1332static const char * | 1026const char * |
1333pmcstat_pmcid_to_name(pmc_id_t pmcid) 1334{ 1335 struct pmcstat_pmcrecord *pr; | 1027pmcstat_pmcid_to_name(pmc_id_t pmcid) 1028{ 1029 struct pmcstat_pmcrecord *pr; |
1336 char fullpath[PATH_MAX]; | |
1337 1338 LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) 1339 if (pr->pr_pmcid == pmcid) 1340 return (pmcstat_string_unintern(pr->pr_pmcname)); 1341 | 1030 1031 LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) 1032 if (pr->pr_pmcid == pmcid) 1033 return (pmcstat_string_unintern(pr->pr_pmcname)); 1034 |
1342 /* create a default name and add this entry */ 1343 if ((pr = malloc(sizeof(*pr))) == NULL) 1344 err(EX_OSERR, "ERROR: "); 1345 pr->pr_pmcid = pmcid; | 1035 err(EX_SOFTWARE, "ERROR: cannot find pmcid"); 1036 return NULL; 1037} |
1346 | 1038 |
1347 (void) snprintf(fullpath, sizeof(fullpath), "%X", (unsigned int) pmcid); 1348 pr->pr_pmcname = pmcstat_string_intern(fullpath); | 1039/* 1040 * Convert PMC index to name. 1041 */ |
1349 | 1042 |
1350 LIST_INSERT_HEAD(&pmcstat_pmcs, pr, pr_next); | 1043const char * 1044pmcstat_pmcindex_to_name(int pmcin) 1045{ 1046 struct pmcstat_pmcrecord *pr; |
1351 | 1047 |
1352 return (pmcstat_string_unintern(pr->pr_pmcname)); | 1048 LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) 1049 if (pr->pr_pmcin == pmcin) 1050 return pmcstat_string_unintern(pr->pr_pmcname); 1051 1052 err(EX_SOFTWARE, "ERROR: cannot find pmcid name"); 1053 return NULL; |
1353} 1354 1355/* | 1054} 1055 1056/* |
1057 * Return PMC record with given index. 1058 */ 1059 1060struct pmcstat_pmcrecord * 1061pmcstat_pmcindex_to_pmcr(int pmcin) 1062{ 1063 struct pmcstat_pmcrecord *pr; 1064 1065 LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) 1066 if (pr->pr_pmcin == pmcin) 1067 return pr; 1068 1069 err(EX_SOFTWARE, "ERROR: invalid pmcindex"); 1070 return NULL; 1071} 1072 1073/* 1074 * Get PMC record by id, apply merge policy. 1075 */ 1076 1077static struct pmcstat_pmcrecord * 1078pmcstat_lookup_pmcid(pmc_id_t pmcid) 1079{ 1080 struct pmcstat_pmcrecord *pr; 1081 1082 LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) { 1083 if (pr->pr_pmcid == pmcid) { 1084 if (pmcstat_mergepmc) 1085 return pr->pr_merge; 1086 return pr; 1087 } 1088 } 1089 1090 return NULL; 1091} 1092 1093/* |
|
1356 * Associate an AOUT image with a process. 1357 */ 1358 1359static void 1360pmcstat_process_aout_exec(struct pmcstat_process *pp, | 1094 * Associate an AOUT image with a process. 1095 */ 1096 1097static void 1098pmcstat_process_aout_exec(struct pmcstat_process *pp, |
1361 struct pmcstat_image *image, uintfptr_t entryaddr, 1362 struct pmcstat_args *a) | 1099 struct pmcstat_image *image, uintfptr_t entryaddr) |
1363{ 1364 (void) pp; 1365 (void) image; 1366 (void) entryaddr; | 1100{ 1101 (void) pp; 1102 (void) image; 1103 (void) entryaddr; |
1367 (void) a; | |
1368 /* TODO Implement a.out handling */ 1369} 1370 1371/* 1372 * Associate an ELF image with a process. 1373 */ 1374 1375static void 1376pmcstat_process_elf_exec(struct pmcstat_process *pp, | 1104 /* TODO Implement a.out handling */ 1105} 1106 1107/* 1108 * Associate an ELF image with a process. 1109 */ 1110 1111static void 1112pmcstat_process_elf_exec(struct pmcstat_process *pp, |
1377 struct pmcstat_image *image, uintfptr_t entryaddr, 1378 struct pmcstat_args *a) | 1113 struct pmcstat_image *image, uintfptr_t entryaddr) |
1379{ 1380 uintmax_t libstart; 1381 struct pmcstat_image *rtldimage; 1382 1383 assert(image->pi_type == PMCSTAT_IMAGE_ELF32 || 1384 image->pi_type == PMCSTAT_IMAGE_ELF64); 1385 1386 /* Create a map entry for the base executable. */ --- 22 unchanged lines hidden (view full) --- 1409 * will vary according to the size of the executable 1410 * and the limits on the size of the process'es data 1411 * segment at the time of exec(). The entry address 1412 * recorded at process exec time corresponds to the 1413 * 'start' address inside the dynamic linker. From 1414 * this we can figure out the address where the 1415 * runtime loader's file object had been mapped to. 1416 */ | 1114{ 1115 uintmax_t libstart; 1116 struct pmcstat_image *rtldimage; 1117 1118 assert(image->pi_type == PMCSTAT_IMAGE_ELF32 || 1119 image->pi_type == PMCSTAT_IMAGE_ELF64); 1120 1121 /* Create a map entry for the base executable. */ --- 22 unchanged lines hidden (view full) --- 1144 * will vary according to the size of the executable 1145 * and the limits on the size of the process'es data 1146 * segment at the time of exec(). The entry address 1147 * recorded at process exec time corresponds to the 1148 * 'start' address inside the dynamic linker. From 1149 * this we can figure out the address where the 1150 * runtime loader's file object had been mapped to. 1151 */ |
1417 rtldimage = pmcstat_image_from_path(image->pi_dynlinkerpath, 1418 0); | 1152 rtldimage = pmcstat_image_from_path(image->pi_dynlinkerpath, 0); |
1419 if (rtldimage == NULL) { 1420 warnx("WARNING: Cannot find image for \"%s\".", 1421 pmcstat_string_unintern(image->pi_dynlinkerpath)); 1422 pmcstat_stats.ps_exec_errors++; 1423 return; 1424 } 1425 1426 if (rtldimage->pi_type == PMCSTAT_IMAGE_UNKNOWN) | 1153 if (rtldimage == NULL) { 1154 warnx("WARNING: Cannot find image for \"%s\".", 1155 pmcstat_string_unintern(image->pi_dynlinkerpath)); 1156 pmcstat_stats.ps_exec_errors++; 1157 return; 1158 } 1159 1160 if (rtldimage->pi_type == PMCSTAT_IMAGE_UNKNOWN) |
1427 pmcstat_image_get_elf_params(rtldimage, a); | 1161 pmcstat_image_get_elf_params(rtldimage); |
1428 1429 if (rtldimage->pi_type != PMCSTAT_IMAGE_ELF32 && 1430 rtldimage->pi_type != PMCSTAT_IMAGE_ELF64) { 1431 warnx("WARNING: rtld not an ELF object \"%s\".", 1432 pmcstat_string_unintern(image->pi_dynlinkerpath)); 1433 return; 1434 } 1435 --- 54 unchanged lines hidden (view full) --- 1490} 1491 1492/* 1493 * Associate an image and a process. 1494 */ 1495 1496static void 1497pmcstat_process_exec(struct pmcstat_process *pp, | 1162 1163 if (rtldimage->pi_type != PMCSTAT_IMAGE_ELF32 && 1164 rtldimage->pi_type != PMCSTAT_IMAGE_ELF64) { 1165 warnx("WARNING: rtld not an ELF object \"%s\".", 1166 pmcstat_string_unintern(image->pi_dynlinkerpath)); 1167 return; 1168 } 1169 --- 54 unchanged lines hidden (view full) --- 1224} 1225 1226/* 1227 * Associate an image and a process. 1228 */ 1229 1230static void 1231pmcstat_process_exec(struct pmcstat_process *pp, |
1498 pmcstat_interned_string path, uintfptr_t entryaddr, 1499 struct pmcstat_args *a) | 1232 pmcstat_interned_string path, uintfptr_t entryaddr) |
1500{ 1501 struct pmcstat_image *image; 1502 1503 if ((image = pmcstat_image_from_path(path, 0)) == NULL) { 1504 pmcstat_stats.ps_exec_errors++; 1505 return; 1506 } 1507 1508 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) | 1233{ 1234 struct pmcstat_image *image; 1235 1236 if ((image = pmcstat_image_from_path(path, 0)) == NULL) { 1237 pmcstat_stats.ps_exec_errors++; 1238 return; 1239 } 1240 1241 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) |
1509 pmcstat_image_determine_type(image, a); | 1242 pmcstat_image_determine_type(image); |
1510 1511 assert(image->pi_type != PMCSTAT_IMAGE_UNKNOWN); 1512 1513 switch (image->pi_type) { 1514 case PMCSTAT_IMAGE_ELF32: 1515 case PMCSTAT_IMAGE_ELF64: 1516 pmcstat_stats.ps_exec_elf++; | 1243 1244 assert(image->pi_type != PMCSTAT_IMAGE_UNKNOWN); 1245 1246 switch (image->pi_type) { 1247 case PMCSTAT_IMAGE_ELF32: 1248 case PMCSTAT_IMAGE_ELF64: 1249 pmcstat_stats.ps_exec_elf++; |
1517 pmcstat_process_elf_exec(pp, image, entryaddr, a); | 1250 pmcstat_process_elf_exec(pp, image, entryaddr); |
1518 break; 1519 1520 case PMCSTAT_IMAGE_AOUT: 1521 pmcstat_stats.ps_exec_aout++; | 1251 break; 1252 1253 case PMCSTAT_IMAGE_AOUT: 1254 pmcstat_stats.ps_exec_aout++; |
1522 pmcstat_process_aout_exec(pp, image, entryaddr, a); | 1255 pmcstat_process_aout_exec(pp, image, entryaddr); |
1523 break; 1524 1525 case PMCSTAT_IMAGE_INDETERMINABLE: 1526 pmcstat_stats.ps_exec_indeterminable++; 1527 break; 1528 1529 default: 1530 err(EX_SOFTWARE, "ERROR: Unsupported executable type for " 1531 "\"%s\"", pmcstat_string_unintern(path)); 1532 } 1533} 1534 1535 1536/* 1537 * Find the map entry associated with process 'p' at PC value 'pc'. 1538 */ 1539 | 1256 break; 1257 1258 case PMCSTAT_IMAGE_INDETERMINABLE: 1259 pmcstat_stats.ps_exec_indeterminable++; 1260 break; 1261 1262 default: 1263 err(EX_SOFTWARE, "ERROR: Unsupported executable type for " 1264 "\"%s\"", pmcstat_string_unintern(path)); 1265 } 1266} 1267 1268 1269/* 1270 * Find the map entry associated with process 'p' at PC value 'pc'. 1271 */ 1272 |
1540static struct pmcstat_pcmap * | 1273struct pmcstat_pcmap * |
1541pmcstat_process_find_map(struct pmcstat_process *p, uintfptr_t pc) 1542{ 1543 struct pmcstat_pcmap *ppm; 1544 1545 TAILQ_FOREACH(ppm, &p->pp_map, ppm_next) { 1546 if (pc >= ppm->ppm_lowpc && pc < ppm->ppm_highpc) 1547 return (ppm); 1548 if (pc < ppm->ppm_lowpc) 1549 return (NULL); 1550 } 1551 1552 return (NULL); 1553} 1554 | 1274pmcstat_process_find_map(struct pmcstat_process *p, uintfptr_t pc) 1275{ 1276 struct pmcstat_pcmap *ppm; 1277 1278 TAILQ_FOREACH(ppm, &p->pp_map, ppm_next) { 1279 if (pc >= ppm->ppm_lowpc && pc < ppm->ppm_highpc) 1280 return (ppm); 1281 if (pc < ppm->ppm_lowpc) 1282 return (NULL); 1283 } 1284 1285 return (NULL); 1286} 1287 |
1555static struct pmcstat_cgnode * 1556pmcstat_cgnode_allocate(struct pmcstat_image *image, uintfptr_t pc) 1557{ 1558 struct pmcstat_cgnode *cg; 1559 1560 if ((cg = malloc(sizeof(*cg))) == NULL) 1561 err(EX_OSERR, "ERROR: Cannot allocate callgraph node"); 1562 1563 cg->pcg_image = image; 1564 cg->pcg_func = pc; 1565 1566 cg->pcg_count = 0; 1567 cg->pcg_nchildren = 0; 1568 LIST_INIT(&cg->pcg_children); 1569 1570 return (cg); 1571} 1572 | |
1573/* | 1288/* |
1574 * Free a node and its children. 1575 */ 1576static void 1577pmcstat_cgnode_free(struct pmcstat_cgnode *cg) 1578{ 1579 struct pmcstat_cgnode *cgc, *cgtmp; 1580 1581 LIST_FOREACH_SAFE(cgc, &cg->pcg_children, pcg_sibling, cgtmp) 1582 pmcstat_cgnode_free(cgc); 1583 free(cg); 1584} 1585 1586/* 1587 * Look for a callgraph node associated with pmc `pmcid' in the global 1588 * hash table that corresponds to the given `pc' value in the process 1589 * `pp'. 1590 */ 1591static struct pmcstat_cgnode * 1592pmcstat_cgnode_hash_lookup_pc(struct pmcstat_process *pp, uint32_t pmcid, 1593 uintfptr_t pc, int usermode) 1594{ 1595 struct pmcstat_pcmap *ppm; 1596 struct pmcstat_symbol *sym; 1597 struct pmcstat_image *image; 1598 struct pmcstat_cgnode *cg; 1599 struct pmcstat_cgnode_hash *h; 1600 uintfptr_t loadaddress; 1601 unsigned int i, hash; 1602 1603 ppm = pmcstat_process_find_map(usermode ? pp : pmcstat_kernproc, pc); 1604 if (ppm == NULL) 1605 return (NULL); 1606 1607 image = ppm->ppm_image; 1608 1609 loadaddress = ppm->ppm_lowpc + image->pi_vaddr - image->pi_start; 1610 pc -= loadaddress; /* Convert to an offset in the image. */ 1611 1612 /* 1613 * Try determine the function at this offset. If we can't 1614 * find a function round leave the `pc' value alone. 1615 */ 1616 if ((sym = pmcstat_symbol_search(image, pc)) != NULL) 1617 pc = sym->ps_start; 1618 1619 for (hash = i = 0; i < sizeof(uintfptr_t); i++) 1620 hash += (pc >> i) & 0xFF; 1621 1622 hash &= PMCSTAT_HASH_MASK; 1623 1624 cg = NULL; 1625 LIST_FOREACH(h, &pmcstat_cgnode_hash[hash], pch_next) 1626 { 1627 if (h->pch_pmcid != pmcid) 1628 continue; 1629 1630 cg = h->pch_cgnode; 1631 1632 assert(cg != NULL); 1633 1634 if (cg->pcg_image == image && cg->pcg_func == pc) 1635 return (cg); 1636 } 1637 1638 /* 1639 * We haven't seen this (pmcid, pc) tuple yet, so allocate a 1640 * new callgraph node and a new hash table entry for it. 1641 */ 1642 cg = pmcstat_cgnode_allocate(image, pc); 1643 if ((h = malloc(sizeof(*h))) == NULL) 1644 err(EX_OSERR, "ERROR: Could not allocate callgraph node"); 1645 1646 h->pch_pmcid = pmcid; 1647 h->pch_cgnode = cg; 1648 LIST_INSERT_HEAD(&pmcstat_cgnode_hash[hash], h, pch_next); 1649 1650 pmcstat_cgnode_hash_count++; 1651 1652 return (cg); 1653} 1654 1655/* 1656 * Compare two callgraph nodes for sorting. 1657 */ 1658static int 1659pmcstat_cgnode_compare(const void *a, const void *b) 1660{ 1661 const struct pmcstat_cgnode *const *pcg1, *const *pcg2, *cg1, *cg2; 1662 1663 pcg1 = (const struct pmcstat_cgnode *const *) a; 1664 cg1 = *pcg1; 1665 pcg2 = (const struct pmcstat_cgnode *const *) b; 1666 cg2 = *pcg2; 1667 1668 /* Sort in reverse order */ 1669 if (cg1->pcg_count < cg2->pcg_count) 1670 return (1); 1671 if (cg1->pcg_count > cg2->pcg_count) 1672 return (-1); 1673 return (0); 1674} 1675 1676/* 1677 * Find (allocating if a needed) a callgraph node in the given 1678 * parent with the same (image, pcoffset) pair. 1679 */ 1680 1681static struct pmcstat_cgnode * 1682pmcstat_cgnode_find(struct pmcstat_cgnode *parent, struct pmcstat_image *image, 1683 uintfptr_t pcoffset) 1684{ 1685 struct pmcstat_cgnode *child; 1686 1687 LIST_FOREACH(child, &parent->pcg_children, pcg_sibling) { 1688 if (child->pcg_image == image && 1689 child->pcg_func == pcoffset) 1690 return (child); 1691 } 1692 1693 /* 1694 * Allocate a new structure. 1695 */ 1696 1697 child = pmcstat_cgnode_allocate(image, pcoffset); 1698 1699 /* 1700 * Link it into the parent. 1701 */ 1702 LIST_INSERT_HEAD(&parent->pcg_children, child, pcg_sibling); 1703 parent->pcg_nchildren++; 1704 1705 return (child); 1706} 1707 1708/* 1709 * Print one callgraph node. The output format is: 1710 * 1711 * indentation %(parent's samples) #nsamples function@object 1712 */ 1713static void 1714pmcstat_cgnode_print(struct pmcstat_args *a, struct pmcstat_cgnode *cg, 1715 int depth, uint32_t total) 1716{ 1717 uint32_t n; 1718 const char *space; 1719 struct pmcstat_symbol *sym; 1720 struct pmcstat_cgnode **sortbuffer, **cgn, *pcg; 1721 1722 space = " "; 1723 1724 if (depth > 0) 1725 (void) fprintf(a->pa_graphfile, "%*s", depth, space); 1726 1727 if (cg->pcg_count == total) 1728 (void) fprintf(a->pa_graphfile, "100.0%% "); 1729 else 1730 (void) fprintf(a->pa_graphfile, "%05.2f%% ", 1731 100.0 * cg->pcg_count / total); 1732 1733 n = fprintf(a->pa_graphfile, " [%u] ", cg->pcg_count); 1734 1735 /* #samples is a 12 character wide field. */ 1736 if (n < 12) 1737 (void) fprintf(a->pa_graphfile, "%*s", 12 - n, space); 1738 1739 if (depth > 0) 1740 (void) fprintf(a->pa_graphfile, "%*s", depth, space); 1741 1742 sym = pmcstat_symbol_search(cg->pcg_image, cg->pcg_func); 1743 if (sym) 1744 (void) fprintf(a->pa_graphfile, "%s", 1745 pmcstat_string_unintern(sym->ps_name)); 1746 else 1747 (void) fprintf(a->pa_graphfile, "%p", 1748 (void *) (cg->pcg_image->pi_vaddr + cg->pcg_func)); 1749 1750 if (pmcstat_previous_filename_printed != 1751 cg->pcg_image->pi_fullpath) { 1752 pmcstat_previous_filename_printed = cg->pcg_image->pi_fullpath; 1753 (void) fprintf(a->pa_graphfile, " @ %s\n", 1754 pmcstat_string_unintern( 1755 pmcstat_previous_filename_printed)); 1756 } else 1757 (void) fprintf(a->pa_graphfile, "\n"); 1758 1759 if (cg->pcg_nchildren == 0) 1760 return; 1761 1762 if ((sortbuffer = (struct pmcstat_cgnode **) 1763 malloc(sizeof(struct pmcstat_cgnode *) * 1764 cg->pcg_nchildren)) == NULL) 1765 err(EX_OSERR, "ERROR: Cannot print callgraph"); 1766 cgn = sortbuffer; 1767 1768 LIST_FOREACH(pcg, &cg->pcg_children, pcg_sibling) 1769 *cgn++ = pcg; 1770 1771 assert(cgn - sortbuffer == (int) cg->pcg_nchildren); 1772 1773 qsort(sortbuffer, cg->pcg_nchildren, sizeof(struct pmcstat_cgnode *), 1774 pmcstat_cgnode_compare); 1775 1776 for (cgn = sortbuffer, n = 0; n < cg->pcg_nchildren; n++, cgn++) 1777 pmcstat_cgnode_print(a, *cgn, depth+1, cg->pcg_count); 1778 1779 free(sortbuffer); 1780} 1781 1782/* 1783 * Record a callchain. 1784 */ 1785 1786static void 1787pmcstat_record_callchain(struct pmcstat_process *pp, uint32_t pmcid, 1788 uint32_t nsamples, uintfptr_t *cc, int usermode, struct pmcstat_args *a) 1789{ 1790 uintfptr_t pc, loadaddress; 1791 uint32_t n; 1792 struct pmcstat_image *image; 1793 struct pmcstat_pcmap *ppm; 1794 struct pmcstat_symbol *sym; 1795 struct pmcstat_cgnode *parent, *child; 1796 1797 /* 1798 * Find the callgraph node recorded in the global hash table 1799 * for this (pmcid, pc). 1800 */ 1801 1802 pc = cc[0]; 1803 parent = pmcstat_cgnode_hash_lookup_pc(pp, pmcid, pc, usermode); 1804 if (parent == NULL) { 1805 pmcstat_stats.ps_callchain_dubious_frames++; 1806 return; 1807 } 1808 1809 parent->pcg_count++; 1810 1811 /* 1812 * For each return address in the call chain record, subject 1813 * to the maximum depth desired. 1814 * - Find the image associated with the sample. Stop if there 1815 * there is no valid image at that address. 1816 * - Find the function that overlaps the return address. 1817 * - If found: use the start address of the function. 1818 * If not found (say an object's symbol table is not present or 1819 * is incomplete), round down to th gprof bucket granularity. 1820 * - Convert return virtual address to an offset in the image. 1821 * - Look for a child with the same {offset,image} tuple, 1822 * inserting one if needed. 1823 * - Increment the count of occurrences of the child. 1824 */ 1825 1826 for (n = 1; n < (uint32_t) a->pa_graphdepth && n < nsamples; n++, 1827 parent = child) { 1828 pc = cc[n]; 1829 1830 ppm = pmcstat_process_find_map(usermode ? pp : 1831 pmcstat_kernproc, pc); 1832 if (ppm == NULL) 1833 return; 1834 1835 image = ppm->ppm_image; 1836 loadaddress = ppm->ppm_lowpc + image->pi_vaddr - 1837 image->pi_start; 1838 pc -= loadaddress; 1839 1840 if ((sym = pmcstat_symbol_search(image, pc)) != NULL) 1841 pc = sym->ps_start; 1842 1843 child = pmcstat_cgnode_find(parent, image, pc); 1844 child->pcg_count++; 1845 } 1846} 1847 1848/* 1849 * Printing a callgraph for a PMC. 1850 */ 1851static void 1852pmcstat_callgraph_print_for_pmcid(struct pmcstat_args *a, 1853 struct pmcstat_pmcrecord *pmcr) 1854{ 1855 int n, nentries; 1856 uint32_t nsamples, pmcid; 1857 struct pmcstat_cgnode **sortbuffer, **cgn; 1858 struct pmcstat_cgnode_hash *pch; 1859 1860 /* 1861 * We pull out all callgraph nodes in the top-level hash table 1862 * with a matching PMC id. We then sort these based on the 1863 * frequency of occurrence. Each callgraph node is then 1864 * printed. 1865 */ 1866 1867 nsamples = 0; 1868 pmcid = pmcr->pr_pmcid; 1869 if ((sortbuffer = (struct pmcstat_cgnode **) 1870 malloc(sizeof(struct pmcstat_cgnode *) * 1871 pmcstat_cgnode_hash_count)) == NULL) 1872 err(EX_OSERR, "ERROR: Cannot sort callgraph"); 1873 cgn = sortbuffer; 1874 1875 memset(sortbuffer, 0xFF, pmcstat_cgnode_hash_count * 1876 sizeof(struct pmcstat_cgnode **)); 1877 1878 for (n = 0; n < PMCSTAT_NHASH; n++) 1879 LIST_FOREACH(pch, &pmcstat_cgnode_hash[n], pch_next) 1880 if (pch->pch_pmcid == pmcid) { 1881 nsamples += pch->pch_cgnode->pcg_count; 1882 *cgn++ = pch->pch_cgnode; 1883 } 1884 1885 nentries = cgn - sortbuffer; 1886 assert(nentries <= pmcstat_cgnode_hash_count); 1887 1888 if (nentries == 0) 1889 return; 1890 1891 qsort(sortbuffer, nentries, sizeof(struct pmcstat_cgnode *), 1892 pmcstat_cgnode_compare); 1893 1894 (void) fprintf(a->pa_graphfile, 1895 "@ %s [%u samples]\n\n", 1896 pmcstat_string_unintern(pmcr->pr_pmcname), 1897 nsamples); 1898 1899 for (cgn = sortbuffer, n = 0; n < nentries; n++, cgn++) { 1900 pmcstat_previous_filename_printed = NULL; 1901 pmcstat_cgnode_print(a, *cgn, 0, nsamples); 1902 (void) fprintf(a->pa_graphfile, "\n"); 1903 } 1904 1905 free(sortbuffer); 1906} 1907 1908/* 1909 * Print out callgraphs. 1910 */ 1911 1912static void 1913pmcstat_callgraph_print(struct pmcstat_args *a) 1914{ 1915 struct pmcstat_pmcrecord *pmcr; 1916 1917 LIST_FOREACH(pmcr, &pmcstat_pmcs, pr_next) 1918 pmcstat_callgraph_print_for_pmcid(a, pmcr); 1919} 1920 1921static void 1922pmcstat_cgnode_do_gmon_arcs(struct pmcstat_cgnode *cg, pmc_id_t pmcid) 1923{ 1924 struct pmcstat_cgnode *cgc; 1925 1926 /* 1927 * Look for child nodes that belong to the same image. 1928 */ 1929 1930 LIST_FOREACH(cgc, &cg->pcg_children, pcg_sibling) { 1931 if (cgc->pcg_image == cg->pcg_image) 1932 pmcstat_gmon_append_arc(cg->pcg_image, pmcid, 1933 cgc->pcg_func, cg->pcg_func, cgc->pcg_count); 1934 if (cgc->pcg_nchildren > 0) 1935 pmcstat_cgnode_do_gmon_arcs(cgc, pmcid); 1936 } 1937} 1938 1939static void 1940pmcstat_callgraph_do_gmon_arcs_for_pmcid(pmc_id_t pmcid) 1941{ 1942 int n; 1943 struct pmcstat_cgnode_hash *pch; 1944 1945 for (n = 0; n < PMCSTAT_NHASH; n++) 1946 LIST_FOREACH(pch, &pmcstat_cgnode_hash[n], pch_next) 1947 if (pch->pch_pmcid == pmcid && 1948 pch->pch_cgnode->pcg_nchildren > 1) 1949 pmcstat_cgnode_do_gmon_arcs(pch->pch_cgnode, 1950 pmcid); 1951} 1952 1953 1954static void 1955pmcstat_callgraph_do_gmon_arcs(void) 1956{ 1957 struct pmcstat_pmcrecord *pmcr; 1958 1959 LIST_FOREACH(pmcr, &pmcstat_pmcs, pr_next) 1960 pmcstat_callgraph_do_gmon_arcs_for_pmcid(pmcr->pr_pmcid); 1961} 1962 1963/* | |
1964 * Convert a hwpmc(4) log to profile information. A system-wide 1965 * callgraph is generated if FLAG_DO_CALLGRAPHS is set. gmon.out 1966 * files usable by gprof(1) are created if FLAG_DO_GPROF is set. 1967 */ 1968static int | 1289 * Convert a hwpmc(4) log to profile information. A system-wide 1290 * callgraph is generated if FLAG_DO_CALLGRAPHS is set. gmon.out 1291 * files usable by gprof(1) are created if FLAG_DO_GPROF is set. 1292 */ 1293static int |
1969pmcstat_analyze_log(struct pmcstat_args *a) | 1294pmcstat_analyze_log(void) |
1970{ 1971 uint32_t cpu, cpuflags; | 1295{ 1296 uint32_t cpu, cpuflags; |
1972 uintfptr_t pc, newpc; | 1297 uintfptr_t pc; |
1973 pid_t pid; 1974 struct pmcstat_image *image; | 1298 pid_t pid; 1299 struct pmcstat_image *image; |
1975 struct pmcstat_symbol *sym; | |
1976 struct pmcstat_process *pp, *ppnew; 1977 struct pmcstat_pcmap *ppm, *ppmtmp; 1978 struct pmclog_ev ev; | 1300 struct pmcstat_process *pp, *ppnew; 1301 struct pmcstat_pcmap *ppm, *ppmtmp; 1302 struct pmclog_ev ev; |
1303 struct pmcstat_pmcrecord *pmcr; |
|
1979 pmcstat_interned_string image_path; 1980 | 1304 pmcstat_interned_string image_path; 1305 |
1981 assert(a->pa_flags & FLAG_DO_ANALYSIS); | 1306 assert(args.pa_flags & FLAG_DO_ANALYSIS); |
1982 1983 if (elf_version(EV_CURRENT) == EV_NONE) 1984 err(EX_UNAVAILABLE, "Elf library intialization failed"); 1985 | 1307 1308 if (elf_version(EV_CURRENT) == EV_NONE) 1309 err(EX_UNAVAILABLE, "Elf library intialization failed"); 1310 |
1986 while (pmclog_read(a->pa_logparser, &ev) == 0) { | 1311 while (pmclog_read(args.pa_logparser, &ev) == 0) { |
1987 assert(ev.pl_state == PMCLOG_OK); 1988 1989 switch (ev.pl_type) { 1990 case PMCLOG_TYPE_INITIALIZE: 1991 if ((ev.pl_u.pl_i.pl_version & 0xFF000000) != | 1312 assert(ev.pl_state == PMCLOG_OK); 1313 1314 switch (ev.pl_type) { 1315 case PMCLOG_TYPE_INITIALIZE: 1316 if ((ev.pl_u.pl_i.pl_version & 0xFF000000) != |
1992 PMC_VERSION_MAJOR << 24 && a->pa_verbosity > 0) | 1317 PMC_VERSION_MAJOR << 24 && args.pa_verbosity > 0) |
1993 warnx("WARNING: Log version 0x%x does not " 1994 "match compiled version 0x%x.", 1995 ev.pl_u.pl_i.pl_version, 1996 PMC_VERSION_MAJOR); 1997 break; 1998 1999 case PMCLOG_TYPE_MAP_IN: 2000 /* --- 13 unchanged lines hidden (view full) --- 2014 PMCSTAT_ALLOCATE); 2015 2016 assert(pp != NULL); 2017 2018 image_path = pmcstat_string_intern(ev.pl_u.pl_mi. 2019 pl_pathname); 2020 image = pmcstat_image_from_path(image_path, pid == -1); 2021 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) | 1318 warnx("WARNING: Log version 0x%x does not " 1319 "match compiled version 0x%x.", 1320 ev.pl_u.pl_i.pl_version, 1321 PMC_VERSION_MAJOR); 1322 break; 1323 1324 case PMCLOG_TYPE_MAP_IN: 1325 /* --- 13 unchanged lines hidden (view full) --- 1339 PMCSTAT_ALLOCATE); 1340 1341 assert(pp != NULL); 1342 1343 image_path = pmcstat_string_intern(ev.pl_u.pl_mi. 1344 pl_pathname); 1345 image = pmcstat_image_from_path(image_path, pid == -1); 1346 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) |
2022 pmcstat_image_determine_type(image, a); | 1347 pmcstat_image_determine_type(image); |
2023 if (image->pi_type != PMCSTAT_IMAGE_INDETERMINABLE) 2024 pmcstat_image_link(pp, image, 2025 ev.pl_u.pl_mi.pl_start); 2026 break; 2027 2028 case PMCLOG_TYPE_MAP_OUT: 2029 /* 2030 * Remove an address map. --- 23 unchanged lines hidden (view full) --- 2054 * pair and increment the appropriate entry 2055 * bin inside this. 2056 */ 2057 pmcstat_stats.ps_samples_total++; 2058 2059 pc = ev.pl_u.pl_s.pl_pc; 2060 pp = pmcstat_process_lookup(ev.pl_u.pl_s.pl_pid, 2061 PMCSTAT_ALLOCATE); | 1348 if (image->pi_type != PMCSTAT_IMAGE_INDETERMINABLE) 1349 pmcstat_image_link(pp, image, 1350 ev.pl_u.pl_mi.pl_start); 1351 break; 1352 1353 case PMCLOG_TYPE_MAP_OUT: 1354 /* 1355 * Remove an address map. --- 23 unchanged lines hidden (view full) --- 1379 * pair and increment the appropriate entry 1380 * bin inside this. 1381 */ 1382 pmcstat_stats.ps_samples_total++; 1383 1384 pc = ev.pl_u.pl_s.pl_pc; 1385 pp = pmcstat_process_lookup(ev.pl_u.pl_s.pl_pid, 1386 PMCSTAT_ALLOCATE); |
2062 if ((ppm = pmcstat_process_find_map(pp, pc)) == NULL && 2063 (ppm = pmcstat_process_find_map(pmcstat_kernproc, 2064 pc)) == NULL) { /* unknown process,offset pair */ 2065 pmcstat_stats.ps_samples_unknown_offset++; 2066 break; 2067 } | |
2068 | 1387 |
2069 pmcstat_image_increment_bucket(ppm, pc, 2070 ev.pl_u.pl_s.pl_pmcid, a); | 1388 /* Get PMC record. */ 1389 pmcr = pmcstat_lookup_pmcid(ev.pl_u.pl_s.pl_pmcid); 1390 assert(pmcr != NULL); |
2071 | 1391 |
1392 /* 1393 * Call the plugins processing 1394 * TODO: move pmcstat_process_find_map inside plugins 1395 */ 1396 1397 if (plugins[args.pa_pplugin].pl_process != NULL) 1398 plugins[args.pa_pplugin].pl_process( 1399 pp, pmcr, 1, &pc, 1400 pmcstat_process_find_map(pp, pc) != NULL, 0); 1401 plugins[args.pa_plugin].pl_process( 1402 pp, pmcr, 1, &pc, 1403 pmcstat_process_find_map(pp, pc) != NULL, 0); |
|
2072 break; 2073 2074 case PMCLOG_TYPE_CALLCHAIN: 2075 pmcstat_stats.ps_samples_total++; 2076 2077 cpuflags = ev.pl_u.pl_cc.pl_cpuflags; 2078 cpu = PMC_CALLCHAIN_CPUFLAGS_TO_CPU(cpuflags); 2079 2080 /* Filter on the CPU id. */ | 1404 break; 1405 1406 case PMCLOG_TYPE_CALLCHAIN: 1407 pmcstat_stats.ps_samples_total++; 1408 1409 cpuflags = ev.pl_u.pl_cc.pl_cpuflags; 1410 cpu = PMC_CALLCHAIN_CPUFLAGS_TO_CPU(cpuflags); 1411 1412 /* Filter on the CPU id. */ |
2081 if ((a->pa_cpumask & (1 << cpu)) == 0) { | 1413 if ((args.pa_cpumask & (1 << cpu)) == 0) { |
2082 pmcstat_stats.ps_samples_skipped++; 2083 break; 2084 } 2085 2086 pp = pmcstat_process_lookup(ev.pl_u.pl_cc.pl_pid, 2087 PMCSTAT_ALLOCATE); 2088 | 1414 pmcstat_stats.ps_samples_skipped++; 1415 break; 1416 } 1417 1418 pp = pmcstat_process_lookup(ev.pl_u.pl_cc.pl_pid, 1419 PMCSTAT_ALLOCATE); 1420 |
2089 if ((a->pa_flags & FLAG_WANTS_MAPPINGS) == 0) 2090 pmcstat_record_callchain(pp, 2091 ev.pl_u.pl_cc.pl_pmcid, 2092 ev.pl_u.pl_cc.pl_npc, ev.pl_u.pl_cc.pl_pc, 2093 PMC_CALLCHAIN_CPUFLAGS_TO_USERMODE(cpuflags), a); | 1421 /* Get PMC record. */ 1422 pmcr = pmcstat_lookup_pmcid(ev.pl_u.pl_cc.pl_pmcid); 1423 assert(pmcr != NULL); |
2094 | 1424 |
2095 if ((a->pa_flags & 2096 (FLAG_DO_GPROF | FLAG_WANTS_MAPPINGS)) == 0) 2097 break; | 1425 /* 1426 * Call the plugins processing 1427 */ |
2098 | 1428 |
2099 pc = ev.pl_u.pl_cc.pl_pc[0]; 2100 if (PMC_CALLCHAIN_CPUFLAGS_TO_USERMODE(cpuflags) == 0) 2101 pp = pmcstat_kernproc; 2102 ppm = pmcstat_process_find_map(pp, pc); 2103 if (ppm == NULL) { 2104 2105 /* Unknown offset. */ 2106 pmcstat_stats.ps_samples_unknown_offset++; 2107 break; 2108 } 2109 if (a->pa_flags & FLAG_WANTS_MAPPINGS) { 2110 image = ppm->ppm_image; 2111 newpc = pc - (ppm->ppm_lowpc + 2112 (image->pi_vaddr - image->pi_start)); 2113 sym = pmcstat_symbol_search(image, newpc); 2114 if (sym == NULL) 2115 break; 2116 fprintf(a->pa_graphfile, "%p %s 0x%jx 0x%jx\n", 2117 (void *)pc, 2118 pmcstat_string_unintern(sym->ps_name), 2119 (uintmax_t)(sym->ps_start + 2120 image->pi_vaddr), (uintmax_t)(sym->ps_end + 2121 image->pi_vaddr)); 2122 break; 2123 } 2124 2125 pmcstat_image_increment_bucket(ppm, pc, 2126 ev.pl_u.pl_cc.pl_pmcid, a); 2127 | 1429 if (plugins[args.pa_pplugin].pl_process != NULL) 1430 plugins[args.pa_pplugin].pl_process( 1431 pp, pmcr, 1432 ev.pl_u.pl_cc.pl_npc, 1433 ev.pl_u.pl_cc.pl_pc, 1434 PMC_CALLCHAIN_CPUFLAGS_TO_USERMODE(cpuflags), 1435 cpu); 1436 plugins[args.pa_plugin].pl_process( 1437 pp, pmcr, 1438 ev.pl_u.pl_cc.pl_npc, 1439 ev.pl_u.pl_cc.pl_pc, 1440 PMC_CALLCHAIN_CPUFLAGS_TO_USERMODE(cpuflags), 1441 cpu); |
2128 break; 2129 2130 case PMCLOG_TYPE_PMCALLOCATE: 2131 /* 2132 * Record the association pmc id between this 2133 * PMC and its name. 2134 */ 2135 pmcstat_pmcid_add(ev.pl_u.pl_a.pl_pmcid, | 1442 break; 1443 1444 case PMCLOG_TYPE_PMCALLOCATE: 1445 /* 1446 * Record the association pmc id between this 1447 * PMC and its name. 1448 */ 1449 pmcstat_pmcid_add(ev.pl_u.pl_a.pl_pmcid, |
2136 pmcstat_string_intern(ev.pl_u.pl_a.pl_evname), a); | 1450 pmcstat_string_intern(ev.pl_u.pl_a.pl_evname)); |
2137 break; 2138 2139 case PMCLOG_TYPE_PROCEXEC: 2140 2141 /* 2142 * Change the executable image associated with 2143 * a process. 2144 */ --- 6 unchanged lines hidden (view full) --- 2151 free(ppm); 2152 } 2153 2154 /* associate this process image */ 2155 image_path = pmcstat_string_intern( 2156 ev.pl_u.pl_x.pl_pathname); 2157 assert(image_path != NULL); 2158 pmcstat_process_exec(pp, image_path, | 1451 break; 1452 1453 case PMCLOG_TYPE_PROCEXEC: 1454 1455 /* 1456 * Change the executable image associated with 1457 * a process. 1458 */ --- 6 unchanged lines hidden (view full) --- 1465 free(ppm); 1466 } 1467 1468 /* associate this process image */ 1469 image_path = pmcstat_string_intern( 1470 ev.pl_u.pl_x.pl_pathname); 1471 assert(image_path != NULL); 1472 pmcstat_process_exec(pp, image_path, |
2159 ev.pl_u.pl_x.pl_entryaddr, a); | 1473 ev.pl_u.pl_x.pl_entryaddr); |
2160 break; 2161 2162 case PMCLOG_TYPE_PROCEXIT: 2163 2164 /* 2165 * Due to the way the log is generated, the 2166 * last few samples corresponding to a process 2167 * may appear in the log after the process --- 51 unchanged lines hidden (view full) --- 2219 "offset 0x%jx)", (uintmax_t) ev.pl_count + 1, ev.pl_offset); 2220} 2221 2222/* 2223 * Print log entries as text. 2224 */ 2225 2226static int | 1474 break; 1475 1476 case PMCLOG_TYPE_PROCEXIT: 1477 1478 /* 1479 * Due to the way the log is generated, the 1480 * last few samples corresponding to a process 1481 * may appear in the log after the process --- 51 unchanged lines hidden (view full) --- 1533 "offset 0x%jx)", (uintmax_t) ev.pl_count + 1, ev.pl_offset); 1534} 1535 1536/* 1537 * Print log entries as text. 1538 */ 1539 1540static int |
2227pmcstat_print_log(struct pmcstat_args *a) | 1541pmcstat_print_log(void) |
2228{ 2229 struct pmclog_ev ev; 2230 uint32_t npc; 2231 | 1542{ 1543 struct pmclog_ev ev; 1544 uint32_t npc; 1545 |
2232 while (pmclog_read(a->pa_logparser, &ev) == 0) { | 1546 while (pmclog_read(args.pa_logparser, &ev) == 0) { |
2233 assert(ev.pl_state == PMCLOG_OK); 2234 switch (ev.pl_type) { 2235 case PMCLOG_TYPE_CALLCHAIN: | 1547 assert(ev.pl_state == PMCLOG_OK); 1548 switch (ev.pl_type) { 1549 case PMCLOG_TYPE_CALLCHAIN: |
2236 PMCSTAT_PRINT_ENTRY(a, "callchain", | 1550 PMCSTAT_PRINT_ENTRY("callchain", |
2237 "%d 0x%x %d %d %c", ev.pl_u.pl_cc.pl_pid, 2238 ev.pl_u.pl_cc.pl_pmcid, 2239 PMC_CALLCHAIN_CPUFLAGS_TO_CPU(ev.pl_u.pl_cc. \ 2240 pl_cpuflags), ev.pl_u.pl_cc.pl_npc, 2241 PMC_CALLCHAIN_CPUFLAGS_TO_USERMODE(ev.pl_u.pl_cc.\ 2242 pl_cpuflags) ? 'u' : 's'); 2243 for (npc = 0; npc < ev.pl_u.pl_cc.pl_npc; npc++) | 1551 "%d 0x%x %d %d %c", ev.pl_u.pl_cc.pl_pid, 1552 ev.pl_u.pl_cc.pl_pmcid, 1553 PMC_CALLCHAIN_CPUFLAGS_TO_CPU(ev.pl_u.pl_cc. \ 1554 pl_cpuflags), ev.pl_u.pl_cc.pl_npc, 1555 PMC_CALLCHAIN_CPUFLAGS_TO_USERMODE(ev.pl_u.pl_cc.\ 1556 pl_cpuflags) ? 'u' : 's'); 1557 for (npc = 0; npc < ev.pl_u.pl_cc.pl_npc; npc++) |
2244 PMCSTAT_PRINT_ENTRY(a, "...", "%p", | 1558 PMCSTAT_PRINT_ENTRY("...", "%p", |
2245 (void *) ev.pl_u.pl_cc.pl_pc[npc]); 2246 break; 2247 case PMCLOG_TYPE_CLOSELOG: | 1559 (void *) ev.pl_u.pl_cc.pl_pc[npc]); 1560 break; 1561 case PMCLOG_TYPE_CLOSELOG: |
2248 PMCSTAT_PRINT_ENTRY(a,"closelog",); | 1562 PMCSTAT_PRINT_ENTRY("closelog",); |
2249 break; 2250 case PMCLOG_TYPE_DROPNOTIFY: | 1563 break; 1564 case PMCLOG_TYPE_DROPNOTIFY: |
2251 PMCSTAT_PRINT_ENTRY(a,"drop",); | 1565 PMCSTAT_PRINT_ENTRY("drop",); |
2252 break; 2253 case PMCLOG_TYPE_INITIALIZE: | 1566 break; 1567 case PMCLOG_TYPE_INITIALIZE: |
2254 PMCSTAT_PRINT_ENTRY(a,"initlog","0x%x \"%s\"", | 1568 PMCSTAT_PRINT_ENTRY("initlog","0x%x \"%s\"", |
2255 ev.pl_u.pl_i.pl_version, 2256 pmc_name_of_cputype(ev.pl_u.pl_i.pl_arch)); 2257 if ((ev.pl_u.pl_i.pl_version & 0xFF000000) != | 1569 ev.pl_u.pl_i.pl_version, 1570 pmc_name_of_cputype(ev.pl_u.pl_i.pl_arch)); 1571 if ((ev.pl_u.pl_i.pl_version & 0xFF000000) != |
2258 PMC_VERSION_MAJOR << 24 && a->pa_verbosity > 0) | 1572 PMC_VERSION_MAJOR << 24 && args.pa_verbosity > 0) |
2259 warnx("WARNING: Log version 0x%x != expected " 2260 "version 0x%x.", ev.pl_u.pl_i.pl_version, 2261 PMC_VERSION); 2262 break; 2263 case PMCLOG_TYPE_MAP_IN: | 1573 warnx("WARNING: Log version 0x%x != expected " 1574 "version 0x%x.", ev.pl_u.pl_i.pl_version, 1575 PMC_VERSION); 1576 break; 1577 case PMCLOG_TYPE_MAP_IN: |
2264 PMCSTAT_PRINT_ENTRY(a,"map-in","%d %p \"%s\"", | 1578 PMCSTAT_PRINT_ENTRY("map-in","%d %p \"%s\"", |
2265 ev.pl_u.pl_mi.pl_pid, 2266 (void *) ev.pl_u.pl_mi.pl_start, 2267 ev.pl_u.pl_mi.pl_pathname); 2268 break; 2269 case PMCLOG_TYPE_MAP_OUT: | 1579 ev.pl_u.pl_mi.pl_pid, 1580 (void *) ev.pl_u.pl_mi.pl_start, 1581 ev.pl_u.pl_mi.pl_pathname); 1582 break; 1583 case PMCLOG_TYPE_MAP_OUT: |
2270 PMCSTAT_PRINT_ENTRY(a,"map-out","%d %p %p", | 1584 PMCSTAT_PRINT_ENTRY("map-out","%d %p %p", |
2271 ev.pl_u.pl_mo.pl_pid, 2272 (void *) ev.pl_u.pl_mo.pl_start, 2273 (void *) ev.pl_u.pl_mo.pl_end); 2274 break; 2275 case PMCLOG_TYPE_PCSAMPLE: | 1585 ev.pl_u.pl_mo.pl_pid, 1586 (void *) ev.pl_u.pl_mo.pl_start, 1587 (void *) ev.pl_u.pl_mo.pl_end); 1588 break; 1589 case PMCLOG_TYPE_PCSAMPLE: |
2276 PMCSTAT_PRINT_ENTRY(a,"sample","0x%x %d %p %c", | 1590 PMCSTAT_PRINT_ENTRY("sample","0x%x %d %p %c", |
2277 ev.pl_u.pl_s.pl_pmcid, 2278 ev.pl_u.pl_s.pl_pid, 2279 (void *) ev.pl_u.pl_s.pl_pc, 2280 ev.pl_u.pl_s.pl_usermode ? 'u' : 's'); 2281 break; 2282 case PMCLOG_TYPE_PMCALLOCATE: | 1591 ev.pl_u.pl_s.pl_pmcid, 1592 ev.pl_u.pl_s.pl_pid, 1593 (void *) ev.pl_u.pl_s.pl_pc, 1594 ev.pl_u.pl_s.pl_usermode ? 'u' : 's'); 1595 break; 1596 case PMCLOG_TYPE_PMCALLOCATE: |
2283 PMCSTAT_PRINT_ENTRY(a,"allocate","0x%x \"%s\" 0x%x", | 1597 PMCSTAT_PRINT_ENTRY("allocate","0x%x \"%s\" 0x%x", |
2284 ev.pl_u.pl_a.pl_pmcid, 2285 ev.pl_u.pl_a.pl_evname, 2286 ev.pl_u.pl_a.pl_flags); 2287 break; 2288 case PMCLOG_TYPE_PMCATTACH: | 1598 ev.pl_u.pl_a.pl_pmcid, 1599 ev.pl_u.pl_a.pl_evname, 1600 ev.pl_u.pl_a.pl_flags); 1601 break; 1602 case PMCLOG_TYPE_PMCATTACH: |
2289 PMCSTAT_PRINT_ENTRY(a,"attach","0x%x %d \"%s\"", | 1603 PMCSTAT_PRINT_ENTRY("attach","0x%x %d \"%s\"", |
2290 ev.pl_u.pl_t.pl_pmcid, 2291 ev.pl_u.pl_t.pl_pid, 2292 ev.pl_u.pl_t.pl_pathname); 2293 break; 2294 case PMCLOG_TYPE_PMCDETACH: | 1604 ev.pl_u.pl_t.pl_pmcid, 1605 ev.pl_u.pl_t.pl_pid, 1606 ev.pl_u.pl_t.pl_pathname); 1607 break; 1608 case PMCLOG_TYPE_PMCDETACH: |
2295 PMCSTAT_PRINT_ENTRY(a,"detach","0x%x %d", | 1609 PMCSTAT_PRINT_ENTRY("detach","0x%x %d", |
2296 ev.pl_u.pl_d.pl_pmcid, 2297 ev.pl_u.pl_d.pl_pid); 2298 break; 2299 case PMCLOG_TYPE_PROCCSW: | 1610 ev.pl_u.pl_d.pl_pmcid, 1611 ev.pl_u.pl_d.pl_pid); 1612 break; 1613 case PMCLOG_TYPE_PROCCSW: |
2300 PMCSTAT_PRINT_ENTRY(a,"cswval","0x%x %d %jd", | 1614 PMCSTAT_PRINT_ENTRY("cswval","0x%x %d %jd", |
2301 ev.pl_u.pl_c.pl_pmcid, 2302 ev.pl_u.pl_c.pl_pid, 2303 ev.pl_u.pl_c.pl_value); 2304 break; 2305 case PMCLOG_TYPE_PROCEXEC: | 1615 ev.pl_u.pl_c.pl_pmcid, 1616 ev.pl_u.pl_c.pl_pid, 1617 ev.pl_u.pl_c.pl_value); 1618 break; 1619 case PMCLOG_TYPE_PROCEXEC: |
2306 PMCSTAT_PRINT_ENTRY(a,"exec","0x%x %d %p \"%s\"", | 1620 PMCSTAT_PRINT_ENTRY("exec","0x%x %d %p \"%s\"", |
2307 ev.pl_u.pl_x.pl_pmcid, 2308 ev.pl_u.pl_x.pl_pid, 2309 (void *) ev.pl_u.pl_x.pl_entryaddr, 2310 ev.pl_u.pl_x.pl_pathname); 2311 break; 2312 case PMCLOG_TYPE_PROCEXIT: | 1621 ev.pl_u.pl_x.pl_pmcid, 1622 ev.pl_u.pl_x.pl_pid, 1623 (void *) ev.pl_u.pl_x.pl_entryaddr, 1624 ev.pl_u.pl_x.pl_pathname); 1625 break; 1626 case PMCLOG_TYPE_PROCEXIT: |
2313 PMCSTAT_PRINT_ENTRY(a,"exitval","0x%x %d %jd", | 1627 PMCSTAT_PRINT_ENTRY("exitval","0x%x %d %jd", |
2314 ev.pl_u.pl_e.pl_pmcid, 2315 ev.pl_u.pl_e.pl_pid, 2316 ev.pl_u.pl_e.pl_value); 2317 break; 2318 case PMCLOG_TYPE_PROCFORK: | 1628 ev.pl_u.pl_e.pl_pmcid, 1629 ev.pl_u.pl_e.pl_pid, 1630 ev.pl_u.pl_e.pl_value); 1631 break; 1632 case PMCLOG_TYPE_PROCFORK: |
2319 PMCSTAT_PRINT_ENTRY(a,"fork","%d %d", | 1633 PMCSTAT_PRINT_ENTRY("fork","%d %d", |
2320 ev.pl_u.pl_f.pl_oldpid, 2321 ev.pl_u.pl_f.pl_newpid); 2322 break; 2323 case PMCLOG_TYPE_USERDATA: | 1634 ev.pl_u.pl_f.pl_oldpid, 1635 ev.pl_u.pl_f.pl_newpid); 1636 break; 1637 case PMCLOG_TYPE_USERDATA: |
2324 PMCSTAT_PRINT_ENTRY(a,"userdata","0x%x", | 1638 PMCSTAT_PRINT_ENTRY("userdata","0x%x", |
2325 ev.pl_u.pl_u.pl_userdata); 2326 break; 2327 case PMCLOG_TYPE_SYSEXIT: | 1639 ev.pl_u.pl_u.pl_userdata); 1640 break; 1641 case PMCLOG_TYPE_SYSEXIT: |
2328 PMCSTAT_PRINT_ENTRY(a,"exit","%d", | 1642 PMCSTAT_PRINT_ENTRY("exit","%d", |
2329 ev.pl_u.pl_se.pl_pid); 2330 break; 2331 default: | 1643 ev.pl_u.pl_se.pl_pid); 1644 break; 1645 default: |
2332 fprintf(a->pa_printfile, "unknown event (type %d).\n", | 1646 fprintf(args.pa_printfile, "unknown event (type %d).\n", |
2333 ev.pl_type); 2334 } 2335 } 2336 2337 if (ev.pl_state == PMCLOG_EOF) 2338 return (PMCSTAT_FINISHED); 2339 else if (ev.pl_state == PMCLOG_REQUIRE_DATA) 2340 return (PMCSTAT_RUNNING); --- 8 unchanged lines hidden (view full) --- 2349 * Public Interfaces. 2350 */ 2351 2352/* 2353 * Close a logfile, after first flushing all in-module queued data. 2354 */ 2355 2356int | 1647 ev.pl_type); 1648 } 1649 } 1650 1651 if (ev.pl_state == PMCLOG_EOF) 1652 return (PMCSTAT_FINISHED); 1653 else if (ev.pl_state == PMCLOG_REQUIRE_DATA) 1654 return (PMCSTAT_RUNNING); --- 8 unchanged lines hidden (view full) --- 1663 * Public Interfaces. 1664 */ 1665 1666/* 1667 * Close a logfile, after first flushing all in-module queued data. 1668 */ 1669 1670int |
2357pmcstat_close_log(struct pmcstat_args *a) | 1671pmcstat_close_log(void) |
2358{ 2359 if (pmc_flush_logfile() < 0 || 2360 pmc_configure_logfile(-1) < 0) 2361 err(EX_OSERR, "ERROR: logging failed"); | 1672{ 1673 if (pmc_flush_logfile() < 0 || 1674 pmc_configure_logfile(-1) < 0) 1675 err(EX_OSERR, "ERROR: logging failed"); |
2362 a->pa_flags &= ~(FLAG_HAS_OUTPUT_LOGFILE | FLAG_HAS_PIPE); 2363 return (a->pa_flags & FLAG_HAS_PIPE ? PMCSTAT_EXITING : | 1676 args.pa_flags &= ~(FLAG_HAS_OUTPUT_LOGFILE | FLAG_HAS_PIPE); 1677 return (args.pa_flags & FLAG_HAS_PIPE ? PMCSTAT_EXITING : |
2364 PMCSTAT_FINISHED); 2365} 2366 2367 2368 2369/* 2370 * Open a log file, for reading or writing. 2371 * --- 79 unchanged lines hidden (view full) --- 2451 return (fd); 2452} 2453 2454/* 2455 * Process a log file in offline analysis mode. 2456 */ 2457 2458int | 1678 PMCSTAT_FINISHED); 1679} 1680 1681 1682 1683/* 1684 * Open a log file, for reading or writing. 1685 * --- 79 unchanged lines hidden (view full) --- 1765 return (fd); 1766} 1767 1768/* 1769 * Process a log file in offline analysis mode. 1770 */ 1771 1772int |
2459pmcstat_process_log(struct pmcstat_args *a) | 1773pmcstat_process_log(void) |
2460{ 2461 2462 /* 2463 * If analysis has not been asked for, just print the log to 2464 * the current output file. 2465 */ | 1774{ 1775 1776 /* 1777 * If analysis has not been asked for, just print the log to 1778 * the current output file. 1779 */ |
2466 if (a->pa_flags & FLAG_DO_PRINT) 2467 return (pmcstat_print_log(a)); | 1780 if (args.pa_flags & FLAG_DO_PRINT) 1781 return (pmcstat_print_log()); |
2468 else | 1782 else |
2469 return (pmcstat_analyze_log(a)); | 1783 return (pmcstat_analyze_log()); |
2470} 2471 2472/* | 1784} 1785 1786/* |
1787 * Refresh top display. 1788 */ 1789 1790static void 1791pmcstat_refresh_top(void) 1792{ 1793 char pmcname[40]; 1794 1795 /* If in pause mode do not refresh display. */ 1796 if (pmcstat_pause) 1797 return; 1798 1799 /* Format PMC name. */ 1800 if (pmcstat_mergepmc) 1801 snprintf(pmcname, sizeof(pmcname), "[%s]", 1802 pmcstat_pmcindex_to_name(pmcstat_pmcinfilter)); 1803 else 1804 snprintf(pmcname, sizeof(pmcname), "%s.%d", 1805 pmcstat_pmcindex_to_name(pmcstat_pmcinfilter), 1806 pmcstat_pmcinfilter); 1807 1808 PMCSTAT_PRINTBEGIN(); 1809 PMCSTAT_PRINTW("PMC: %s Samples: %u processed, %u invalid\n\n", 1810 pmcname, 1811 pmcstat_stats.ps_samples_total, 1812 pmcstat_stats.ps_samples_unknown_offset + 1813 pmcstat_stats.ps_samples_indeterminable + 1814 pmcstat_stats.ps_callchain_dubious_frames); 1815 if (plugins[args.pa_plugin].pl_topdisplay != NULL) 1816 plugins[args.pa_plugin].pl_topdisplay(); 1817 PMCSTAT_PRINTEND(); 1818} 1819 1820/* 1821 * Find the next pmc index to display. 1822 */ 1823 1824static void 1825pmcstat_changefilter(void) 1826{ 1827 int pmcin; 1828 struct pmcstat_pmcrecord *pmcr; 1829 1830 /* 1831 * Find the next merge target. 1832 */ 1833 if (pmcstat_mergepmc) { 1834 pmcin = pmcstat_pmcinfilter; 1835 1836 do { 1837 pmcr = pmcstat_pmcindex_to_pmcr(pmcstat_pmcinfilter); 1838 if (pmcr == pmcr->pr_merge) 1839 break; 1840 1841 pmcstat_pmcinfilter++; 1842 if (pmcstat_pmcinfilter >= pmcstat_npmcs) 1843 pmcstat_pmcinfilter = 0; 1844 1845 } while (pmcstat_pmcinfilter != pmcin); 1846 } 1847} 1848 1849/* 1850 * Top mode keypress. 1851 */ 1852 1853int 1854pmcstat_keypress_log(void) 1855{ 1856 int c, ret = 0; 1857 WINDOW *w; 1858 1859 w = newwin(1, 0, 1, 0); 1860 c = wgetch(w); 1861 wprintw(w, "Key: %c => ", c); 1862 switch (c) { 1863 case 'c': 1864 wprintw(w, "enter mode 'd' or 'a' => "); 1865 c = wgetch(w); 1866 if (c == 'd') { 1867 args.pa_topmode = PMCSTAT_TOP_DELTA; 1868 wprintw(w, "switching to delta mode"); 1869 } else { 1870 args.pa_topmode = PMCSTAT_TOP_ACCUM; 1871 wprintw(w, "switching to accumulation mode"); 1872 } 1873 break; 1874 case 'm': 1875 pmcstat_mergepmc = !pmcstat_mergepmc; 1876 /* 1877 * Changing merge state require data reset. 1878 */ 1879 if (plugins[args.pa_plugin].pl_shutdown != NULL) 1880 plugins[args.pa_plugin].pl_shutdown(NULL); 1881 bzero(&pmcstat_stats, sizeof(struct pmcstat_stats)); 1882 if (plugins[args.pa_plugin].pl_init != NULL) 1883 plugins[args.pa_plugin].pl_init(); 1884 1885 /* Update filter to be on a merge target. */ 1886 pmcstat_changefilter(); 1887 wprintw(w, "merge PMC %s", pmcstat_mergepmc ? "on" : "off"); 1888 break; 1889 case 'n': 1890 /* Close current plugin. */ 1891 if (plugins[args.pa_plugin].pl_shutdown != NULL) 1892 plugins[args.pa_plugin].pl_shutdown(NULL); 1893 1894 /* Find next top display available. */ 1895 do { 1896 args.pa_plugin++; 1897 if (plugins[args.pa_plugin].pl_name == NULL) 1898 args.pa_plugin = 0; 1899 } while (plugins[args.pa_plugin].pl_topdisplay == NULL); 1900 1901 /* Open new plugin. */ 1902 bzero(&pmcstat_stats, sizeof(struct pmcstat_stats)); 1903 if (plugins[args.pa_plugin].pl_init != NULL) 1904 plugins[args.pa_plugin].pl_init(); 1905 wprintw(w, "switching to plugin %s", 1906 plugins[args.pa_plugin].pl_name); 1907 break; 1908 case 'p': 1909 pmcstat_pmcinfilter++; 1910 if (pmcstat_pmcinfilter >= pmcstat_npmcs) 1911 pmcstat_pmcinfilter = 0; 1912 pmcstat_changefilter(); 1913 wprintw(w, "switching to PMC %s.%d", 1914 pmcstat_pmcindex_to_name(pmcstat_pmcinfilter), 1915 pmcstat_pmcinfilter); 1916 break; 1917 case ' ': 1918 pmcstat_pause = !pmcstat_pause; 1919 if (pmcstat_pause) 1920 wprintw(w, "pause => press space again to continue"); 1921 break; 1922 case 'q': 1923 wprintw(w, "exiting..."); 1924 ret = 1; 1925 default: 1926 if (plugins[args.pa_plugin].pl_topkeypress != NULL) 1927 if (plugins[args.pa_plugin].pl_topkeypress(c, w)) 1928 ret = 1; 1929 } 1930 1931 wrefresh(w); 1932 delwin(w); 1933 return ret; 1934} 1935 1936 1937/* 1938 * Top mode display. 1939 */ 1940 1941void 1942pmcstat_display_log(void) 1943{ 1944 1945 pmcstat_refresh_top(); 1946 1947 /* Reset everythings if delta mode. */ 1948 if (args.pa_topmode == PMCSTAT_TOP_DELTA) { 1949 if (plugins[args.pa_plugin].pl_shutdown != NULL) 1950 plugins[args.pa_plugin].pl_shutdown(NULL); 1951 bzero(&pmcstat_stats, sizeof(struct pmcstat_stats)); 1952 if (plugins[args.pa_plugin].pl_init != NULL) 1953 plugins[args.pa_plugin].pl_init(); 1954 } 1955 1956} 1957 1958/* 1959 * Configure a plugins. 1960 */ 1961 1962void 1963pmcstat_pluginconfigure_log(char *opt) 1964{ 1965 1966 if (strncmp(opt, "threshold=", 10) == 0) { 1967 pmcstat_threshold = atof(opt+10); 1968 } else { 1969 if (plugins[args.pa_plugin].pl_configure != NULL) { 1970 if (!plugins[args.pa_plugin].pl_configure(opt)) 1971 err(EX_USAGE, 1972 "ERROR: unknown option <%s>.", opt); 1973 } 1974 } 1975} 1976 1977/* |
|
2473 * Initialize module. 2474 */ 2475 2476void | 1978 * Initialize module. 1979 */ 1980 1981void |
2477pmcstat_initialize_logging(struct pmcstat_args *a) | 1982pmcstat_initialize_logging(void) |
2478{ 2479 int i; 2480 | 1983{ 1984 int i; 1985 |
2481 (void) a; 2482 | |
2483 /* use a convenient format for 'ldd' output */ 2484 if (setenv("LD_TRACE_LOADED_OBJECTS_FMT1","%o \"%p\" %x\n",1) != 0) 2485 err(EX_OSERR, "ERROR: Cannot setenv"); 2486 2487 /* Initialize hash tables */ 2488 pmcstat_string_initialize(); 2489 for (i = 0; i < PMCSTAT_NHASH; i++) { 2490 LIST_INIT(&pmcstat_image_hash[i]); 2491 LIST_INIT(&pmcstat_process_hash[i]); 2492 } 2493 2494 /* 2495 * Create a fake 'process' entry for the kernel with pid -1. 2496 * hwpmc(4) will subsequently inform us about where the kernel 2497 * and any loaded kernel modules are mapped. 2498 */ 2499 if ((pmcstat_kernproc = pmcstat_process_lookup((pid_t) -1, 2500 PMCSTAT_ALLOCATE)) == NULL) 2501 err(EX_OSERR, "ERROR: Cannot initialize logging"); | 1986 /* use a convenient format for 'ldd' output */ 1987 if (setenv("LD_TRACE_LOADED_OBJECTS_FMT1","%o \"%p\" %x\n",1) != 0) 1988 err(EX_OSERR, "ERROR: Cannot setenv"); 1989 1990 /* Initialize hash tables */ 1991 pmcstat_string_initialize(); 1992 for (i = 0; i < PMCSTAT_NHASH; i++) { 1993 LIST_INIT(&pmcstat_image_hash[i]); 1994 LIST_INIT(&pmcstat_process_hash[i]); 1995 } 1996 1997 /* 1998 * Create a fake 'process' entry for the kernel with pid -1. 1999 * hwpmc(4) will subsequently inform us about where the kernel 2000 * and any loaded kernel modules are mapped. 2001 */ 2002 if ((pmcstat_kernproc = pmcstat_process_lookup((pid_t) -1, 2003 PMCSTAT_ALLOCATE)) == NULL) 2004 err(EX_OSERR, "ERROR: Cannot initialize logging"); |
2005 2006 /* PMC count. */ 2007 pmcstat_npmcs = 0; 2008 2009 /* Merge PMC with same name. */ 2010 pmcstat_mergepmc = args.pa_mergepmc; 2011 2012 /* 2013 * Initialize plugins 2014 */ 2015 2016 if (plugins[args.pa_pplugin].pl_init != NULL) 2017 plugins[args.pa_pplugin].pl_init(); 2018 if (plugins[args.pa_plugin].pl_init != NULL) 2019 plugins[args.pa_plugin].pl_init(); |
|
2502} 2503 2504/* 2505 * Shutdown module. 2506 */ 2507 2508void | 2020} 2021 2022/* 2023 * Shutdown module. 2024 */ 2025 2026void |
2509pmcstat_shutdown_logging(struct pmcstat_args *a) | 2027pmcstat_shutdown_logging(void) |
2510{ 2511 int i; 2512 FILE *mf; | 2028{ 2029 int i; 2030 FILE *mf; |
2513 struct pmcstat_gmonfile *pgf, *pgftmp; | |
2514 struct pmcstat_image *pi, *pitmp; 2515 struct pmcstat_process *pp, *pptmp; | 2031 struct pmcstat_image *pi, *pitmp; 2032 struct pmcstat_process *pp, *pptmp; |
2516 struct pmcstat_cgnode_hash *pch, *pchtmp; | 2033 struct pmcstat_pcmap *ppm, *ppmtmp; |
2517 2518 /* determine where to send the map file */ 2519 mf = NULL; | 2034 2035 /* determine where to send the map file */ 2036 mf = NULL; |
2520 if (a->pa_mapfilename != NULL) 2521 mf = (strcmp(a->pa_mapfilename, "-") == 0) ? 2522 a->pa_printfile : fopen(a->pa_mapfilename, "w"); | 2037 if (args.pa_mapfilename != NULL) 2038 mf = (strcmp(args.pa_mapfilename, "-") == 0) ? 2039 args.pa_printfile : fopen(args.pa_mapfilename, "w"); |
2523 | 2040 |
2524 if (mf == NULL && a->pa_flags & FLAG_DO_GPROF && 2525 a->pa_verbosity >= 2) 2526 mf = a->pa_printfile; | 2041 if (mf == NULL && args.pa_flags & FLAG_DO_GPROF && 2042 args.pa_verbosity >= 2) 2043 mf = args.pa_printfile; |
2527 2528 if (mf) 2529 (void) fprintf(mf, "MAP:\n"); 2530 | 2044 2045 if (mf) 2046 (void) fprintf(mf, "MAP:\n"); 2047 |
2531 2532 if (a->pa_flags & FLAG_DO_CALLGRAPHS) 2533 pmcstat_callgraph_print(a); 2534 | |
2535 /* | 2048 /* |
2536 * Sync back all gprof flat profile data. | 2049 * Shutdown the plugins |
2537 */ | 2050 */ |
2538 for (i = 0; i < PMCSTAT_NHASH; i++) { 2539 LIST_FOREACH(pi, &pmcstat_image_hash[i], pi_next) { 2540 if (mf) 2541 (void) fprintf(mf, " \"%s\" => \"%s\"", 2542 pmcstat_string_unintern(pi->pi_execpath), 2543 pmcstat_string_unintern( 2544 pi->pi_samplename)); | |
2545 | 2051 |
2546 /* flush gmon.out data to disk */ 2547 LIST_FOREACH(pgf, &pi->pi_gmlist, pgf_next) { 2548 pmcstat_gmon_unmap_file(pgf); 2549 if (mf) 2550 (void) fprintf(mf, " %s/%d", 2551 pmcstat_pmcid_to_name( 2552 pgf->pgf_pmcid), 2553 pgf->pgf_nsamples); 2554 if (pgf->pgf_overflow && a->pa_verbosity >= 1) 2555 warnx("WARNING: profile \"%s\" " 2556 "overflowed.", 2557 pmcstat_string_unintern( 2558 pgf->pgf_name)); 2559 } | 2052 if (plugins[args.pa_plugin].pl_shutdown != NULL) 2053 plugins[args.pa_plugin].pl_shutdown(mf); 2054 if (plugins[args.pa_pplugin].pl_shutdown != NULL) 2055 plugins[args.pa_pplugin].pl_shutdown(mf); |
2560 | 2056 |
2561 if (mf) 2562 (void) fprintf(mf, "\n"); 2563 } 2564 } 2565 2566 /* 2567 * Compute arcs and add these to the gprof files. 2568 */ 2569 if (a->pa_flags & FLAG_DO_GPROF && a->pa_graphdepth > 1) 2570 pmcstat_callgraph_do_gmon_arcs(); 2571 2572 /* 2573 * Free memory. 2574 */ | |
2575 for (i = 0; i < PMCSTAT_NHASH; i++) { | 2057 for (i = 0; i < PMCSTAT_NHASH; i++) { |
2576 LIST_FOREACH_SAFE(pch, &pmcstat_cgnode_hash[i], pch_next, 2577 pchtmp) { 2578 pmcstat_cgnode_free(pch->pch_cgnode); 2579 free(pch); 2580 } 2581 } | 2058 LIST_FOREACH_SAFE(pi, &pmcstat_image_hash[i], pi_next, 2059 pitmp) { 2060 if (plugins[args.pa_plugin].pl_shutdownimage != NULL) 2061 plugins[args.pa_plugin].pl_shutdownimage(pi); 2062 if (plugins[args.pa_pplugin].pl_shutdownimage != NULL) 2063 plugins[args.pa_pplugin].pl_shutdownimage(pi); |
2582 | 2064 |
2583 for (i = 0; i < PMCSTAT_NHASH; i++) { 2584 LIST_FOREACH_SAFE(pi, &pmcstat_image_hash[i], pi_next, pitmp) 2585 { 2586 LIST_FOREACH_SAFE(pgf, &pi->pi_gmlist, pgf_next, 2587 pgftmp) { 2588 if (pgf->pgf_file) 2589 (void) fclose(pgf->pgf_file); 2590 LIST_REMOVE(pgf, pgf_next); 2591 free(pgf); 2592 } 2593 if (pi->pi_symbols) 2594 free(pi->pi_symbols); 2595 | 2065 free(pi->pi_symbols); 2066 if (pi->pi_addr2line != NULL) 2067 pclose(pi->pi_addr2line); |
2596 LIST_REMOVE(pi, pi_next); 2597 free(pi); 2598 } 2599 2600 LIST_FOREACH_SAFE(pp, &pmcstat_process_hash[i], pp_next, 2601 pptmp) { | 2068 LIST_REMOVE(pi, pi_next); 2069 free(pi); 2070 } 2071 2072 LIST_FOREACH_SAFE(pp, &pmcstat_process_hash[i], pp_next, 2073 pptmp) { |
2074 TAILQ_FOREACH_SAFE(ppm, &pp->pp_map, ppm_next, ppmtmp) { 2075 TAILQ_REMOVE(&pp->pp_map, ppm, ppm_next); 2076 free(ppm); 2077 } |
|
2602 LIST_REMOVE(pp, pp_next); 2603 free(pp); 2604 } 2605 } 2606 2607 pmcstat_string_shutdown(); 2608 2609 /* 2610 * Print errors unless -q was specified. Print all statistics 2611 * if verbosity > 1. 2612 */ | 2078 LIST_REMOVE(pp, pp_next); 2079 free(pp); 2080 } 2081 } 2082 2083 pmcstat_string_shutdown(); 2084 2085 /* 2086 * Print errors unless -q was specified. Print all statistics 2087 * if verbosity > 1. 2088 */ |
2613#define PRINT(N,V,A) do { \ 2614 if (pmcstat_stats.ps_##V || (A)->pa_verbosity >= 2) \ 2615 (void) fprintf((A)->pa_printfile, " %-40s %d\n",\ | 2089#define PRINT(N,V) do { \ 2090 if (pmcstat_stats.ps_##V || args.pa_verbosity >= 2) \ 2091 (void) fprintf(args.pa_printfile, " %-40s %d\n",\ |
2616 N, pmcstat_stats.ps_##V); \ 2617 } while (0) 2618 | 2092 N, pmcstat_stats.ps_##V); \ 2093 } while (0) 2094 |
2619 if (a->pa_verbosity >= 1 && a->pa_flags & FLAG_DO_GPROF) { 2620 (void) fprintf(a->pa_printfile, "CONVERSION STATISTICS:\n"); 2621 PRINT("#exec/a.out", exec_aout, a); 2622 PRINT("#exec/elf", exec_elf, a); 2623 PRINT("#exec/unknown", exec_indeterminable, a); 2624 PRINT("#exec handling errors", exec_errors, a); 2625 PRINT("#samples/total", samples_total, a); 2626 PRINT("#samples/unclaimed", samples_unknown_offset, a); 2627 PRINT("#samples/unknown-object", samples_indeterminable, a); 2628 PRINT("#callchain/dubious-frames", callchain_dubious_frames, 2629 a); | 2095 if (args.pa_verbosity >= 1 && (args.pa_flags & FLAG_DO_ANALYSIS) && 2096 (args.pa_flags & FLAG_DO_TOP) == 0) { 2097 (void) fprintf(args.pa_printfile, "CONVERSION STATISTICS:\n"); 2098 PRINT("#exec/a.out", exec_aout); 2099 PRINT("#exec/elf", exec_elf); 2100 PRINT("#exec/unknown", exec_indeterminable); 2101 PRINT("#exec handling errors", exec_errors); 2102 PRINT("#samples/total", samples_total); 2103 PRINT("#samples/unclaimed", samples_unknown_offset); 2104 PRINT("#samples/unknown-object", samples_indeterminable); 2105 PRINT("#callchain/dubious-frames", callchain_dubious_frames); |
2630 } 2631 2632 if (mf) 2633 (void) fclose(mf); 2634} | 2106 } 2107 2108 if (mf) 2109 (void) fclose(mf); 2110} |