115139246SJoseph Koshy /*- 21de7b4b8SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 31de7b4b8SPedro F. Giffuni * 4b6010f9eSJoseph Koshy * Copyright (c) 2005-2007, Joseph Koshy 5b6010f9eSJoseph Koshy * Copyright (c) 2007 The FreeBSD Foundation 615139246SJoseph Koshy * All rights reserved. 715139246SJoseph Koshy * 8b6010f9eSJoseph Koshy * Portions of this software were developed by A. Joseph Koshy under 9b6010f9eSJoseph Koshy * sponsorship from the FreeBSD Foundation and Google, Inc. 10b6010f9eSJoseph Koshy * 1115139246SJoseph Koshy * Redistribution and use in source and binary forms, with or without 1215139246SJoseph Koshy * modification, are permitted provided that the following conditions 1315139246SJoseph Koshy * are met: 1415139246SJoseph Koshy * 1. Redistributions of source code must retain the above copyright 1515139246SJoseph Koshy * notice, this list of conditions and the following disclaimer. 1615139246SJoseph Koshy * 2. Redistributions in binary form must reproduce the above copyright 1715139246SJoseph Koshy * notice, this list of conditions and the following disclaimer in the 1815139246SJoseph Koshy * documentation and/or other materials provided with the distribution. 1915139246SJoseph Koshy * 2015139246SJoseph Koshy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2115139246SJoseph Koshy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2215139246SJoseph Koshy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2315139246SJoseph Koshy * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2415139246SJoseph Koshy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2515139246SJoseph Koshy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2615139246SJoseph Koshy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2715139246SJoseph Koshy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2815139246SJoseph Koshy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2915139246SJoseph Koshy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3015139246SJoseph Koshy * SUCH DAMAGE. 3115139246SJoseph Koshy */ 3215139246SJoseph Koshy 3349874f6eSJoseph Koshy /* 3449874f6eSJoseph Koshy * Transform a hwpmc(4) log into human readable form, and into 3549874f6eSJoseph Koshy * gprof(1) compatible profiles. 3649874f6eSJoseph Koshy */ 3749874f6eSJoseph Koshy 3815139246SJoseph Koshy #include <sys/cdefs.h> 3915139246SJoseph Koshy __FBSDID("$FreeBSD$"); 4015139246SJoseph Koshy 4115139246SJoseph Koshy #include <sys/param.h> 4215139246SJoseph Koshy #include <sys/endian.h> 43ea056888SAttilio Rao #include <sys/cpuset.h> 4415139246SJoseph Koshy #include <sys/gmon.h> 4515139246SJoseph Koshy #include <sys/imgact_aout.h> 4615139246SJoseph Koshy #include <sys/imgact_elf.h> 4715139246SJoseph Koshy #include <sys/mman.h> 4815139246SJoseph Koshy #include <sys/pmc.h> 4915139246SJoseph Koshy #include <sys/queue.h> 50302cbb90SJoseph Koshy #include <sys/socket.h> 5115139246SJoseph Koshy #include <sys/stat.h> 5215139246SJoseph Koshy #include <sys/wait.h> 5315139246SJoseph Koshy 5415139246SJoseph Koshy #include <netinet/in.h> 5515139246SJoseph Koshy 5615139246SJoseph Koshy #include <assert.h> 570b86b1bbSFabien Thomas #include <curses.h> 5815139246SJoseph Koshy #include <err.h> 59302cbb90SJoseph Koshy #include <errno.h> 6015139246SJoseph Koshy #include <fcntl.h> 61b6010f9eSJoseph Koshy #include <gelf.h> 6215139246SJoseph Koshy #include <libgen.h> 6315139246SJoseph Koshy #include <limits.h> 64302cbb90SJoseph Koshy #include <netdb.h> 6515139246SJoseph Koshy #include <pmc.h> 6615139246SJoseph Koshy #include <pmclog.h> 6715139246SJoseph Koshy #include <sysexits.h> 6815139246SJoseph Koshy #include <stdint.h> 6915139246SJoseph Koshy #include <stdio.h> 7015139246SJoseph Koshy #include <stdlib.h> 7115139246SJoseph Koshy #include <string.h> 7215139246SJoseph Koshy #include <unistd.h> 7315139246SJoseph Koshy 7415139246SJoseph Koshy #include "pmcstat.h" 750b86b1bbSFabien Thomas #include "pmcstat_log.h" 760b86b1bbSFabien Thomas #include "pmcstat_top.h" 7715139246SJoseph Koshy 7815139246SJoseph Koshy /* 7949874f6eSJoseph Koshy * PUBLIC INTERFACES 8049874f6eSJoseph Koshy * 8149874f6eSJoseph Koshy * pmcstat_initialize_logging() initialize this module, called first 8249874f6eSJoseph Koshy * pmcstat_shutdown_logging() orderly shutdown, called last 8349874f6eSJoseph Koshy * pmcstat_open_log() open an eventlog for processing 8449874f6eSJoseph Koshy * pmcstat_process_log() print/convert an event log 850b86b1bbSFabien Thomas * pmcstat_display_log() top mode display for the log 8649874f6eSJoseph Koshy * pmcstat_close_log() finish processing an event log 8749874f6eSJoseph Koshy * 88b6010f9eSJoseph Koshy * IMPLEMENTATION NOTES 8949874f6eSJoseph Koshy * 90b6010f9eSJoseph Koshy * We correlate each 'callchain' or 'sample' entry seen in the event 91b6010f9eSJoseph Koshy * log back to an executable object in the system. Executable objects 92b6010f9eSJoseph Koshy * include: 9349874f6eSJoseph Koshy * - program executables, 9449874f6eSJoseph Koshy * - shared libraries loaded by the runtime loader, 9549874f6eSJoseph Koshy * - dlopen()'ed objects loaded by the program, 9649874f6eSJoseph Koshy * - the runtime loader itself, 9749874f6eSJoseph Koshy * - the kernel and kernel modules. 9849874f6eSJoseph Koshy * 9949874f6eSJoseph Koshy * Each process that we know about is treated as a set of regions that 10049874f6eSJoseph Koshy * map to executable objects. Processes are described by 10149874f6eSJoseph Koshy * 'pmcstat_process' structures. Executable objects are tracked by 10249874f6eSJoseph Koshy * 'pmcstat_image' structures. The kernel and kernel modules are 10349874f6eSJoseph Koshy * common to all processes (they reside at the same virtual addresses 10449874f6eSJoseph Koshy * for all processes). Individual processes can have their text 10549874f6eSJoseph Koshy * segments and shared libraries loaded at process-specific locations. 10649874f6eSJoseph Koshy * 10749874f6eSJoseph Koshy * A given executable object can be in use by multiple processes 10849874f6eSJoseph Koshy * (e.g., libc.so) and loaded at a different address in each. 10949874f6eSJoseph Koshy * pmcstat_pcmap structures track per-image mappings. 11049874f6eSJoseph Koshy * 11149874f6eSJoseph Koshy * The sample log could have samples from multiple PMCs; we 11249874f6eSJoseph Koshy * generate one 'gmon.out' profile per PMC. 113b6010f9eSJoseph Koshy * 114b6010f9eSJoseph Koshy * IMPLEMENTATION OF GMON OUTPUT 115b6010f9eSJoseph Koshy * 116b6010f9eSJoseph Koshy * Each executable object gets one 'gmon.out' profile, per PMC in 117b6010f9eSJoseph Koshy * use. Creation of 'gmon.out' profiles is done lazily. The 118b6010f9eSJoseph Koshy * 'gmon.out' profiles generated for a given sampling PMC are 119b6010f9eSJoseph Koshy * aggregates of all the samples for that particular executable 120b6010f9eSJoseph Koshy * object. 121b6010f9eSJoseph Koshy * 122b6010f9eSJoseph Koshy * IMPLEMENTATION OF SYSTEM-WIDE CALLGRAPH OUTPUT 123b6010f9eSJoseph Koshy * 124b6010f9eSJoseph Koshy * Each active pmcid has its own callgraph structure, described by a 125b6010f9eSJoseph Koshy * 'struct pmcstat_callgraph'. Given a process id and a list of pc 126b6010f9eSJoseph Koshy * values, we map each pc value to a tuple (image, symbol), where 127b6010f9eSJoseph Koshy * 'image' denotes an executable object and 'symbol' is the closest 128b6010f9eSJoseph Koshy * symbol that precedes the pc value. Each pc value in the list is 129b6010f9eSJoseph Koshy * also given a 'rank' that reflects its depth in the call stack. 13015139246SJoseph Koshy */ 13115139246SJoseph Koshy 1320b86b1bbSFabien Thomas struct pmcstat_pmcs pmcstat_pmcs = LIST_HEAD_INITIALIZER(pmcstat_pmcs); 13315139246SJoseph Koshy 13449874f6eSJoseph Koshy /* 13549874f6eSJoseph Koshy * All image descriptors are kept in a hash table. 13649874f6eSJoseph Koshy */ 1370b86b1bbSFabien Thomas struct pmcstat_image_hash_list pmcstat_image_hash[PMCSTAT_NHASH]; 13815139246SJoseph Koshy 13949874f6eSJoseph Koshy /* 14049874f6eSJoseph Koshy * All process descriptors are kept in a hash table. 14149874f6eSJoseph Koshy */ 1420b86b1bbSFabien Thomas struct pmcstat_process_hash_list pmcstat_process_hash[PMCSTAT_NHASH]; 14315139246SJoseph Koshy 1440b86b1bbSFabien Thomas struct pmcstat_stats pmcstat_stats; /* statistics */ 145bf70beceSEd Schouten static int ps_samples_period; /* samples count between top refresh. */ 14615139246SJoseph Koshy 1470b86b1bbSFabien Thomas struct pmcstat_process *pmcstat_kernproc; /* kernel 'process' */ 148b6010f9eSJoseph Koshy 1490b86b1bbSFabien Thomas #include "pmcpl_gprof.h" 1500b86b1bbSFabien Thomas #include "pmcpl_callgraph.h" 1510b86b1bbSFabien Thomas #include "pmcpl_annotate.h" 15285ec49f3SAdrian Chadd #include "pmcpl_annotate_cg.h" 1530b86b1bbSFabien Thomas #include "pmcpl_calltree.h" 1540b86b1bbSFabien Thomas 155d27927f7SRuslan Bukin static struct pmc_plugins plugins[] = { 1560b86b1bbSFabien Thomas { 1570b86b1bbSFabien Thomas .pl_name = "none", 1580b86b1bbSFabien Thomas }, 1590b86b1bbSFabien Thomas { 1600b86b1bbSFabien Thomas .pl_name = "callgraph", 1610b86b1bbSFabien Thomas .pl_init = pmcpl_cg_init, 1620b86b1bbSFabien Thomas .pl_shutdown = pmcpl_cg_shutdown, 1630b86b1bbSFabien Thomas .pl_process = pmcpl_cg_process, 1640b86b1bbSFabien Thomas .pl_topkeypress = pmcpl_cg_topkeypress, 1650b86b1bbSFabien Thomas .pl_topdisplay = pmcpl_cg_topdisplay 1660b86b1bbSFabien Thomas }, 1670b86b1bbSFabien Thomas { 1680b86b1bbSFabien Thomas .pl_name = "gprof", 1690b86b1bbSFabien Thomas .pl_shutdown = pmcpl_gmon_shutdown, 1700b86b1bbSFabien Thomas .pl_process = pmcpl_gmon_process, 1710b86b1bbSFabien Thomas .pl_initimage = pmcpl_gmon_initimage, 1720b86b1bbSFabien Thomas .pl_shutdownimage = pmcpl_gmon_shutdownimage, 1730b86b1bbSFabien Thomas .pl_newpmc = pmcpl_gmon_newpmc 1740b86b1bbSFabien Thomas }, 1750b86b1bbSFabien Thomas { 1760b86b1bbSFabien Thomas .pl_name = "annotate", 1770b86b1bbSFabien Thomas .pl_process = pmcpl_annotate_process 1780b86b1bbSFabien Thomas }, 1790b86b1bbSFabien Thomas { 1800b86b1bbSFabien Thomas .pl_name = "calltree", 1810b86b1bbSFabien Thomas .pl_configure = pmcpl_ct_configure, 1820b86b1bbSFabien Thomas .pl_init = pmcpl_ct_init, 1830b86b1bbSFabien Thomas .pl_shutdown = pmcpl_ct_shutdown, 1840b86b1bbSFabien Thomas .pl_process = pmcpl_ct_process, 1850b86b1bbSFabien Thomas .pl_topkeypress = pmcpl_ct_topkeypress, 1860b86b1bbSFabien Thomas .pl_topdisplay = pmcpl_ct_topdisplay 1870b86b1bbSFabien Thomas }, 1880b86b1bbSFabien Thomas { 18985ec49f3SAdrian Chadd .pl_name = "annotate_cg", 19085ec49f3SAdrian Chadd .pl_process = pmcpl_annotate_cg_process 19185ec49f3SAdrian Chadd }, 19285ec49f3SAdrian Chadd 19385ec49f3SAdrian Chadd { 1940b86b1bbSFabien Thomas .pl_name = NULL 1950b86b1bbSFabien Thomas } 196b6010f9eSJoseph Koshy }; 197b6010f9eSJoseph Koshy 198bf70beceSEd Schouten static int pmcstat_mergepmc; 199b6010f9eSJoseph Koshy 2000b86b1bbSFabien Thomas int pmcstat_pmcinfilter = 0; /* PMC filter for top mode. */ 2010b86b1bbSFabien Thomas float pmcstat_threshold = 0.5; /* Cost filter for top mode. */ 202b6010f9eSJoseph Koshy 20315139246SJoseph Koshy /* 20415139246SJoseph Koshy * Prototypes 20515139246SJoseph Koshy */ 20615139246SJoseph Koshy 207ac708fddSFabien Thomas static void pmcstat_stats_reset(int _reset_global); 20815139246SJoseph Koshy 20915139246SJoseph Koshy /* 2100b86b1bbSFabien Thomas * PMC count. 2110b86b1bbSFabien Thomas */ 2120b86b1bbSFabien Thomas int pmcstat_npmcs; 2130b86b1bbSFabien Thomas 2140b86b1bbSFabien Thomas /* 2150b86b1bbSFabien Thomas * PMC Top mode pause state. 2160b86b1bbSFabien Thomas */ 217bf70beceSEd Schouten static int pmcstat_pause; 2180b86b1bbSFabien Thomas 219c86819ecSFabien Thomas static void 220ac708fddSFabien Thomas pmcstat_stats_reset(int reset_global) 221c86819ecSFabien Thomas { 222c86819ecSFabien Thomas struct pmcstat_pmcrecord *pr; 223c86819ecSFabien Thomas 224c86819ecSFabien Thomas /* Flush PMCs stats. */ 225c86819ecSFabien Thomas LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) { 226c86819ecSFabien Thomas pr->pr_samples = 0; 227c86819ecSFabien Thomas pr->pr_dubious_frames = 0; 228c86819ecSFabien Thomas } 229ac708fddSFabien Thomas ps_samples_period = 0; 230c86819ecSFabien Thomas 231c86819ecSFabien Thomas /* Flush global stats. */ 232ac708fddSFabien Thomas if (reset_global) 233c86819ecSFabien Thomas bzero(&pmcstat_stats, sizeof(struct pmcstat_stats)); 234c86819ecSFabien Thomas } 235c86819ecSFabien Thomas 2360b86b1bbSFabien Thomas /* 2370b86b1bbSFabien Thomas * Resolve file name and line number for the given address. 2380b86b1bbSFabien Thomas */ 2390b86b1bbSFabien Thomas int 2400b86b1bbSFabien Thomas pmcstat_image_addr2line(struct pmcstat_image *image, uintfptr_t addr, 2410b86b1bbSFabien Thomas char *sourcefile, size_t sourcefile_len, unsigned *sourceline, 2420b86b1bbSFabien Thomas char *funcname, size_t funcname_len) 2430b86b1bbSFabien Thomas { 2440b86b1bbSFabien Thomas static int addr2line_warn = 0; 2450b86b1bbSFabien Thomas 2460b86b1bbSFabien Thomas char *sep, cmdline[PATH_MAX], imagepath[PATH_MAX]; 24766ca84a7SFabien Thomas unsigned l; 2480b86b1bbSFabien Thomas int fd; 2490b86b1bbSFabien Thomas 2500b86b1bbSFabien Thomas if (image->pi_addr2line == NULL) { 25166ca84a7SFabien Thomas /* Try default debug file location. */ 25266ca84a7SFabien Thomas snprintf(imagepath, sizeof(imagepath), 25366ca84a7SFabien Thomas "/usr/lib/debug/%s%s.debug", 25466ca84a7SFabien Thomas args.pa_fsroot, 25566ca84a7SFabien Thomas pmcstat_string_unintern(image->pi_fullpath)); 25666ca84a7SFabien Thomas fd = open(imagepath, O_RDONLY); 25766ca84a7SFabien Thomas if (fd < 0) { 25866ca84a7SFabien Thomas /* Old kernel symbol path. */ 259ac708fddSFabien Thomas snprintf(imagepath, sizeof(imagepath), "%s%s.symbols", 260ac708fddSFabien Thomas args.pa_fsroot, 2610b86b1bbSFabien Thomas pmcstat_string_unintern(image->pi_fullpath)); 2620b86b1bbSFabien Thomas fd = open(imagepath, O_RDONLY); 2630b86b1bbSFabien Thomas if (fd < 0) { 264ac708fddSFabien Thomas snprintf(imagepath, sizeof(imagepath), "%s%s", 265ac708fddSFabien Thomas args.pa_fsroot, 26666ca84a7SFabien Thomas pmcstat_string_unintern( 26766ca84a7SFabien Thomas image->pi_fullpath)); 26866ca84a7SFabien Thomas } 26966ca84a7SFabien Thomas } 27066ca84a7SFabien Thomas if (fd >= 0) 2710b86b1bbSFabien Thomas close(fd); 272fa18b0b2SFabien Thomas /* 273fa18b0b2SFabien Thomas * New addr2line support recursive inline function with -i 274fa18b0b2SFabien Thomas * but the format does not add a marker when no more entries 275fa18b0b2SFabien Thomas * are available. 276fa18b0b2SFabien Thomas */ 2770b86b1bbSFabien Thomas snprintf(cmdline, sizeof(cmdline), "addr2line -Cfe \"%s\"", 2780b86b1bbSFabien Thomas imagepath); 2790b86b1bbSFabien Thomas image->pi_addr2line = popen(cmdline, "r+"); 2800b86b1bbSFabien Thomas if (image->pi_addr2line == NULL) { 2810b86b1bbSFabien Thomas if (!addr2line_warn) { 2820b86b1bbSFabien Thomas addr2line_warn = 1; 28337d6f8a9SDavid E. O'Brien warnx( 28437d6f8a9SDavid E. O'Brien "WARNING: addr2line is needed for source code information." 28537d6f8a9SDavid E. O'Brien ); 2860b86b1bbSFabien Thomas } 2870b86b1bbSFabien Thomas return (0); 2880b86b1bbSFabien Thomas } 2890b86b1bbSFabien Thomas } 2900b86b1bbSFabien Thomas 2910b86b1bbSFabien Thomas if (feof(image->pi_addr2line) || ferror(image->pi_addr2line)) { 2920b86b1bbSFabien Thomas warnx("WARNING: addr2line pipe error"); 2930b86b1bbSFabien Thomas pclose(image->pi_addr2line); 2940b86b1bbSFabien Thomas image->pi_addr2line = NULL; 2950b86b1bbSFabien Thomas return (0); 2960b86b1bbSFabien Thomas } 2970b86b1bbSFabien Thomas 2980b86b1bbSFabien Thomas fprintf(image->pi_addr2line, "%p\n", (void *)addr); 2990b86b1bbSFabien Thomas 3000b86b1bbSFabien Thomas if (fgets(funcname, funcname_len, image->pi_addr2line) == NULL) { 3010b86b1bbSFabien Thomas warnx("WARNING: addr2line function name read error"); 3020b86b1bbSFabien Thomas return (0); 3030b86b1bbSFabien Thomas } 3040b86b1bbSFabien Thomas sep = strchr(funcname, '\n'); 3050b86b1bbSFabien Thomas if (sep != NULL) 3060b86b1bbSFabien Thomas *sep = '\0'; 3070b86b1bbSFabien Thomas 3080b86b1bbSFabien Thomas if (fgets(sourcefile, sourcefile_len, image->pi_addr2line) == NULL) { 3090b86b1bbSFabien Thomas warnx("WARNING: addr2line source file read error"); 3100b86b1bbSFabien Thomas return (0); 3110b86b1bbSFabien Thomas } 3120b86b1bbSFabien Thomas sep = strchr(sourcefile, ':'); 3130b86b1bbSFabien Thomas if (sep == NULL) { 3140b86b1bbSFabien Thomas warnx("WARNING: addr2line source line separator missing"); 3150b86b1bbSFabien Thomas return (0); 3160b86b1bbSFabien Thomas } 3170b86b1bbSFabien Thomas *sep = '\0'; 318fa18b0b2SFabien Thomas l = atoi(sep+1); 319fa18b0b2SFabien Thomas if (l == 0) 3200b86b1bbSFabien Thomas return (0); 321fa18b0b2SFabien Thomas *sourceline = l; 3220b86b1bbSFabien Thomas return (1); 3230b86b1bbSFabien Thomas } 3240b86b1bbSFabien Thomas 3250b86b1bbSFabien Thomas /* 32649874f6eSJoseph Koshy * Given a pmcid in use, find its human-readable name. 32715139246SJoseph Koshy */ 32815139246SJoseph Koshy 3290b86b1bbSFabien Thomas const char * 33015139246SJoseph Koshy pmcstat_pmcid_to_name(pmc_id_t pmcid) 33115139246SJoseph Koshy { 33215139246SJoseph Koshy struct pmcstat_pmcrecord *pr; 33315139246SJoseph Koshy 33415139246SJoseph Koshy LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) 33515139246SJoseph Koshy if (pr->pr_pmcid == pmcid) 33649874f6eSJoseph Koshy return (pmcstat_string_unintern(pr->pr_pmcname)); 33715139246SJoseph Koshy 3380b86b1bbSFabien Thomas return NULL; 3390b86b1bbSFabien Thomas } 34015139246SJoseph Koshy 3410b86b1bbSFabien Thomas /* 3420b86b1bbSFabien Thomas * Convert PMC index to name. 3430b86b1bbSFabien Thomas */ 34415139246SJoseph Koshy 3450b86b1bbSFabien Thomas const char * 3460b86b1bbSFabien Thomas pmcstat_pmcindex_to_name(int pmcin) 3470b86b1bbSFabien Thomas { 3480b86b1bbSFabien Thomas struct pmcstat_pmcrecord *pr; 34915139246SJoseph Koshy 3500b86b1bbSFabien Thomas LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) 3510b86b1bbSFabien Thomas if (pr->pr_pmcin == pmcin) 3520b86b1bbSFabien Thomas return pmcstat_string_unintern(pr->pr_pmcname); 3530b86b1bbSFabien Thomas 3540b86b1bbSFabien Thomas return NULL; 3550b86b1bbSFabien Thomas } 3560b86b1bbSFabien Thomas 3570b86b1bbSFabien Thomas /* 3580b86b1bbSFabien Thomas * Return PMC record with given index. 3590b86b1bbSFabien Thomas */ 3600b86b1bbSFabien Thomas 3610b86b1bbSFabien Thomas struct pmcstat_pmcrecord * 3620b86b1bbSFabien Thomas pmcstat_pmcindex_to_pmcr(int pmcin) 3630b86b1bbSFabien Thomas { 3640b86b1bbSFabien Thomas struct pmcstat_pmcrecord *pr; 3650b86b1bbSFabien Thomas 3660b86b1bbSFabien Thomas LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) 3670b86b1bbSFabien Thomas if (pr->pr_pmcin == pmcin) 3680b86b1bbSFabien Thomas return pr; 3690b86b1bbSFabien Thomas 3700b86b1bbSFabien Thomas return NULL; 3710b86b1bbSFabien Thomas } 3720b86b1bbSFabien Thomas 3730b86b1bbSFabien Thomas /* 37415139246SJoseph Koshy * Print log entries as text. 37515139246SJoseph Koshy */ 37615139246SJoseph Koshy 37749874f6eSJoseph Koshy static int 3780b86b1bbSFabien Thomas pmcstat_print_log(void) 37915139246SJoseph Koshy { 38015139246SJoseph Koshy struct pmclog_ev ev; 381b6010f9eSJoseph Koshy uint32_t npc; 38215139246SJoseph Koshy 3830b86b1bbSFabien Thomas while (pmclog_read(args.pa_logparser, &ev) == 0) { 38415139246SJoseph Koshy assert(ev.pl_state == PMCLOG_OK); 38515139246SJoseph Koshy switch (ev.pl_type) { 386b6010f9eSJoseph Koshy case PMCLOG_TYPE_CALLCHAIN: 3870b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("callchain", 388b6010f9eSJoseph Koshy "%d 0x%x %d %d %c", ev.pl_u.pl_cc.pl_pid, 389b6010f9eSJoseph Koshy ev.pl_u.pl_cc.pl_pmcid, 390b6010f9eSJoseph Koshy PMC_CALLCHAIN_CPUFLAGS_TO_CPU(ev.pl_u.pl_cc. \ 391b6010f9eSJoseph Koshy pl_cpuflags), ev.pl_u.pl_cc.pl_npc, 392b6010f9eSJoseph Koshy PMC_CALLCHAIN_CPUFLAGS_TO_USERMODE(ev.pl_u.pl_cc.\ 393b6010f9eSJoseph Koshy pl_cpuflags) ? 'u' : 's'); 394b6010f9eSJoseph Koshy for (npc = 0; npc < ev.pl_u.pl_cc.pl_npc; npc++) 3950b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("...", "%p", 396b6010f9eSJoseph Koshy (void *) ev.pl_u.pl_cc.pl_pc[npc]); 397b6010f9eSJoseph Koshy break; 39815139246SJoseph Koshy case PMCLOG_TYPE_CLOSELOG: 3990b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("closelog",); 40015139246SJoseph Koshy break; 40115139246SJoseph Koshy case PMCLOG_TYPE_DROPNOTIFY: 4020b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("drop",); 40315139246SJoseph Koshy break; 40415139246SJoseph Koshy case PMCLOG_TYPE_INITIALIZE: 4050b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("initlog","0x%x \"%s\"", 40615139246SJoseph Koshy ev.pl_u.pl_i.pl_version, 40715139246SJoseph Koshy pmc_name_of_cputype(ev.pl_u.pl_i.pl_arch)); 4083ab065b6SJoseph Koshy if ((ev.pl_u.pl_i.pl_version & 0xFF000000) != 40995104040SMatt Macy PMC_VERSION_MAJOR << 24) 41037d6f8a9SDavid E. O'Brien warnx( 41137d6f8a9SDavid E. O'Brien "WARNING: Log version 0x%x != expected version 0x%x.", 41237d6f8a9SDavid E. O'Brien ev.pl_u.pl_i.pl_version, PMC_VERSION); 41315139246SJoseph Koshy break; 41449874f6eSJoseph Koshy case PMCLOG_TYPE_MAP_IN: 4150b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("map-in","%d %p \"%s\"", 41649874f6eSJoseph Koshy ev.pl_u.pl_mi.pl_pid, 41749874f6eSJoseph Koshy (void *) ev.pl_u.pl_mi.pl_start, 41849874f6eSJoseph Koshy ev.pl_u.pl_mi.pl_pathname); 41949874f6eSJoseph Koshy break; 42049874f6eSJoseph Koshy case PMCLOG_TYPE_MAP_OUT: 4210b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("map-out","%d %p %p", 42249874f6eSJoseph Koshy ev.pl_u.pl_mo.pl_pid, 42349874f6eSJoseph Koshy (void *) ev.pl_u.pl_mo.pl_start, 42449874f6eSJoseph Koshy (void *) ev.pl_u.pl_mo.pl_end); 42515139246SJoseph Koshy break; 42615139246SJoseph Koshy case PMCLOG_TYPE_PMCALLOCATE: 4270b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("allocate","0x%x \"%s\" 0x%x", 42815139246SJoseph Koshy ev.pl_u.pl_a.pl_pmcid, 42915139246SJoseph Koshy ev.pl_u.pl_a.pl_evname, 43015139246SJoseph Koshy ev.pl_u.pl_a.pl_flags); 43115139246SJoseph Koshy break; 432f5f9340bSFabien Thomas case PMCLOG_TYPE_PMCALLOCATEDYN: 433f5f9340bSFabien Thomas PMCSTAT_PRINT_ENTRY("allocatedyn","0x%x \"%s\" 0x%x", 434f5f9340bSFabien Thomas ev.pl_u.pl_ad.pl_pmcid, 435f5f9340bSFabien Thomas ev.pl_u.pl_ad.pl_evname, 436f5f9340bSFabien Thomas ev.pl_u.pl_ad.pl_flags); 437f5f9340bSFabien Thomas break; 43815139246SJoseph Koshy case PMCLOG_TYPE_PMCATTACH: 4390b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("attach","0x%x %d \"%s\"", 44015139246SJoseph Koshy ev.pl_u.pl_t.pl_pmcid, 44115139246SJoseph Koshy ev.pl_u.pl_t.pl_pid, 44215139246SJoseph Koshy ev.pl_u.pl_t.pl_pathname); 44315139246SJoseph Koshy break; 44415139246SJoseph Koshy case PMCLOG_TYPE_PMCDETACH: 4450b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("detach","0x%x %d", 44615139246SJoseph Koshy ev.pl_u.pl_d.pl_pmcid, 44715139246SJoseph Koshy ev.pl_u.pl_d.pl_pid); 44815139246SJoseph Koshy break; 44915139246SJoseph Koshy case PMCLOG_TYPE_PROCCSW: 4500b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("cswval","0x%x %d %jd", 45115139246SJoseph Koshy ev.pl_u.pl_c.pl_pmcid, 45215139246SJoseph Koshy ev.pl_u.pl_c.pl_pid, 45315139246SJoseph Koshy ev.pl_u.pl_c.pl_value); 45415139246SJoseph Koshy break; 45515139246SJoseph Koshy case PMCLOG_TYPE_PROCEXEC: 4560b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("exec","0x%x %d %p \"%s\"", 45715139246SJoseph Koshy ev.pl_u.pl_x.pl_pmcid, 45815139246SJoseph Koshy ev.pl_u.pl_x.pl_pid, 45915139246SJoseph Koshy (void *) ev.pl_u.pl_x.pl_entryaddr, 46015139246SJoseph Koshy ev.pl_u.pl_x.pl_pathname); 46115139246SJoseph Koshy break; 46215139246SJoseph Koshy case PMCLOG_TYPE_PROCEXIT: 4630b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("exitval","0x%x %d %jd", 46415139246SJoseph Koshy ev.pl_u.pl_e.pl_pmcid, 46515139246SJoseph Koshy ev.pl_u.pl_e.pl_pid, 46615139246SJoseph Koshy ev.pl_u.pl_e.pl_value); 46715139246SJoseph Koshy break; 46815139246SJoseph Koshy case PMCLOG_TYPE_PROCFORK: 4690b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("fork","%d %d", 47015139246SJoseph Koshy ev.pl_u.pl_f.pl_oldpid, 47115139246SJoseph Koshy ev.pl_u.pl_f.pl_newpid); 47215139246SJoseph Koshy break; 47315139246SJoseph Koshy case PMCLOG_TYPE_USERDATA: 4740b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("userdata","0x%x", 47515139246SJoseph Koshy ev.pl_u.pl_u.pl_userdata); 47615139246SJoseph Koshy break; 47715139246SJoseph Koshy case PMCLOG_TYPE_SYSEXIT: 4780b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("exit","%d", 47915139246SJoseph Koshy ev.pl_u.pl_se.pl_pid); 48015139246SJoseph Koshy break; 48115139246SJoseph Koshy default: 4820b86b1bbSFabien Thomas fprintf(args.pa_printfile, "unknown event (type %d).\n", 48315139246SJoseph Koshy ev.pl_type); 48415139246SJoseph Koshy } 48515139246SJoseph Koshy } 48615139246SJoseph Koshy 48715139246SJoseph Koshy if (ev.pl_state == PMCLOG_EOF) 48849874f6eSJoseph Koshy return (PMCSTAT_FINISHED); 48915139246SJoseph Koshy else if (ev.pl_state == PMCLOG_REQUIRE_DATA) 49049874f6eSJoseph Koshy return (PMCSTAT_RUNNING); 49115139246SJoseph Koshy 49237d6f8a9SDavid E. O'Brien errx(EX_DATAERR, 49337d6f8a9SDavid E. O'Brien "ERROR: event parsing failed (record %jd, offset 0x%jx).", 49415139246SJoseph Koshy (uintmax_t) ev.pl_count + 1, ev.pl_offset); 49515139246SJoseph Koshy /*NOTREACHED*/ 49615139246SJoseph Koshy } 49715139246SJoseph Koshy 49815139246SJoseph Koshy /* 49949874f6eSJoseph Koshy * Public Interfaces. 50049874f6eSJoseph Koshy */ 50149874f6eSJoseph Koshy 50249874f6eSJoseph Koshy /* 50315139246SJoseph Koshy * Process a log file in offline analysis mode. 50415139246SJoseph Koshy */ 50515139246SJoseph Koshy 506dc1d9d2eSJoseph Koshy int 5070b86b1bbSFabien Thomas pmcstat_process_log(void) 50815139246SJoseph Koshy { 50915139246SJoseph Koshy 51015139246SJoseph Koshy /* 511b6010f9eSJoseph Koshy * If analysis has not been asked for, just print the log to 512b6010f9eSJoseph Koshy * the current output file. 51315139246SJoseph Koshy */ 5140b86b1bbSFabien Thomas if (args.pa_flags & FLAG_DO_PRINT) 5150b86b1bbSFabien Thomas return (pmcstat_print_log()); 51615139246SJoseph Koshy else 517d27927f7SRuslan Bukin return (pmcstat_analyze_log(&args, plugins, &pmcstat_stats, pmcstat_kernproc, 518d27927f7SRuslan Bukin pmcstat_mergepmc, &pmcstat_npmcs, &ps_samples_period)); 5190b86b1bbSFabien Thomas } 5200b86b1bbSFabien Thomas 5210b86b1bbSFabien Thomas /* 5220b86b1bbSFabien Thomas * Refresh top display. 5230b86b1bbSFabien Thomas */ 5240b86b1bbSFabien Thomas 5250b86b1bbSFabien Thomas static void 5260b86b1bbSFabien Thomas pmcstat_refresh_top(void) 5270b86b1bbSFabien Thomas { 528c86819ecSFabien Thomas int v_attrs; 529c86819ecSFabien Thomas float v; 5300b86b1bbSFabien Thomas char pmcname[40]; 531c86819ecSFabien Thomas struct pmcstat_pmcrecord *pmcpr; 5320b86b1bbSFabien Thomas 5330b86b1bbSFabien Thomas /* If in pause mode do not refresh display. */ 5340b86b1bbSFabien Thomas if (pmcstat_pause) 5350b86b1bbSFabien Thomas return; 5360b86b1bbSFabien Thomas 5379ba84a88SFabien Thomas /* Wait until PMC pop in the log. */ 538c86819ecSFabien Thomas pmcpr = pmcstat_pmcindex_to_pmcr(pmcstat_pmcinfilter); 539c86819ecSFabien Thomas if (pmcpr == NULL) 5409ba84a88SFabien Thomas return; 5419ba84a88SFabien Thomas 5420b86b1bbSFabien Thomas /* Format PMC name. */ 5430b86b1bbSFabien Thomas if (pmcstat_mergepmc) 544c86819ecSFabien Thomas snprintf(pmcname, sizeof(pmcname), "[%s]", 545c86819ecSFabien Thomas pmcstat_string_unintern(pmcpr->pr_pmcname)); 5460b86b1bbSFabien Thomas else 5470b86b1bbSFabien Thomas snprintf(pmcname, sizeof(pmcname), "%s.%d", 548c86819ecSFabien Thomas pmcstat_string_unintern(pmcpr->pr_pmcname), 549c86819ecSFabien Thomas pmcstat_pmcinfilter); 550c86819ecSFabien Thomas 551c86819ecSFabien Thomas /* Format samples count. */ 552ac708fddSFabien Thomas if (ps_samples_period > 0) 553ac708fddSFabien Thomas v = (pmcpr->pr_samples * 100.0) / ps_samples_period; 554c86819ecSFabien Thomas else 555c86819ecSFabien Thomas v = 0.; 556c86819ecSFabien Thomas v_attrs = PMCSTAT_ATTRPERCENT(v); 5570b86b1bbSFabien Thomas 5580b86b1bbSFabien Thomas PMCSTAT_PRINTBEGIN(); 559c86819ecSFabien Thomas PMCSTAT_PRINTW("PMC: %s Samples: %u ", 5600b86b1bbSFabien Thomas pmcname, 561c86819ecSFabien Thomas pmcpr->pr_samples); 562c86819ecSFabien Thomas PMCSTAT_ATTRON(v_attrs); 563c86819ecSFabien Thomas PMCSTAT_PRINTW("(%.1f%%) ", v); 564c86819ecSFabien Thomas PMCSTAT_ATTROFF(v_attrs); 565c86819ecSFabien Thomas PMCSTAT_PRINTW(", %u unresolved\n\n", 566c86819ecSFabien Thomas pmcpr->pr_dubious_frames); 5670b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_topdisplay != NULL) 5680b86b1bbSFabien Thomas plugins[args.pa_plugin].pl_topdisplay(); 5690b86b1bbSFabien Thomas PMCSTAT_PRINTEND(); 5700b86b1bbSFabien Thomas } 5710b86b1bbSFabien Thomas 5720b86b1bbSFabien Thomas /* 5730b86b1bbSFabien Thomas * Find the next pmc index to display. 5740b86b1bbSFabien Thomas */ 5750b86b1bbSFabien Thomas 5760b86b1bbSFabien Thomas static void 5770b86b1bbSFabien Thomas pmcstat_changefilter(void) 5780b86b1bbSFabien Thomas { 5790b86b1bbSFabien Thomas int pmcin; 5800b86b1bbSFabien Thomas struct pmcstat_pmcrecord *pmcr; 5810b86b1bbSFabien Thomas 5820b86b1bbSFabien Thomas /* 5830b86b1bbSFabien Thomas * Find the next merge target. 5840b86b1bbSFabien Thomas */ 5850b86b1bbSFabien Thomas if (pmcstat_mergepmc) { 5860b86b1bbSFabien Thomas pmcin = pmcstat_pmcinfilter; 5870b86b1bbSFabien Thomas 5880b86b1bbSFabien Thomas do { 5890b86b1bbSFabien Thomas pmcr = pmcstat_pmcindex_to_pmcr(pmcstat_pmcinfilter); 590ac708fddSFabien Thomas if (pmcr == NULL || pmcr == pmcr->pr_merge) 5910b86b1bbSFabien Thomas break; 5920b86b1bbSFabien Thomas 5930b86b1bbSFabien Thomas pmcstat_pmcinfilter++; 5940b86b1bbSFabien Thomas if (pmcstat_pmcinfilter >= pmcstat_npmcs) 5950b86b1bbSFabien Thomas pmcstat_pmcinfilter = 0; 5960b86b1bbSFabien Thomas 5970b86b1bbSFabien Thomas } while (pmcstat_pmcinfilter != pmcin); 5980b86b1bbSFabien Thomas } 5990b86b1bbSFabien Thomas } 6000b86b1bbSFabien Thomas 6010b86b1bbSFabien Thomas /* 6020b86b1bbSFabien Thomas * Top mode keypress. 6030b86b1bbSFabien Thomas */ 6040b86b1bbSFabien Thomas 6050b86b1bbSFabien Thomas int 6060b86b1bbSFabien Thomas pmcstat_keypress_log(void) 6070b86b1bbSFabien Thomas { 6080b86b1bbSFabien Thomas int c, ret = 0; 6090b86b1bbSFabien Thomas WINDOW *w; 6100b86b1bbSFabien Thomas 6110b86b1bbSFabien Thomas w = newwin(1, 0, 1, 0); 6120b86b1bbSFabien Thomas c = wgetch(w); 6130b86b1bbSFabien Thomas wprintw(w, "Key: %c => ", c); 6140b86b1bbSFabien Thomas switch (c) { 615*94e9ef85SMateusz Guzik case 'A': 616*94e9ef85SMateusz Guzik if (args.pa_flags & FLAG_SKIP_TOP_FN_RES) 617*94e9ef85SMateusz Guzik args.pa_flags &= ~FLAG_SKIP_TOP_FN_RES; 618*94e9ef85SMateusz Guzik else 619*94e9ef85SMateusz Guzik args.pa_flags |= FLAG_SKIP_TOP_FN_RES; 620*94e9ef85SMateusz Guzik break; 6210b86b1bbSFabien Thomas case 'c': 6220b86b1bbSFabien Thomas wprintw(w, "enter mode 'd' or 'a' => "); 6230b86b1bbSFabien Thomas c = wgetch(w); 6240b86b1bbSFabien Thomas if (c == 'd') { 6250b86b1bbSFabien Thomas args.pa_topmode = PMCSTAT_TOP_DELTA; 6260b86b1bbSFabien Thomas wprintw(w, "switching to delta mode"); 6270b86b1bbSFabien Thomas } else { 6280b86b1bbSFabien Thomas args.pa_topmode = PMCSTAT_TOP_ACCUM; 6290b86b1bbSFabien Thomas wprintw(w, "switching to accumulation mode"); 6300b86b1bbSFabien Thomas } 6310b86b1bbSFabien Thomas break; 632*94e9ef85SMateusz Guzik case 'I': 633*94e9ef85SMateusz Guzik if (args.pa_flags & FLAG_SHOW_OFFSET) 634*94e9ef85SMateusz Guzik args.pa_flags &= ~FLAG_SHOW_OFFSET; 635*94e9ef85SMateusz Guzik else 636*94e9ef85SMateusz Guzik args.pa_flags |= FLAG_SHOW_OFFSET; 637*94e9ef85SMateusz Guzik break; 6380b86b1bbSFabien Thomas case 'm': 6390b86b1bbSFabien Thomas pmcstat_mergepmc = !pmcstat_mergepmc; 6400b86b1bbSFabien Thomas /* 6410b86b1bbSFabien Thomas * Changing merge state require data reset. 6420b86b1bbSFabien Thomas */ 6430b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_shutdown != NULL) 6440b86b1bbSFabien Thomas plugins[args.pa_plugin].pl_shutdown(NULL); 645ac708fddSFabien Thomas pmcstat_stats_reset(0); 6460b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_init != NULL) 6470b86b1bbSFabien Thomas plugins[args.pa_plugin].pl_init(); 6480b86b1bbSFabien Thomas 6490b86b1bbSFabien Thomas /* Update filter to be on a merge target. */ 6500b86b1bbSFabien Thomas pmcstat_changefilter(); 6510b86b1bbSFabien Thomas wprintw(w, "merge PMC %s", pmcstat_mergepmc ? "on" : "off"); 6520b86b1bbSFabien Thomas break; 6530b86b1bbSFabien Thomas case 'n': 6540b86b1bbSFabien Thomas /* Close current plugin. */ 6550b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_shutdown != NULL) 6560b86b1bbSFabien Thomas plugins[args.pa_plugin].pl_shutdown(NULL); 6570b86b1bbSFabien Thomas 6580b86b1bbSFabien Thomas /* Find next top display available. */ 6590b86b1bbSFabien Thomas do { 6600b86b1bbSFabien Thomas args.pa_plugin++; 6610b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_name == NULL) 6620b86b1bbSFabien Thomas args.pa_plugin = 0; 6630b86b1bbSFabien Thomas } while (plugins[args.pa_plugin].pl_topdisplay == NULL); 6640b86b1bbSFabien Thomas 6650b86b1bbSFabien Thomas /* Open new plugin. */ 666ac708fddSFabien Thomas pmcstat_stats_reset(0); 6670b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_init != NULL) 6680b86b1bbSFabien Thomas plugins[args.pa_plugin].pl_init(); 6690b86b1bbSFabien Thomas wprintw(w, "switching to plugin %s", 6700b86b1bbSFabien Thomas plugins[args.pa_plugin].pl_name); 6710b86b1bbSFabien Thomas break; 6720b86b1bbSFabien Thomas case 'p': 6730b86b1bbSFabien Thomas pmcstat_pmcinfilter++; 6740b86b1bbSFabien Thomas if (pmcstat_pmcinfilter >= pmcstat_npmcs) 6750b86b1bbSFabien Thomas pmcstat_pmcinfilter = 0; 6760b86b1bbSFabien Thomas pmcstat_changefilter(); 6770b86b1bbSFabien Thomas wprintw(w, "switching to PMC %s.%d", 6780b86b1bbSFabien Thomas pmcstat_pmcindex_to_name(pmcstat_pmcinfilter), 6790b86b1bbSFabien Thomas pmcstat_pmcinfilter); 6800b86b1bbSFabien Thomas break; 6810b86b1bbSFabien Thomas case ' ': 6820b86b1bbSFabien Thomas pmcstat_pause = !pmcstat_pause; 6830b86b1bbSFabien Thomas if (pmcstat_pause) 6840b86b1bbSFabien Thomas wprintw(w, "pause => press space again to continue"); 6850b86b1bbSFabien Thomas break; 6860b86b1bbSFabien Thomas case 'q': 6870b86b1bbSFabien Thomas wprintw(w, "exiting..."); 6880b86b1bbSFabien Thomas ret = 1; 6895c15d3c8SFabien Thomas break; 6900b86b1bbSFabien Thomas default: 6910b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_topkeypress != NULL) 692d27927f7SRuslan Bukin if (plugins[args.pa_plugin].pl_topkeypress(c, (void *)w)) 6930b86b1bbSFabien Thomas ret = 1; 6940b86b1bbSFabien Thomas } 6950b86b1bbSFabien Thomas 6960b86b1bbSFabien Thomas wrefresh(w); 6970b86b1bbSFabien Thomas delwin(w); 6980b86b1bbSFabien Thomas return ret; 6990b86b1bbSFabien Thomas } 7000b86b1bbSFabien Thomas 7010b86b1bbSFabien Thomas 7020b86b1bbSFabien Thomas /* 7030b86b1bbSFabien Thomas * Top mode display. 7040b86b1bbSFabien Thomas */ 7050b86b1bbSFabien Thomas 7060b86b1bbSFabien Thomas void 7070b86b1bbSFabien Thomas pmcstat_display_log(void) 7080b86b1bbSFabien Thomas { 7090b86b1bbSFabien Thomas 7100b86b1bbSFabien Thomas pmcstat_refresh_top(); 7110b86b1bbSFabien Thomas 7120b86b1bbSFabien Thomas /* Reset everythings if delta mode. */ 7130b86b1bbSFabien Thomas if (args.pa_topmode == PMCSTAT_TOP_DELTA) { 7140b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_shutdown != NULL) 7150b86b1bbSFabien Thomas plugins[args.pa_plugin].pl_shutdown(NULL); 716ac708fddSFabien Thomas pmcstat_stats_reset(0); 7170b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_init != NULL) 7180b86b1bbSFabien Thomas plugins[args.pa_plugin].pl_init(); 7190b86b1bbSFabien Thomas } 7200b86b1bbSFabien Thomas } 7210b86b1bbSFabien Thomas 7220b86b1bbSFabien Thomas /* 7230b86b1bbSFabien Thomas * Configure a plugins. 7240b86b1bbSFabien Thomas */ 7250b86b1bbSFabien Thomas 7260b86b1bbSFabien Thomas void 7270b86b1bbSFabien Thomas pmcstat_pluginconfigure_log(char *opt) 7280b86b1bbSFabien Thomas { 7290b86b1bbSFabien Thomas 7300b86b1bbSFabien Thomas if (strncmp(opt, "threshold=", 10) == 0) { 7310b86b1bbSFabien Thomas pmcstat_threshold = atof(opt+10); 7320b86b1bbSFabien Thomas } else { 7330b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_configure != NULL) { 7340b86b1bbSFabien Thomas if (!plugins[args.pa_plugin].pl_configure(opt)) 7350b86b1bbSFabien Thomas err(EX_USAGE, 7360b86b1bbSFabien Thomas "ERROR: unknown option <%s>.", opt); 7370b86b1bbSFabien Thomas } 7380b86b1bbSFabien Thomas } 73915139246SJoseph Koshy } 74015139246SJoseph Koshy 741d27927f7SRuslan Bukin void 742d27927f7SRuslan Bukin pmcstat_log_shutdown_logging(void) 743d27927f7SRuslan Bukin { 744d27927f7SRuslan Bukin 745d27927f7SRuslan Bukin pmcstat_shutdown_logging(&args, plugins, &pmcstat_stats); 746d27927f7SRuslan Bukin } 74749874f6eSJoseph Koshy 74815139246SJoseph Koshy void 749d27927f7SRuslan Bukin pmcstat_log_initialize_logging(void) 75015139246SJoseph Koshy { 75149874f6eSJoseph Koshy 752d27927f7SRuslan Bukin pmcstat_initialize_logging(&pmcstat_kernproc, 753d27927f7SRuslan Bukin &args, plugins, &pmcstat_npmcs, &pmcstat_mergepmc); 75415139246SJoseph Koshy } 755