115139246SJoseph Koshy /*- 2b6010f9eSJoseph Koshy * Copyright (c) 2005-2007, Joseph Koshy 3b6010f9eSJoseph Koshy * Copyright (c) 2007 The FreeBSD Foundation 415139246SJoseph Koshy * All rights reserved. 515139246SJoseph Koshy * 6b6010f9eSJoseph Koshy * Portions of this software were developed by A. Joseph Koshy under 7b6010f9eSJoseph Koshy * sponsorship from the FreeBSD Foundation and Google, Inc. 8b6010f9eSJoseph Koshy * 915139246SJoseph Koshy * Redistribution and use in source and binary forms, with or without 1015139246SJoseph Koshy * modification, are permitted provided that the following conditions 1115139246SJoseph Koshy * are met: 1215139246SJoseph Koshy * 1. Redistributions of source code must retain the above copyright 1315139246SJoseph Koshy * notice, this list of conditions and the following disclaimer. 1415139246SJoseph Koshy * 2. Redistributions in binary form must reproduce the above copyright 1515139246SJoseph Koshy * notice, this list of conditions and the following disclaimer in the 1615139246SJoseph Koshy * documentation and/or other materials provided with the distribution. 1715139246SJoseph Koshy * 1815139246SJoseph Koshy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1915139246SJoseph Koshy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2015139246SJoseph Koshy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2115139246SJoseph Koshy * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2215139246SJoseph Koshy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2315139246SJoseph Koshy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2415139246SJoseph Koshy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2515139246SJoseph Koshy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2615139246SJoseph Koshy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2715139246SJoseph Koshy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2815139246SJoseph Koshy * SUCH DAMAGE. 2915139246SJoseph Koshy */ 3015139246SJoseph Koshy 3149874f6eSJoseph Koshy /* 3249874f6eSJoseph Koshy * Transform a hwpmc(4) log into human readable form, and into 3349874f6eSJoseph Koshy * gprof(1) compatible profiles. 3449874f6eSJoseph Koshy */ 3549874f6eSJoseph Koshy 3615139246SJoseph Koshy #include <sys/cdefs.h> 3715139246SJoseph Koshy __FBSDID("$FreeBSD$"); 3815139246SJoseph Koshy 3915139246SJoseph Koshy #include <sys/param.h> 4015139246SJoseph Koshy #include <sys/endian.h> 41ea056888SAttilio Rao #include <sys/cpuset.h> 4215139246SJoseph Koshy #include <sys/gmon.h> 4315139246SJoseph Koshy #include <sys/imgact_aout.h> 4415139246SJoseph Koshy #include <sys/imgact_elf.h> 4515139246SJoseph Koshy #include <sys/mman.h> 4615139246SJoseph Koshy #include <sys/pmc.h> 4715139246SJoseph Koshy #include <sys/queue.h> 48302cbb90SJoseph Koshy #include <sys/socket.h> 4915139246SJoseph Koshy #include <sys/stat.h> 5015139246SJoseph Koshy #include <sys/wait.h> 5115139246SJoseph Koshy 5215139246SJoseph Koshy #include <netinet/in.h> 5315139246SJoseph Koshy 5415139246SJoseph Koshy #include <assert.h> 550b86b1bbSFabien Thomas #include <curses.h> 5615139246SJoseph Koshy #include <err.h> 57302cbb90SJoseph Koshy #include <errno.h> 5815139246SJoseph Koshy #include <fcntl.h> 59b6010f9eSJoseph Koshy #include <gelf.h> 6015139246SJoseph Koshy #include <libgen.h> 6115139246SJoseph Koshy #include <limits.h> 62302cbb90SJoseph Koshy #include <netdb.h> 6315139246SJoseph Koshy #include <pmc.h> 6415139246SJoseph Koshy #include <pmclog.h> 6515139246SJoseph Koshy #include <sysexits.h> 6615139246SJoseph Koshy #include <stdint.h> 6715139246SJoseph Koshy #include <stdio.h> 6815139246SJoseph Koshy #include <stdlib.h> 6915139246SJoseph Koshy #include <string.h> 7015139246SJoseph Koshy #include <unistd.h> 7115139246SJoseph Koshy 7215139246SJoseph Koshy #include "pmcstat.h" 730b86b1bbSFabien Thomas #include "pmcstat_log.h" 740b86b1bbSFabien Thomas #include "pmcstat_top.h" 7515139246SJoseph Koshy 7615139246SJoseph Koshy /* 7749874f6eSJoseph Koshy * PUBLIC INTERFACES 7849874f6eSJoseph Koshy * 7949874f6eSJoseph Koshy * pmcstat_initialize_logging() initialize this module, called first 8049874f6eSJoseph Koshy * pmcstat_shutdown_logging() orderly shutdown, called last 8149874f6eSJoseph Koshy * pmcstat_open_log() open an eventlog for processing 8249874f6eSJoseph Koshy * pmcstat_process_log() print/convert an event log 830b86b1bbSFabien Thomas * pmcstat_display_log() top mode display for the log 8449874f6eSJoseph Koshy * pmcstat_close_log() finish processing an event log 8549874f6eSJoseph Koshy * 86b6010f9eSJoseph Koshy * IMPLEMENTATION NOTES 8749874f6eSJoseph Koshy * 88b6010f9eSJoseph Koshy * We correlate each 'callchain' or 'sample' entry seen in the event 89b6010f9eSJoseph Koshy * log back to an executable object in the system. Executable objects 90b6010f9eSJoseph Koshy * include: 9149874f6eSJoseph Koshy * - program executables, 9249874f6eSJoseph Koshy * - shared libraries loaded by the runtime loader, 9349874f6eSJoseph Koshy * - dlopen()'ed objects loaded by the program, 9449874f6eSJoseph Koshy * - the runtime loader itself, 9549874f6eSJoseph Koshy * - the kernel and kernel modules. 9649874f6eSJoseph Koshy * 9749874f6eSJoseph Koshy * Each process that we know about is treated as a set of regions that 9849874f6eSJoseph Koshy * map to executable objects. Processes are described by 9949874f6eSJoseph Koshy * 'pmcstat_process' structures. Executable objects are tracked by 10049874f6eSJoseph Koshy * 'pmcstat_image' structures. The kernel and kernel modules are 10149874f6eSJoseph Koshy * common to all processes (they reside at the same virtual addresses 10249874f6eSJoseph Koshy * for all processes). Individual processes can have their text 10349874f6eSJoseph Koshy * segments and shared libraries loaded at process-specific locations. 10449874f6eSJoseph Koshy * 10549874f6eSJoseph Koshy * A given executable object can be in use by multiple processes 10649874f6eSJoseph Koshy * (e.g., libc.so) and loaded at a different address in each. 10749874f6eSJoseph Koshy * pmcstat_pcmap structures track per-image mappings. 10849874f6eSJoseph Koshy * 10949874f6eSJoseph Koshy * The sample log could have samples from multiple PMCs; we 11049874f6eSJoseph Koshy * generate one 'gmon.out' profile per PMC. 111b6010f9eSJoseph Koshy * 112b6010f9eSJoseph Koshy * IMPLEMENTATION OF GMON OUTPUT 113b6010f9eSJoseph Koshy * 114b6010f9eSJoseph Koshy * Each executable object gets one 'gmon.out' profile, per PMC in 115b6010f9eSJoseph Koshy * use. Creation of 'gmon.out' profiles is done lazily. The 116b6010f9eSJoseph Koshy * 'gmon.out' profiles generated for a given sampling PMC are 117b6010f9eSJoseph Koshy * aggregates of all the samples for that particular executable 118b6010f9eSJoseph Koshy * object. 119b6010f9eSJoseph Koshy * 120b6010f9eSJoseph Koshy * IMPLEMENTATION OF SYSTEM-WIDE CALLGRAPH OUTPUT 121b6010f9eSJoseph Koshy * 122b6010f9eSJoseph Koshy * Each active pmcid has its own callgraph structure, described by a 123b6010f9eSJoseph Koshy * 'struct pmcstat_callgraph'. Given a process id and a list of pc 124b6010f9eSJoseph Koshy * values, we map each pc value to a tuple (image, symbol), where 125b6010f9eSJoseph Koshy * 'image' denotes an executable object and 'symbol' is the closest 126b6010f9eSJoseph Koshy * symbol that precedes the pc value. Each pc value in the list is 127b6010f9eSJoseph Koshy * also given a 'rank' that reflects its depth in the call stack. 12815139246SJoseph Koshy */ 12915139246SJoseph Koshy 1300b86b1bbSFabien Thomas struct pmcstat_pmcs pmcstat_pmcs = LIST_HEAD_INITIALIZER(pmcstat_pmcs); 13115139246SJoseph Koshy 13249874f6eSJoseph Koshy /* 13349874f6eSJoseph Koshy * All image descriptors are kept in a hash table. 13449874f6eSJoseph Koshy */ 1350b86b1bbSFabien Thomas struct pmcstat_image_hash_list pmcstat_image_hash[PMCSTAT_NHASH]; 13615139246SJoseph Koshy 13749874f6eSJoseph Koshy /* 13849874f6eSJoseph Koshy * All process descriptors are kept in a hash table. 13949874f6eSJoseph Koshy */ 1400b86b1bbSFabien Thomas struct pmcstat_process_hash_list pmcstat_process_hash[PMCSTAT_NHASH]; 14115139246SJoseph Koshy 1420b86b1bbSFabien Thomas struct pmcstat_stats pmcstat_stats; /* statistics */ 143bf70beceSEd Schouten static int ps_samples_period; /* samples count between top refresh. */ 14415139246SJoseph Koshy 1450b86b1bbSFabien Thomas struct pmcstat_process *pmcstat_kernproc; /* kernel 'process' */ 146b6010f9eSJoseph Koshy 1470b86b1bbSFabien Thomas #include "pmcpl_gprof.h" 1480b86b1bbSFabien Thomas #include "pmcpl_callgraph.h" 1490b86b1bbSFabien Thomas #include "pmcpl_annotate.h" 15085ec49f3SAdrian Chadd #include "pmcpl_annotate_cg.h" 1510b86b1bbSFabien Thomas #include "pmcpl_calltree.h" 1520b86b1bbSFabien Thomas 153*d27927f7SRuslan Bukin static struct pmc_plugins plugins[] = { 1540b86b1bbSFabien Thomas { 1550b86b1bbSFabien Thomas .pl_name = "none", 1560b86b1bbSFabien Thomas }, 1570b86b1bbSFabien Thomas { 1580b86b1bbSFabien Thomas .pl_name = "callgraph", 1590b86b1bbSFabien Thomas .pl_init = pmcpl_cg_init, 1600b86b1bbSFabien Thomas .pl_shutdown = pmcpl_cg_shutdown, 1610b86b1bbSFabien Thomas .pl_process = pmcpl_cg_process, 1620b86b1bbSFabien Thomas .pl_topkeypress = pmcpl_cg_topkeypress, 1630b86b1bbSFabien Thomas .pl_topdisplay = pmcpl_cg_topdisplay 1640b86b1bbSFabien Thomas }, 1650b86b1bbSFabien Thomas { 1660b86b1bbSFabien Thomas .pl_name = "gprof", 1670b86b1bbSFabien Thomas .pl_shutdown = pmcpl_gmon_shutdown, 1680b86b1bbSFabien Thomas .pl_process = pmcpl_gmon_process, 1690b86b1bbSFabien Thomas .pl_initimage = pmcpl_gmon_initimage, 1700b86b1bbSFabien Thomas .pl_shutdownimage = pmcpl_gmon_shutdownimage, 1710b86b1bbSFabien Thomas .pl_newpmc = pmcpl_gmon_newpmc 1720b86b1bbSFabien Thomas }, 1730b86b1bbSFabien Thomas { 1740b86b1bbSFabien Thomas .pl_name = "annotate", 1750b86b1bbSFabien Thomas .pl_process = pmcpl_annotate_process 1760b86b1bbSFabien Thomas }, 1770b86b1bbSFabien Thomas { 1780b86b1bbSFabien Thomas .pl_name = "calltree", 1790b86b1bbSFabien Thomas .pl_configure = pmcpl_ct_configure, 1800b86b1bbSFabien Thomas .pl_init = pmcpl_ct_init, 1810b86b1bbSFabien Thomas .pl_shutdown = pmcpl_ct_shutdown, 1820b86b1bbSFabien Thomas .pl_process = pmcpl_ct_process, 1830b86b1bbSFabien Thomas .pl_topkeypress = pmcpl_ct_topkeypress, 1840b86b1bbSFabien Thomas .pl_topdisplay = pmcpl_ct_topdisplay 1850b86b1bbSFabien Thomas }, 1860b86b1bbSFabien Thomas { 18785ec49f3SAdrian Chadd .pl_name = "annotate_cg", 18885ec49f3SAdrian Chadd .pl_process = pmcpl_annotate_cg_process 18985ec49f3SAdrian Chadd }, 19085ec49f3SAdrian Chadd 19185ec49f3SAdrian Chadd { 1920b86b1bbSFabien Thomas .pl_name = NULL 1930b86b1bbSFabien Thomas } 194b6010f9eSJoseph Koshy }; 195b6010f9eSJoseph Koshy 196bf70beceSEd Schouten static int pmcstat_mergepmc; 197b6010f9eSJoseph Koshy 1980b86b1bbSFabien Thomas int pmcstat_pmcinfilter = 0; /* PMC filter for top mode. */ 1990b86b1bbSFabien Thomas float pmcstat_threshold = 0.5; /* Cost filter for top mode. */ 200b6010f9eSJoseph Koshy 20115139246SJoseph Koshy /* 20215139246SJoseph Koshy * Prototypes 20315139246SJoseph Koshy */ 20415139246SJoseph Koshy 205ac708fddSFabien Thomas static void pmcstat_stats_reset(int _reset_global); 20615139246SJoseph Koshy 20715139246SJoseph Koshy /* 2080b86b1bbSFabien Thomas * PMC count. 2090b86b1bbSFabien Thomas */ 2100b86b1bbSFabien Thomas int pmcstat_npmcs; 2110b86b1bbSFabien Thomas 2120b86b1bbSFabien Thomas /* 2130b86b1bbSFabien Thomas * PMC Top mode pause state. 2140b86b1bbSFabien Thomas */ 215bf70beceSEd Schouten static int pmcstat_pause; 2160b86b1bbSFabien Thomas 217c86819ecSFabien Thomas static void 218ac708fddSFabien Thomas pmcstat_stats_reset(int reset_global) 219c86819ecSFabien Thomas { 220c86819ecSFabien Thomas struct pmcstat_pmcrecord *pr; 221c86819ecSFabien Thomas 222c86819ecSFabien Thomas /* Flush PMCs stats. */ 223c86819ecSFabien Thomas LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) { 224c86819ecSFabien Thomas pr->pr_samples = 0; 225c86819ecSFabien Thomas pr->pr_dubious_frames = 0; 226c86819ecSFabien Thomas } 227ac708fddSFabien Thomas ps_samples_period = 0; 228c86819ecSFabien Thomas 229c86819ecSFabien Thomas /* Flush global stats. */ 230ac708fddSFabien Thomas if (reset_global) 231c86819ecSFabien Thomas bzero(&pmcstat_stats, sizeof(struct pmcstat_stats)); 232c86819ecSFabien Thomas } 233c86819ecSFabien Thomas 2340b86b1bbSFabien Thomas /* 2350b86b1bbSFabien Thomas * Resolve file name and line number for the given address. 2360b86b1bbSFabien Thomas */ 2370b86b1bbSFabien Thomas int 2380b86b1bbSFabien Thomas pmcstat_image_addr2line(struct pmcstat_image *image, uintfptr_t addr, 2390b86b1bbSFabien Thomas char *sourcefile, size_t sourcefile_len, unsigned *sourceline, 2400b86b1bbSFabien Thomas char *funcname, size_t funcname_len) 2410b86b1bbSFabien Thomas { 2420b86b1bbSFabien Thomas static int addr2line_warn = 0; 2430b86b1bbSFabien Thomas 2440b86b1bbSFabien Thomas char *sep, cmdline[PATH_MAX], imagepath[PATH_MAX]; 24566ca84a7SFabien Thomas unsigned l; 2460b86b1bbSFabien Thomas int fd; 2470b86b1bbSFabien Thomas 2480b86b1bbSFabien Thomas if (image->pi_addr2line == NULL) { 24966ca84a7SFabien Thomas /* Try default debug file location. */ 25066ca84a7SFabien Thomas snprintf(imagepath, sizeof(imagepath), 25166ca84a7SFabien Thomas "/usr/lib/debug/%s%s.debug", 25266ca84a7SFabien Thomas args.pa_fsroot, 25366ca84a7SFabien Thomas pmcstat_string_unintern(image->pi_fullpath)); 25466ca84a7SFabien Thomas fd = open(imagepath, O_RDONLY); 25566ca84a7SFabien Thomas if (fd < 0) { 25666ca84a7SFabien Thomas /* Old kernel symbol path. */ 257ac708fddSFabien Thomas snprintf(imagepath, sizeof(imagepath), "%s%s.symbols", 258ac708fddSFabien Thomas args.pa_fsroot, 2590b86b1bbSFabien Thomas pmcstat_string_unintern(image->pi_fullpath)); 2600b86b1bbSFabien Thomas fd = open(imagepath, O_RDONLY); 2610b86b1bbSFabien Thomas if (fd < 0) { 262ac708fddSFabien Thomas snprintf(imagepath, sizeof(imagepath), "%s%s", 263ac708fddSFabien Thomas args.pa_fsroot, 26466ca84a7SFabien Thomas pmcstat_string_unintern( 26566ca84a7SFabien Thomas image->pi_fullpath)); 26666ca84a7SFabien Thomas } 26766ca84a7SFabien Thomas } 26866ca84a7SFabien Thomas if (fd >= 0) 2690b86b1bbSFabien Thomas close(fd); 270fa18b0b2SFabien Thomas /* 271fa18b0b2SFabien Thomas * New addr2line support recursive inline function with -i 272fa18b0b2SFabien Thomas * but the format does not add a marker when no more entries 273fa18b0b2SFabien Thomas * are available. 274fa18b0b2SFabien Thomas */ 2750b86b1bbSFabien Thomas snprintf(cmdline, sizeof(cmdline), "addr2line -Cfe \"%s\"", 2760b86b1bbSFabien Thomas imagepath); 2770b86b1bbSFabien Thomas image->pi_addr2line = popen(cmdline, "r+"); 2780b86b1bbSFabien Thomas if (image->pi_addr2line == NULL) { 2790b86b1bbSFabien Thomas if (!addr2line_warn) { 2800b86b1bbSFabien Thomas addr2line_warn = 1; 28137d6f8a9SDavid E. O'Brien warnx( 28237d6f8a9SDavid E. O'Brien "WARNING: addr2line is needed for source code information." 28337d6f8a9SDavid E. O'Brien ); 2840b86b1bbSFabien Thomas } 2850b86b1bbSFabien Thomas return (0); 2860b86b1bbSFabien Thomas } 2870b86b1bbSFabien Thomas } 2880b86b1bbSFabien Thomas 2890b86b1bbSFabien Thomas if (feof(image->pi_addr2line) || ferror(image->pi_addr2line)) { 2900b86b1bbSFabien Thomas warnx("WARNING: addr2line pipe error"); 2910b86b1bbSFabien Thomas pclose(image->pi_addr2line); 2920b86b1bbSFabien Thomas image->pi_addr2line = NULL; 2930b86b1bbSFabien Thomas return (0); 2940b86b1bbSFabien Thomas } 2950b86b1bbSFabien Thomas 2960b86b1bbSFabien Thomas fprintf(image->pi_addr2line, "%p\n", (void *)addr); 2970b86b1bbSFabien Thomas 2980b86b1bbSFabien Thomas if (fgets(funcname, funcname_len, image->pi_addr2line) == NULL) { 2990b86b1bbSFabien Thomas warnx("WARNING: addr2line function name read error"); 3000b86b1bbSFabien Thomas return (0); 3010b86b1bbSFabien Thomas } 3020b86b1bbSFabien Thomas sep = strchr(funcname, '\n'); 3030b86b1bbSFabien Thomas if (sep != NULL) 3040b86b1bbSFabien Thomas *sep = '\0'; 3050b86b1bbSFabien Thomas 3060b86b1bbSFabien Thomas if (fgets(sourcefile, sourcefile_len, image->pi_addr2line) == NULL) { 3070b86b1bbSFabien Thomas warnx("WARNING: addr2line source file read error"); 3080b86b1bbSFabien Thomas return (0); 3090b86b1bbSFabien Thomas } 3100b86b1bbSFabien Thomas sep = strchr(sourcefile, ':'); 3110b86b1bbSFabien Thomas if (sep == NULL) { 3120b86b1bbSFabien Thomas warnx("WARNING: addr2line source line separator missing"); 3130b86b1bbSFabien Thomas return (0); 3140b86b1bbSFabien Thomas } 3150b86b1bbSFabien Thomas *sep = '\0'; 316fa18b0b2SFabien Thomas l = atoi(sep+1); 317fa18b0b2SFabien Thomas if (l == 0) 3180b86b1bbSFabien Thomas return (0); 319fa18b0b2SFabien Thomas *sourceline = l; 3200b86b1bbSFabien Thomas return (1); 3210b86b1bbSFabien Thomas } 3220b86b1bbSFabien Thomas 3230b86b1bbSFabien Thomas /* 32449874f6eSJoseph Koshy * Given a pmcid in use, find its human-readable name. 32515139246SJoseph Koshy */ 32615139246SJoseph Koshy 3270b86b1bbSFabien Thomas const char * 32815139246SJoseph Koshy pmcstat_pmcid_to_name(pmc_id_t pmcid) 32915139246SJoseph Koshy { 33015139246SJoseph Koshy struct pmcstat_pmcrecord *pr; 33115139246SJoseph Koshy 33215139246SJoseph Koshy LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) 33315139246SJoseph Koshy if (pr->pr_pmcid == pmcid) 33449874f6eSJoseph Koshy return (pmcstat_string_unintern(pr->pr_pmcname)); 33515139246SJoseph Koshy 3360b86b1bbSFabien Thomas return NULL; 3370b86b1bbSFabien Thomas } 33815139246SJoseph Koshy 3390b86b1bbSFabien Thomas /* 3400b86b1bbSFabien Thomas * Convert PMC index to name. 3410b86b1bbSFabien Thomas */ 34215139246SJoseph Koshy 3430b86b1bbSFabien Thomas const char * 3440b86b1bbSFabien Thomas pmcstat_pmcindex_to_name(int pmcin) 3450b86b1bbSFabien Thomas { 3460b86b1bbSFabien Thomas struct pmcstat_pmcrecord *pr; 34715139246SJoseph Koshy 3480b86b1bbSFabien Thomas LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) 3490b86b1bbSFabien Thomas if (pr->pr_pmcin == pmcin) 3500b86b1bbSFabien Thomas return pmcstat_string_unintern(pr->pr_pmcname); 3510b86b1bbSFabien Thomas 3520b86b1bbSFabien Thomas return NULL; 3530b86b1bbSFabien Thomas } 3540b86b1bbSFabien Thomas 3550b86b1bbSFabien Thomas /* 3560b86b1bbSFabien Thomas * Return PMC record with given index. 3570b86b1bbSFabien Thomas */ 3580b86b1bbSFabien Thomas 3590b86b1bbSFabien Thomas struct pmcstat_pmcrecord * 3600b86b1bbSFabien Thomas pmcstat_pmcindex_to_pmcr(int pmcin) 3610b86b1bbSFabien Thomas { 3620b86b1bbSFabien Thomas struct pmcstat_pmcrecord *pr; 3630b86b1bbSFabien Thomas 3640b86b1bbSFabien Thomas LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) 3650b86b1bbSFabien Thomas if (pr->pr_pmcin == pmcin) 3660b86b1bbSFabien Thomas return pr; 3670b86b1bbSFabien Thomas 3680b86b1bbSFabien Thomas return NULL; 3690b86b1bbSFabien Thomas } 3700b86b1bbSFabien Thomas 3710b86b1bbSFabien Thomas /* 37215139246SJoseph Koshy * Print log entries as text. 37315139246SJoseph Koshy */ 37415139246SJoseph Koshy 37549874f6eSJoseph Koshy static int 3760b86b1bbSFabien Thomas pmcstat_print_log(void) 37715139246SJoseph Koshy { 37815139246SJoseph Koshy struct pmclog_ev ev; 379b6010f9eSJoseph Koshy uint32_t npc; 38015139246SJoseph Koshy 3810b86b1bbSFabien Thomas while (pmclog_read(args.pa_logparser, &ev) == 0) { 38215139246SJoseph Koshy assert(ev.pl_state == PMCLOG_OK); 38315139246SJoseph Koshy switch (ev.pl_type) { 384b6010f9eSJoseph Koshy case PMCLOG_TYPE_CALLCHAIN: 3850b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("callchain", 386b6010f9eSJoseph Koshy "%d 0x%x %d %d %c", ev.pl_u.pl_cc.pl_pid, 387b6010f9eSJoseph Koshy ev.pl_u.pl_cc.pl_pmcid, 388b6010f9eSJoseph Koshy PMC_CALLCHAIN_CPUFLAGS_TO_CPU(ev.pl_u.pl_cc. \ 389b6010f9eSJoseph Koshy pl_cpuflags), ev.pl_u.pl_cc.pl_npc, 390b6010f9eSJoseph Koshy PMC_CALLCHAIN_CPUFLAGS_TO_USERMODE(ev.pl_u.pl_cc.\ 391b6010f9eSJoseph Koshy pl_cpuflags) ? 'u' : 's'); 392b6010f9eSJoseph Koshy for (npc = 0; npc < ev.pl_u.pl_cc.pl_npc; npc++) 3930b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("...", "%p", 394b6010f9eSJoseph Koshy (void *) ev.pl_u.pl_cc.pl_pc[npc]); 395b6010f9eSJoseph Koshy break; 39615139246SJoseph Koshy case PMCLOG_TYPE_CLOSELOG: 3970b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("closelog",); 39815139246SJoseph Koshy break; 39915139246SJoseph Koshy case PMCLOG_TYPE_DROPNOTIFY: 4000b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("drop",); 40115139246SJoseph Koshy break; 40215139246SJoseph Koshy case PMCLOG_TYPE_INITIALIZE: 4030b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("initlog","0x%x \"%s\"", 40415139246SJoseph Koshy ev.pl_u.pl_i.pl_version, 40515139246SJoseph Koshy pmc_name_of_cputype(ev.pl_u.pl_i.pl_arch)); 4063ab065b6SJoseph Koshy if ((ev.pl_u.pl_i.pl_version & 0xFF000000) != 4070b86b1bbSFabien Thomas PMC_VERSION_MAJOR << 24 && args.pa_verbosity > 0) 40837d6f8a9SDavid E. O'Brien warnx( 40937d6f8a9SDavid E. O'Brien "WARNING: Log version 0x%x != expected version 0x%x.", 41037d6f8a9SDavid E. O'Brien ev.pl_u.pl_i.pl_version, PMC_VERSION); 41115139246SJoseph Koshy break; 41249874f6eSJoseph Koshy case PMCLOG_TYPE_MAP_IN: 4130b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("map-in","%d %p \"%s\"", 41449874f6eSJoseph Koshy ev.pl_u.pl_mi.pl_pid, 41549874f6eSJoseph Koshy (void *) ev.pl_u.pl_mi.pl_start, 41649874f6eSJoseph Koshy ev.pl_u.pl_mi.pl_pathname); 41749874f6eSJoseph Koshy break; 41849874f6eSJoseph Koshy case PMCLOG_TYPE_MAP_OUT: 4190b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("map-out","%d %p %p", 42049874f6eSJoseph Koshy ev.pl_u.pl_mo.pl_pid, 42149874f6eSJoseph Koshy (void *) ev.pl_u.pl_mo.pl_start, 42249874f6eSJoseph Koshy (void *) ev.pl_u.pl_mo.pl_end); 42315139246SJoseph Koshy break; 42415139246SJoseph Koshy case PMCLOG_TYPE_PCSAMPLE: 4250b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("sample","0x%x %d %p %c", 42615139246SJoseph Koshy ev.pl_u.pl_s.pl_pmcid, 42715139246SJoseph Koshy ev.pl_u.pl_s.pl_pid, 42815139246SJoseph Koshy (void *) ev.pl_u.pl_s.pl_pc, 42915139246SJoseph Koshy ev.pl_u.pl_s.pl_usermode ? 'u' : 's'); 43015139246SJoseph Koshy break; 43115139246SJoseph Koshy case PMCLOG_TYPE_PMCALLOCATE: 4320b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("allocate","0x%x \"%s\" 0x%x", 43315139246SJoseph Koshy ev.pl_u.pl_a.pl_pmcid, 43415139246SJoseph Koshy ev.pl_u.pl_a.pl_evname, 43515139246SJoseph Koshy ev.pl_u.pl_a.pl_flags); 43615139246SJoseph Koshy break; 437f5f9340bSFabien Thomas case PMCLOG_TYPE_PMCALLOCATEDYN: 438f5f9340bSFabien Thomas PMCSTAT_PRINT_ENTRY("allocatedyn","0x%x \"%s\" 0x%x", 439f5f9340bSFabien Thomas ev.pl_u.pl_ad.pl_pmcid, 440f5f9340bSFabien Thomas ev.pl_u.pl_ad.pl_evname, 441f5f9340bSFabien Thomas ev.pl_u.pl_ad.pl_flags); 442f5f9340bSFabien Thomas break; 44315139246SJoseph Koshy case PMCLOG_TYPE_PMCATTACH: 4440b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("attach","0x%x %d \"%s\"", 44515139246SJoseph Koshy ev.pl_u.pl_t.pl_pmcid, 44615139246SJoseph Koshy ev.pl_u.pl_t.pl_pid, 44715139246SJoseph Koshy ev.pl_u.pl_t.pl_pathname); 44815139246SJoseph Koshy break; 44915139246SJoseph Koshy case PMCLOG_TYPE_PMCDETACH: 4500b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("detach","0x%x %d", 45115139246SJoseph Koshy ev.pl_u.pl_d.pl_pmcid, 45215139246SJoseph Koshy ev.pl_u.pl_d.pl_pid); 45315139246SJoseph Koshy break; 45415139246SJoseph Koshy case PMCLOG_TYPE_PROCCSW: 4550b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("cswval","0x%x %d %jd", 45615139246SJoseph Koshy ev.pl_u.pl_c.pl_pmcid, 45715139246SJoseph Koshy ev.pl_u.pl_c.pl_pid, 45815139246SJoseph Koshy ev.pl_u.pl_c.pl_value); 45915139246SJoseph Koshy break; 46015139246SJoseph Koshy case PMCLOG_TYPE_PROCEXEC: 4610b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("exec","0x%x %d %p \"%s\"", 46215139246SJoseph Koshy ev.pl_u.pl_x.pl_pmcid, 46315139246SJoseph Koshy ev.pl_u.pl_x.pl_pid, 46415139246SJoseph Koshy (void *) ev.pl_u.pl_x.pl_entryaddr, 46515139246SJoseph Koshy ev.pl_u.pl_x.pl_pathname); 46615139246SJoseph Koshy break; 46715139246SJoseph Koshy case PMCLOG_TYPE_PROCEXIT: 4680b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("exitval","0x%x %d %jd", 46915139246SJoseph Koshy ev.pl_u.pl_e.pl_pmcid, 47015139246SJoseph Koshy ev.pl_u.pl_e.pl_pid, 47115139246SJoseph Koshy ev.pl_u.pl_e.pl_value); 47215139246SJoseph Koshy break; 47315139246SJoseph Koshy case PMCLOG_TYPE_PROCFORK: 4740b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("fork","%d %d", 47515139246SJoseph Koshy ev.pl_u.pl_f.pl_oldpid, 47615139246SJoseph Koshy ev.pl_u.pl_f.pl_newpid); 47715139246SJoseph Koshy break; 47815139246SJoseph Koshy case PMCLOG_TYPE_USERDATA: 4790b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("userdata","0x%x", 48015139246SJoseph Koshy ev.pl_u.pl_u.pl_userdata); 48115139246SJoseph Koshy break; 48215139246SJoseph Koshy case PMCLOG_TYPE_SYSEXIT: 4830b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("exit","%d", 48415139246SJoseph Koshy ev.pl_u.pl_se.pl_pid); 48515139246SJoseph Koshy break; 48615139246SJoseph Koshy default: 4870b86b1bbSFabien Thomas fprintf(args.pa_printfile, "unknown event (type %d).\n", 48815139246SJoseph Koshy ev.pl_type); 48915139246SJoseph Koshy } 49015139246SJoseph Koshy } 49115139246SJoseph Koshy 49215139246SJoseph Koshy if (ev.pl_state == PMCLOG_EOF) 49349874f6eSJoseph Koshy return (PMCSTAT_FINISHED); 49415139246SJoseph Koshy else if (ev.pl_state == PMCLOG_REQUIRE_DATA) 49549874f6eSJoseph Koshy return (PMCSTAT_RUNNING); 49615139246SJoseph Koshy 49737d6f8a9SDavid E. O'Brien errx(EX_DATAERR, 49837d6f8a9SDavid E. O'Brien "ERROR: event parsing failed (record %jd, offset 0x%jx).", 49915139246SJoseph Koshy (uintmax_t) ev.pl_count + 1, ev.pl_offset); 50015139246SJoseph Koshy /*NOTREACHED*/ 50115139246SJoseph Koshy } 50215139246SJoseph Koshy 50315139246SJoseph Koshy /* 50449874f6eSJoseph Koshy * Public Interfaces. 50549874f6eSJoseph Koshy */ 50649874f6eSJoseph Koshy 50749874f6eSJoseph Koshy /* 50815139246SJoseph Koshy * Process a log file in offline analysis mode. 50915139246SJoseph Koshy */ 51015139246SJoseph Koshy 511dc1d9d2eSJoseph Koshy int 5120b86b1bbSFabien Thomas pmcstat_process_log(void) 51315139246SJoseph Koshy { 51415139246SJoseph Koshy 51515139246SJoseph Koshy /* 516b6010f9eSJoseph Koshy * If analysis has not been asked for, just print the log to 517b6010f9eSJoseph Koshy * the current output file. 51815139246SJoseph Koshy */ 5190b86b1bbSFabien Thomas if (args.pa_flags & FLAG_DO_PRINT) 5200b86b1bbSFabien Thomas return (pmcstat_print_log()); 52115139246SJoseph Koshy else 522*d27927f7SRuslan Bukin return (pmcstat_analyze_log(&args, plugins, &pmcstat_stats, pmcstat_kernproc, 523*d27927f7SRuslan Bukin pmcstat_mergepmc, &pmcstat_npmcs, &ps_samples_period)); 5240b86b1bbSFabien Thomas } 5250b86b1bbSFabien Thomas 5260b86b1bbSFabien Thomas /* 5270b86b1bbSFabien Thomas * Refresh top display. 5280b86b1bbSFabien Thomas */ 5290b86b1bbSFabien Thomas 5300b86b1bbSFabien Thomas static void 5310b86b1bbSFabien Thomas pmcstat_refresh_top(void) 5320b86b1bbSFabien Thomas { 533c86819ecSFabien Thomas int v_attrs; 534c86819ecSFabien Thomas float v; 5350b86b1bbSFabien Thomas char pmcname[40]; 536c86819ecSFabien Thomas struct pmcstat_pmcrecord *pmcpr; 5370b86b1bbSFabien Thomas 5380b86b1bbSFabien Thomas /* If in pause mode do not refresh display. */ 5390b86b1bbSFabien Thomas if (pmcstat_pause) 5400b86b1bbSFabien Thomas return; 5410b86b1bbSFabien Thomas 5429ba84a88SFabien Thomas /* Wait until PMC pop in the log. */ 543c86819ecSFabien Thomas pmcpr = pmcstat_pmcindex_to_pmcr(pmcstat_pmcinfilter); 544c86819ecSFabien Thomas if (pmcpr == NULL) 5459ba84a88SFabien Thomas return; 5469ba84a88SFabien Thomas 5470b86b1bbSFabien Thomas /* Format PMC name. */ 5480b86b1bbSFabien Thomas if (pmcstat_mergepmc) 549c86819ecSFabien Thomas snprintf(pmcname, sizeof(pmcname), "[%s]", 550c86819ecSFabien Thomas pmcstat_string_unintern(pmcpr->pr_pmcname)); 5510b86b1bbSFabien Thomas else 5520b86b1bbSFabien Thomas snprintf(pmcname, sizeof(pmcname), "%s.%d", 553c86819ecSFabien Thomas pmcstat_string_unintern(pmcpr->pr_pmcname), 554c86819ecSFabien Thomas pmcstat_pmcinfilter); 555c86819ecSFabien Thomas 556c86819ecSFabien Thomas /* Format samples count. */ 557ac708fddSFabien Thomas if (ps_samples_period > 0) 558ac708fddSFabien Thomas v = (pmcpr->pr_samples * 100.0) / ps_samples_period; 559c86819ecSFabien Thomas else 560c86819ecSFabien Thomas v = 0.; 561c86819ecSFabien Thomas v_attrs = PMCSTAT_ATTRPERCENT(v); 5620b86b1bbSFabien Thomas 5630b86b1bbSFabien Thomas PMCSTAT_PRINTBEGIN(); 564c86819ecSFabien Thomas PMCSTAT_PRINTW("PMC: %s Samples: %u ", 5650b86b1bbSFabien Thomas pmcname, 566c86819ecSFabien Thomas pmcpr->pr_samples); 567c86819ecSFabien Thomas PMCSTAT_ATTRON(v_attrs); 568c86819ecSFabien Thomas PMCSTAT_PRINTW("(%.1f%%) ", v); 569c86819ecSFabien Thomas PMCSTAT_ATTROFF(v_attrs); 570c86819ecSFabien Thomas PMCSTAT_PRINTW(", %u unresolved\n\n", 571c86819ecSFabien Thomas pmcpr->pr_dubious_frames); 5720b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_topdisplay != NULL) 5730b86b1bbSFabien Thomas plugins[args.pa_plugin].pl_topdisplay(); 5740b86b1bbSFabien Thomas PMCSTAT_PRINTEND(); 5750b86b1bbSFabien Thomas } 5760b86b1bbSFabien Thomas 5770b86b1bbSFabien Thomas /* 5780b86b1bbSFabien Thomas * Find the next pmc index to display. 5790b86b1bbSFabien Thomas */ 5800b86b1bbSFabien Thomas 5810b86b1bbSFabien Thomas static void 5820b86b1bbSFabien Thomas pmcstat_changefilter(void) 5830b86b1bbSFabien Thomas { 5840b86b1bbSFabien Thomas int pmcin; 5850b86b1bbSFabien Thomas struct pmcstat_pmcrecord *pmcr; 5860b86b1bbSFabien Thomas 5870b86b1bbSFabien Thomas /* 5880b86b1bbSFabien Thomas * Find the next merge target. 5890b86b1bbSFabien Thomas */ 5900b86b1bbSFabien Thomas if (pmcstat_mergepmc) { 5910b86b1bbSFabien Thomas pmcin = pmcstat_pmcinfilter; 5920b86b1bbSFabien Thomas 5930b86b1bbSFabien Thomas do { 5940b86b1bbSFabien Thomas pmcr = pmcstat_pmcindex_to_pmcr(pmcstat_pmcinfilter); 595ac708fddSFabien Thomas if (pmcr == NULL || pmcr == pmcr->pr_merge) 5960b86b1bbSFabien Thomas break; 5970b86b1bbSFabien Thomas 5980b86b1bbSFabien Thomas pmcstat_pmcinfilter++; 5990b86b1bbSFabien Thomas if (pmcstat_pmcinfilter >= pmcstat_npmcs) 6000b86b1bbSFabien Thomas pmcstat_pmcinfilter = 0; 6010b86b1bbSFabien Thomas 6020b86b1bbSFabien Thomas } while (pmcstat_pmcinfilter != pmcin); 6030b86b1bbSFabien Thomas } 6040b86b1bbSFabien Thomas } 6050b86b1bbSFabien Thomas 6060b86b1bbSFabien Thomas /* 6070b86b1bbSFabien Thomas * Top mode keypress. 6080b86b1bbSFabien Thomas */ 6090b86b1bbSFabien Thomas 6100b86b1bbSFabien Thomas int 6110b86b1bbSFabien Thomas pmcstat_keypress_log(void) 6120b86b1bbSFabien Thomas { 6130b86b1bbSFabien Thomas int c, ret = 0; 6140b86b1bbSFabien Thomas WINDOW *w; 6150b86b1bbSFabien Thomas 6160b86b1bbSFabien Thomas w = newwin(1, 0, 1, 0); 6170b86b1bbSFabien Thomas c = wgetch(w); 6180b86b1bbSFabien Thomas wprintw(w, "Key: %c => ", c); 6190b86b1bbSFabien Thomas switch (c) { 6200b86b1bbSFabien Thomas case 'c': 6210b86b1bbSFabien Thomas wprintw(w, "enter mode 'd' or 'a' => "); 6220b86b1bbSFabien Thomas c = wgetch(w); 6230b86b1bbSFabien Thomas if (c == 'd') { 6240b86b1bbSFabien Thomas args.pa_topmode = PMCSTAT_TOP_DELTA; 6250b86b1bbSFabien Thomas wprintw(w, "switching to delta mode"); 6260b86b1bbSFabien Thomas } else { 6270b86b1bbSFabien Thomas args.pa_topmode = PMCSTAT_TOP_ACCUM; 6280b86b1bbSFabien Thomas wprintw(w, "switching to accumulation mode"); 6290b86b1bbSFabien Thomas } 6300b86b1bbSFabien Thomas break; 6310b86b1bbSFabien Thomas case 'm': 6320b86b1bbSFabien Thomas pmcstat_mergepmc = !pmcstat_mergepmc; 6330b86b1bbSFabien Thomas /* 6340b86b1bbSFabien Thomas * Changing merge state require data reset. 6350b86b1bbSFabien Thomas */ 6360b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_shutdown != NULL) 6370b86b1bbSFabien Thomas plugins[args.pa_plugin].pl_shutdown(NULL); 638ac708fddSFabien Thomas pmcstat_stats_reset(0); 6390b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_init != NULL) 6400b86b1bbSFabien Thomas plugins[args.pa_plugin].pl_init(); 6410b86b1bbSFabien Thomas 6420b86b1bbSFabien Thomas /* Update filter to be on a merge target. */ 6430b86b1bbSFabien Thomas pmcstat_changefilter(); 6440b86b1bbSFabien Thomas wprintw(w, "merge PMC %s", pmcstat_mergepmc ? "on" : "off"); 6450b86b1bbSFabien Thomas break; 6460b86b1bbSFabien Thomas case 'n': 6470b86b1bbSFabien Thomas /* Close current plugin. */ 6480b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_shutdown != NULL) 6490b86b1bbSFabien Thomas plugins[args.pa_plugin].pl_shutdown(NULL); 6500b86b1bbSFabien Thomas 6510b86b1bbSFabien Thomas /* Find next top display available. */ 6520b86b1bbSFabien Thomas do { 6530b86b1bbSFabien Thomas args.pa_plugin++; 6540b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_name == NULL) 6550b86b1bbSFabien Thomas args.pa_plugin = 0; 6560b86b1bbSFabien Thomas } while (plugins[args.pa_plugin].pl_topdisplay == NULL); 6570b86b1bbSFabien Thomas 6580b86b1bbSFabien Thomas /* Open new plugin. */ 659ac708fddSFabien Thomas pmcstat_stats_reset(0); 6600b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_init != NULL) 6610b86b1bbSFabien Thomas plugins[args.pa_plugin].pl_init(); 6620b86b1bbSFabien Thomas wprintw(w, "switching to plugin %s", 6630b86b1bbSFabien Thomas plugins[args.pa_plugin].pl_name); 6640b86b1bbSFabien Thomas break; 6650b86b1bbSFabien Thomas case 'p': 6660b86b1bbSFabien Thomas pmcstat_pmcinfilter++; 6670b86b1bbSFabien Thomas if (pmcstat_pmcinfilter >= pmcstat_npmcs) 6680b86b1bbSFabien Thomas pmcstat_pmcinfilter = 0; 6690b86b1bbSFabien Thomas pmcstat_changefilter(); 6700b86b1bbSFabien Thomas wprintw(w, "switching to PMC %s.%d", 6710b86b1bbSFabien Thomas pmcstat_pmcindex_to_name(pmcstat_pmcinfilter), 6720b86b1bbSFabien Thomas pmcstat_pmcinfilter); 6730b86b1bbSFabien Thomas break; 6740b86b1bbSFabien Thomas case ' ': 6750b86b1bbSFabien Thomas pmcstat_pause = !pmcstat_pause; 6760b86b1bbSFabien Thomas if (pmcstat_pause) 6770b86b1bbSFabien Thomas wprintw(w, "pause => press space again to continue"); 6780b86b1bbSFabien Thomas break; 6790b86b1bbSFabien Thomas case 'q': 6800b86b1bbSFabien Thomas wprintw(w, "exiting..."); 6810b86b1bbSFabien Thomas ret = 1; 6825c15d3c8SFabien Thomas break; 6830b86b1bbSFabien Thomas default: 6840b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_topkeypress != NULL) 685*d27927f7SRuslan Bukin if (plugins[args.pa_plugin].pl_topkeypress(c, (void *)w)) 6860b86b1bbSFabien Thomas ret = 1; 6870b86b1bbSFabien Thomas } 6880b86b1bbSFabien Thomas 6890b86b1bbSFabien Thomas wrefresh(w); 6900b86b1bbSFabien Thomas delwin(w); 6910b86b1bbSFabien Thomas return ret; 6920b86b1bbSFabien Thomas } 6930b86b1bbSFabien Thomas 6940b86b1bbSFabien Thomas 6950b86b1bbSFabien Thomas /* 6960b86b1bbSFabien Thomas * Top mode display. 6970b86b1bbSFabien Thomas */ 6980b86b1bbSFabien Thomas 6990b86b1bbSFabien Thomas void 7000b86b1bbSFabien Thomas pmcstat_display_log(void) 7010b86b1bbSFabien Thomas { 7020b86b1bbSFabien Thomas 7030b86b1bbSFabien Thomas pmcstat_refresh_top(); 7040b86b1bbSFabien Thomas 7050b86b1bbSFabien Thomas /* Reset everythings if delta mode. */ 7060b86b1bbSFabien Thomas if (args.pa_topmode == PMCSTAT_TOP_DELTA) { 7070b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_shutdown != NULL) 7080b86b1bbSFabien Thomas plugins[args.pa_plugin].pl_shutdown(NULL); 709ac708fddSFabien Thomas pmcstat_stats_reset(0); 7100b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_init != NULL) 7110b86b1bbSFabien Thomas plugins[args.pa_plugin].pl_init(); 7120b86b1bbSFabien Thomas } 7130b86b1bbSFabien Thomas } 7140b86b1bbSFabien Thomas 7150b86b1bbSFabien Thomas /* 7160b86b1bbSFabien Thomas * Configure a plugins. 7170b86b1bbSFabien Thomas */ 7180b86b1bbSFabien Thomas 7190b86b1bbSFabien Thomas void 7200b86b1bbSFabien Thomas pmcstat_pluginconfigure_log(char *opt) 7210b86b1bbSFabien Thomas { 7220b86b1bbSFabien Thomas 7230b86b1bbSFabien Thomas if (strncmp(opt, "threshold=", 10) == 0) { 7240b86b1bbSFabien Thomas pmcstat_threshold = atof(opt+10); 7250b86b1bbSFabien Thomas } else { 7260b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_configure != NULL) { 7270b86b1bbSFabien Thomas if (!plugins[args.pa_plugin].pl_configure(opt)) 7280b86b1bbSFabien Thomas err(EX_USAGE, 7290b86b1bbSFabien Thomas "ERROR: unknown option <%s>.", opt); 7300b86b1bbSFabien Thomas } 7310b86b1bbSFabien Thomas } 73215139246SJoseph Koshy } 73315139246SJoseph Koshy 734*d27927f7SRuslan Bukin void 735*d27927f7SRuslan Bukin pmcstat_log_shutdown_logging(void) 736*d27927f7SRuslan Bukin { 737*d27927f7SRuslan Bukin 738*d27927f7SRuslan Bukin pmcstat_shutdown_logging(&args, plugins, &pmcstat_stats); 739*d27927f7SRuslan Bukin } 74049874f6eSJoseph Koshy 74115139246SJoseph Koshy void 742*d27927f7SRuslan Bukin pmcstat_log_initialize_logging(void) 74315139246SJoseph Koshy { 74449874f6eSJoseph Koshy 745*d27927f7SRuslan Bukin pmcstat_initialize_logging(&pmcstat_kernproc, 746*d27927f7SRuslan Bukin &args, plugins, &pmcstat_npmcs, &pmcstat_mergepmc); 74715139246SJoseph Koshy } 748