Deleted Added
full compact
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}