115139246SJoseph Koshy /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
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/param.h>
3915139246SJoseph Koshy #include <sys/endian.h>
40ea056888SAttilio Rao #include <sys/cpuset.h>
4115139246SJoseph Koshy #include <sys/gmon.h>
4215139246SJoseph Koshy #include <sys/imgact_aout.h>
4315139246SJoseph Koshy #include <sys/imgact_elf.h>
4415139246SJoseph Koshy #include <sys/mman.h>
4515139246SJoseph Koshy #include <sys/pmc.h>
4615139246SJoseph Koshy #include <sys/queue.h>
47302cbb90SJoseph Koshy #include <sys/socket.h>
4815139246SJoseph Koshy #include <sys/stat.h>
4915139246SJoseph Koshy #include <sys/wait.h>
5015139246SJoseph Koshy
5115139246SJoseph Koshy #include <netinet/in.h>
5215139246SJoseph Koshy
5315139246SJoseph Koshy #include <assert.h>
540b86b1bbSFabien Thomas #include <curses.h>
5515139246SJoseph Koshy #include <err.h>
56302cbb90SJoseph Koshy #include <errno.h>
5715139246SJoseph Koshy #include <fcntl.h>
58b6010f9eSJoseph Koshy #include <gelf.h>
5915139246SJoseph Koshy #include <libgen.h>
6015139246SJoseph Koshy #include <limits.h>
61302cbb90SJoseph Koshy #include <netdb.h>
6215139246SJoseph Koshy #include <pmc.h>
6315139246SJoseph Koshy #include <pmclog.h>
6415139246SJoseph Koshy #include <sysexits.h>
6515139246SJoseph Koshy #include <stdint.h>
6615139246SJoseph Koshy #include <stdio.h>
6715139246SJoseph Koshy #include <stdlib.h>
6815139246SJoseph Koshy #include <string.h>
6915139246SJoseph Koshy #include <unistd.h>
7015139246SJoseph Koshy
7115139246SJoseph Koshy #include "pmcstat.h"
720b86b1bbSFabien Thomas #include "pmcstat_log.h"
730b86b1bbSFabien Thomas #include "pmcstat_top.h"
7415139246SJoseph Koshy
7515139246SJoseph Koshy /*
7649874f6eSJoseph Koshy * PUBLIC INTERFACES
7749874f6eSJoseph Koshy *
7849874f6eSJoseph Koshy * pmcstat_initialize_logging() initialize this module, called first
7949874f6eSJoseph Koshy * pmcstat_shutdown_logging() orderly shutdown, called last
8049874f6eSJoseph Koshy * pmcstat_open_log() open an eventlog for processing
8149874f6eSJoseph Koshy * pmcstat_process_log() print/convert an event log
820b86b1bbSFabien Thomas * pmcstat_display_log() top mode display for the log
8349874f6eSJoseph Koshy * pmcstat_close_log() finish processing an event log
8449874f6eSJoseph Koshy *
85b6010f9eSJoseph Koshy * IMPLEMENTATION NOTES
8649874f6eSJoseph Koshy *
87b6010f9eSJoseph Koshy * We correlate each 'callchain' or 'sample' entry seen in the event
88b6010f9eSJoseph Koshy * log back to an executable object in the system. Executable objects
89b6010f9eSJoseph Koshy * include:
9049874f6eSJoseph Koshy * - program executables,
9149874f6eSJoseph Koshy * - shared libraries loaded by the runtime loader,
9249874f6eSJoseph Koshy * - dlopen()'ed objects loaded by the program,
9349874f6eSJoseph Koshy * - the runtime loader itself,
9449874f6eSJoseph Koshy * - the kernel and kernel modules.
9549874f6eSJoseph Koshy *
9649874f6eSJoseph Koshy * Each process that we know about is treated as a set of regions that
9749874f6eSJoseph Koshy * map to executable objects. Processes are described by
9849874f6eSJoseph Koshy * 'pmcstat_process' structures. Executable objects are tracked by
9949874f6eSJoseph Koshy * 'pmcstat_image' structures. The kernel and kernel modules are
10049874f6eSJoseph Koshy * common to all processes (they reside at the same virtual addresses
10149874f6eSJoseph Koshy * for all processes). Individual processes can have their text
10249874f6eSJoseph Koshy * segments and shared libraries loaded at process-specific locations.
10349874f6eSJoseph Koshy *
10449874f6eSJoseph Koshy * A given executable object can be in use by multiple processes
10549874f6eSJoseph Koshy * (e.g., libc.so) and loaded at a different address in each.
10649874f6eSJoseph Koshy * pmcstat_pcmap structures track per-image mappings.
10749874f6eSJoseph Koshy *
10849874f6eSJoseph Koshy * The sample log could have samples from multiple PMCs; we
10949874f6eSJoseph Koshy * generate one 'gmon.out' profile per PMC.
110b6010f9eSJoseph Koshy *
111b6010f9eSJoseph Koshy * IMPLEMENTATION OF GMON OUTPUT
112b6010f9eSJoseph Koshy *
113b6010f9eSJoseph Koshy * Each executable object gets one 'gmon.out' profile, per PMC in
114b6010f9eSJoseph Koshy * use. Creation of 'gmon.out' profiles is done lazily. The
115b6010f9eSJoseph Koshy * 'gmon.out' profiles generated for a given sampling PMC are
116b6010f9eSJoseph Koshy * aggregates of all the samples for that particular executable
117b6010f9eSJoseph Koshy * object.
118b6010f9eSJoseph Koshy *
119b6010f9eSJoseph Koshy * IMPLEMENTATION OF SYSTEM-WIDE CALLGRAPH OUTPUT
120b6010f9eSJoseph Koshy *
121b6010f9eSJoseph Koshy * Each active pmcid has its own callgraph structure, described by a
122b6010f9eSJoseph Koshy * 'struct pmcstat_callgraph'. Given a process id and a list of pc
123b6010f9eSJoseph Koshy * values, we map each pc value to a tuple (image, symbol), where
124b6010f9eSJoseph Koshy * 'image' denotes an executable object and 'symbol' is the closest
125b6010f9eSJoseph Koshy * symbol that precedes the pc value. Each pc value in the list is
126b6010f9eSJoseph Koshy * also given a 'rank' that reflects its depth in the call stack.
12715139246SJoseph Koshy */
12815139246SJoseph Koshy
1290b86b1bbSFabien Thomas struct pmcstat_pmcs pmcstat_pmcs = LIST_HEAD_INITIALIZER(pmcstat_pmcs);
13015139246SJoseph Koshy
13149874f6eSJoseph Koshy /*
13249874f6eSJoseph Koshy * All image descriptors are kept in a hash table.
13349874f6eSJoseph Koshy */
1340b86b1bbSFabien Thomas struct pmcstat_image_hash_list pmcstat_image_hash[PMCSTAT_NHASH];
13515139246SJoseph Koshy
13649874f6eSJoseph Koshy /*
13749874f6eSJoseph Koshy * All process descriptors are kept in a hash table.
13849874f6eSJoseph Koshy */
1390b86b1bbSFabien Thomas struct pmcstat_process_hash_list pmcstat_process_hash[PMCSTAT_NHASH];
14015139246SJoseph Koshy
1410b86b1bbSFabien Thomas struct pmcstat_stats pmcstat_stats; /* statistics */
142bf70beceSEd Schouten static int ps_samples_period; /* samples count between top refresh. */
14315139246SJoseph Koshy
1440b86b1bbSFabien Thomas struct pmcstat_process *pmcstat_kernproc; /* kernel 'process' */
145b6010f9eSJoseph Koshy
1460b86b1bbSFabien Thomas #include "pmcpl_gprof.h"
1470b86b1bbSFabien Thomas #include "pmcpl_callgraph.h"
1480b86b1bbSFabien Thomas #include "pmcpl_annotate.h"
14985ec49f3SAdrian Chadd #include "pmcpl_annotate_cg.h"
1500b86b1bbSFabien Thomas #include "pmcpl_calltree.h"
1510b86b1bbSFabien Thomas
152d27927f7SRuslan Bukin static struct pmc_plugins plugins[] = {
1530b86b1bbSFabien Thomas {
1540b86b1bbSFabien Thomas .pl_name = "none",
1550b86b1bbSFabien Thomas },
1560b86b1bbSFabien Thomas {
1570b86b1bbSFabien Thomas .pl_name = "callgraph",
1580b86b1bbSFabien Thomas .pl_init = pmcpl_cg_init,
1590b86b1bbSFabien Thomas .pl_shutdown = pmcpl_cg_shutdown,
1600b86b1bbSFabien Thomas .pl_process = pmcpl_cg_process,
1610b86b1bbSFabien Thomas .pl_topkeypress = pmcpl_cg_topkeypress,
1620b86b1bbSFabien Thomas .pl_topdisplay = pmcpl_cg_topdisplay
1630b86b1bbSFabien Thomas },
1640b86b1bbSFabien Thomas {
1650b86b1bbSFabien Thomas .pl_name = "gprof",
1660b86b1bbSFabien Thomas .pl_shutdown = pmcpl_gmon_shutdown,
1670b86b1bbSFabien Thomas .pl_process = pmcpl_gmon_process,
1680b86b1bbSFabien Thomas .pl_initimage = pmcpl_gmon_initimage,
1690b86b1bbSFabien Thomas .pl_shutdownimage = pmcpl_gmon_shutdownimage,
1700b86b1bbSFabien Thomas .pl_newpmc = pmcpl_gmon_newpmc
1710b86b1bbSFabien Thomas },
1720b86b1bbSFabien Thomas {
1730b86b1bbSFabien Thomas .pl_name = "annotate",
1740b86b1bbSFabien Thomas .pl_process = pmcpl_annotate_process
1750b86b1bbSFabien Thomas },
1760b86b1bbSFabien Thomas {
1770b86b1bbSFabien Thomas .pl_name = "calltree",
1780b86b1bbSFabien Thomas .pl_configure = pmcpl_ct_configure,
1790b86b1bbSFabien Thomas .pl_init = pmcpl_ct_init,
1800b86b1bbSFabien Thomas .pl_shutdown = pmcpl_ct_shutdown,
1810b86b1bbSFabien Thomas .pl_process = pmcpl_ct_process,
1820b86b1bbSFabien Thomas .pl_topkeypress = pmcpl_ct_topkeypress,
1830b86b1bbSFabien Thomas .pl_topdisplay = pmcpl_ct_topdisplay
1840b86b1bbSFabien Thomas },
1850b86b1bbSFabien Thomas {
18685ec49f3SAdrian Chadd .pl_name = "annotate_cg",
18785ec49f3SAdrian Chadd .pl_process = pmcpl_annotate_cg_process
18885ec49f3SAdrian Chadd },
18985ec49f3SAdrian Chadd
19085ec49f3SAdrian Chadd {
1910b86b1bbSFabien Thomas .pl_name = NULL
1920b86b1bbSFabien Thomas }
193b6010f9eSJoseph Koshy };
194b6010f9eSJoseph Koshy
195bf70beceSEd Schouten static int pmcstat_mergepmc;
196b6010f9eSJoseph Koshy
1970b86b1bbSFabien Thomas int pmcstat_pmcinfilter = 0; /* PMC filter for top mode. */
1980b86b1bbSFabien Thomas float pmcstat_threshold = 0.5; /* Cost filter for top mode. */
199b6010f9eSJoseph Koshy
20015139246SJoseph Koshy /*
20115139246SJoseph Koshy * Prototypes
20215139246SJoseph Koshy */
20315139246SJoseph Koshy
204ac708fddSFabien Thomas static void pmcstat_stats_reset(int _reset_global);
20515139246SJoseph Koshy
20615139246SJoseph Koshy /*
2070b86b1bbSFabien Thomas * PMC count.
2080b86b1bbSFabien Thomas */
2090b86b1bbSFabien Thomas int pmcstat_npmcs;
2100b86b1bbSFabien Thomas
2110b86b1bbSFabien Thomas /*
2120b86b1bbSFabien Thomas * PMC Top mode pause state.
2130b86b1bbSFabien Thomas */
214bf70beceSEd Schouten static int pmcstat_pause;
2150b86b1bbSFabien Thomas
216c86819ecSFabien Thomas static void
pmcstat_stats_reset(int reset_global)217ac708fddSFabien Thomas pmcstat_stats_reset(int reset_global)
218c86819ecSFabien Thomas {
219c86819ecSFabien Thomas struct pmcstat_pmcrecord *pr;
220c86819ecSFabien Thomas
221c86819ecSFabien Thomas /* Flush PMCs stats. */
222c86819ecSFabien Thomas LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) {
223c86819ecSFabien Thomas pr->pr_samples = 0;
224c86819ecSFabien Thomas pr->pr_dubious_frames = 0;
225c86819ecSFabien Thomas }
226ac708fddSFabien Thomas ps_samples_period = 0;
227c86819ecSFabien Thomas
228c86819ecSFabien Thomas /* Flush global stats. */
229ac708fddSFabien Thomas if (reset_global)
230c86819ecSFabien Thomas bzero(&pmcstat_stats, sizeof(struct pmcstat_stats));
231c86819ecSFabien Thomas }
232c86819ecSFabien Thomas
2330b86b1bbSFabien Thomas /*
2340b86b1bbSFabien Thomas * Resolve file name and line number for the given address.
2350b86b1bbSFabien Thomas */
2360b86b1bbSFabien Thomas int
pmcstat_image_addr2line(struct pmcstat_image * image,uintfptr_t addr,char * sourcefile,size_t sourcefile_len,unsigned * sourceline,char * funcname,size_t funcname_len)2370b86b1bbSFabien Thomas pmcstat_image_addr2line(struct pmcstat_image *image, uintfptr_t addr,
2380b86b1bbSFabien Thomas char *sourcefile, size_t sourcefile_len, unsigned *sourceline,
2390b86b1bbSFabien Thomas char *funcname, size_t funcname_len)
2400b86b1bbSFabien Thomas {
2410b86b1bbSFabien Thomas static int addr2line_warn = 0;
2420b86b1bbSFabien Thomas
2430b86b1bbSFabien Thomas char *sep, cmdline[PATH_MAX], imagepath[PATH_MAX];
24466ca84a7SFabien Thomas unsigned l;
2450b86b1bbSFabien Thomas int fd;
2460b86b1bbSFabien Thomas
2470b86b1bbSFabien Thomas if (image->pi_addr2line == NULL) {
24866ca84a7SFabien Thomas /* Try default debug file location. */
24966ca84a7SFabien Thomas snprintf(imagepath, sizeof(imagepath),
25066ca84a7SFabien Thomas "/usr/lib/debug/%s%s.debug",
25166ca84a7SFabien Thomas args.pa_fsroot,
25266ca84a7SFabien Thomas pmcstat_string_unintern(image->pi_fullpath));
25366ca84a7SFabien Thomas fd = open(imagepath, O_RDONLY);
25466ca84a7SFabien Thomas if (fd < 0) {
25566ca84a7SFabien Thomas /* Old kernel symbol path. */
256ac708fddSFabien Thomas snprintf(imagepath, sizeof(imagepath), "%s%s.symbols",
257ac708fddSFabien Thomas args.pa_fsroot,
2580b86b1bbSFabien Thomas pmcstat_string_unintern(image->pi_fullpath));
2590b86b1bbSFabien Thomas fd = open(imagepath, O_RDONLY);
2600b86b1bbSFabien Thomas if (fd < 0) {
261ac708fddSFabien Thomas snprintf(imagepath, sizeof(imagepath), "%s%s",
262ac708fddSFabien Thomas args.pa_fsroot,
26366ca84a7SFabien Thomas pmcstat_string_unintern(
26466ca84a7SFabien Thomas image->pi_fullpath));
26566ca84a7SFabien Thomas }
26666ca84a7SFabien Thomas }
26766ca84a7SFabien Thomas if (fd >= 0)
2680b86b1bbSFabien Thomas close(fd);
269fa18b0b2SFabien Thomas /*
270fa18b0b2SFabien Thomas * New addr2line support recursive inline function with -i
271fa18b0b2SFabien Thomas * but the format does not add a marker when no more entries
272fa18b0b2SFabien Thomas * are available.
273fa18b0b2SFabien Thomas */
2740b86b1bbSFabien Thomas snprintf(cmdline, sizeof(cmdline), "addr2line -Cfe \"%s\"",
2750b86b1bbSFabien Thomas imagepath);
2760b86b1bbSFabien Thomas image->pi_addr2line = popen(cmdline, "r+");
2770b86b1bbSFabien Thomas if (image->pi_addr2line == NULL) {
2780b86b1bbSFabien Thomas if (!addr2line_warn) {
2790b86b1bbSFabien Thomas addr2line_warn = 1;
28037d6f8a9SDavid E. O'Brien warnx(
28137d6f8a9SDavid E. O'Brien "WARNING: addr2line is needed for source code information."
28237d6f8a9SDavid E. O'Brien );
2830b86b1bbSFabien Thomas }
2840b86b1bbSFabien Thomas return (0);
2850b86b1bbSFabien Thomas }
2860b86b1bbSFabien Thomas }
2870b86b1bbSFabien Thomas
2880b86b1bbSFabien Thomas if (feof(image->pi_addr2line) || ferror(image->pi_addr2line)) {
2890b86b1bbSFabien Thomas warnx("WARNING: addr2line pipe error");
2900b86b1bbSFabien Thomas pclose(image->pi_addr2line);
2910b86b1bbSFabien Thomas image->pi_addr2line = NULL;
2920b86b1bbSFabien Thomas return (0);
2930b86b1bbSFabien Thomas }
2940b86b1bbSFabien Thomas
2950b86b1bbSFabien Thomas fprintf(image->pi_addr2line, "%p\n", (void *)addr);
2960b86b1bbSFabien Thomas
2970b86b1bbSFabien Thomas if (fgets(funcname, funcname_len, image->pi_addr2line) == NULL) {
2980b86b1bbSFabien Thomas warnx("WARNING: addr2line function name read error");
2990b86b1bbSFabien Thomas return (0);
3000b86b1bbSFabien Thomas }
3010b86b1bbSFabien Thomas sep = strchr(funcname, '\n');
3020b86b1bbSFabien Thomas if (sep != NULL)
3030b86b1bbSFabien Thomas *sep = '\0';
3040b86b1bbSFabien Thomas
3050b86b1bbSFabien Thomas if (fgets(sourcefile, sourcefile_len, image->pi_addr2line) == NULL) {
3060b86b1bbSFabien Thomas warnx("WARNING: addr2line source file read error");
3070b86b1bbSFabien Thomas return (0);
3080b86b1bbSFabien Thomas }
3090b86b1bbSFabien Thomas sep = strchr(sourcefile, ':');
3100b86b1bbSFabien Thomas if (sep == NULL) {
3110b86b1bbSFabien Thomas warnx("WARNING: addr2line source line separator missing");
3120b86b1bbSFabien Thomas return (0);
3130b86b1bbSFabien Thomas }
3140b86b1bbSFabien Thomas *sep = '\0';
315fa18b0b2SFabien Thomas l = atoi(sep+1);
316fa18b0b2SFabien Thomas if (l == 0)
3170b86b1bbSFabien Thomas return (0);
318fa18b0b2SFabien Thomas *sourceline = l;
3190b86b1bbSFabien Thomas return (1);
3200b86b1bbSFabien Thomas }
3210b86b1bbSFabien Thomas
3220b86b1bbSFabien Thomas /*
32349874f6eSJoseph Koshy * Given a pmcid in use, find its human-readable name.
32415139246SJoseph Koshy */
32515139246SJoseph Koshy
3260b86b1bbSFabien Thomas const char *
pmcstat_pmcid_to_name(pmc_id_t pmcid)32715139246SJoseph Koshy pmcstat_pmcid_to_name(pmc_id_t pmcid)
32815139246SJoseph Koshy {
32915139246SJoseph Koshy struct pmcstat_pmcrecord *pr;
33015139246SJoseph Koshy
33115139246SJoseph Koshy LIST_FOREACH(pr, &pmcstat_pmcs, pr_next)
33215139246SJoseph Koshy if (pr->pr_pmcid == pmcid)
33349874f6eSJoseph Koshy return (pmcstat_string_unintern(pr->pr_pmcname));
33415139246SJoseph Koshy
3350b86b1bbSFabien Thomas return NULL;
3360b86b1bbSFabien Thomas }
33715139246SJoseph Koshy
3380b86b1bbSFabien Thomas /*
3390b86b1bbSFabien Thomas * Convert PMC index to name.
3400b86b1bbSFabien Thomas */
34115139246SJoseph Koshy
3420b86b1bbSFabien Thomas const char *
pmcstat_pmcindex_to_name(int pmcin)3430b86b1bbSFabien Thomas pmcstat_pmcindex_to_name(int pmcin)
3440b86b1bbSFabien Thomas {
3450b86b1bbSFabien Thomas struct pmcstat_pmcrecord *pr;
34615139246SJoseph Koshy
3470b86b1bbSFabien Thomas LIST_FOREACH(pr, &pmcstat_pmcs, pr_next)
3480b86b1bbSFabien Thomas if (pr->pr_pmcin == pmcin)
3490b86b1bbSFabien Thomas return pmcstat_string_unintern(pr->pr_pmcname);
3500b86b1bbSFabien Thomas
3510b86b1bbSFabien Thomas return NULL;
3520b86b1bbSFabien Thomas }
3530b86b1bbSFabien Thomas
3540b86b1bbSFabien Thomas /*
3550b86b1bbSFabien Thomas * Return PMC record with given index.
3560b86b1bbSFabien Thomas */
3570b86b1bbSFabien Thomas
3580b86b1bbSFabien Thomas struct pmcstat_pmcrecord *
pmcstat_pmcindex_to_pmcr(int pmcin)3590b86b1bbSFabien Thomas pmcstat_pmcindex_to_pmcr(int pmcin)
3600b86b1bbSFabien Thomas {
3610b86b1bbSFabien Thomas struct pmcstat_pmcrecord *pr;
3620b86b1bbSFabien Thomas
3630b86b1bbSFabien Thomas LIST_FOREACH(pr, &pmcstat_pmcs, pr_next)
3640b86b1bbSFabien Thomas if (pr->pr_pmcin == pmcin)
3650b86b1bbSFabien Thomas return pr;
3660b86b1bbSFabien Thomas
3670b86b1bbSFabien Thomas return NULL;
3680b86b1bbSFabien Thomas }
3690b86b1bbSFabien Thomas
3700b86b1bbSFabien Thomas /*
37115139246SJoseph Koshy * Print log entries as text.
37215139246SJoseph Koshy */
37315139246SJoseph Koshy
37449874f6eSJoseph Koshy static int
pmcstat_print_log(void)3750b86b1bbSFabien Thomas pmcstat_print_log(void)
37615139246SJoseph Koshy {
37715139246SJoseph Koshy struct pmclog_ev ev;
378b6010f9eSJoseph Koshy uint32_t npc;
37915139246SJoseph Koshy
3800b86b1bbSFabien Thomas while (pmclog_read(args.pa_logparser, &ev) == 0) {
38115139246SJoseph Koshy assert(ev.pl_state == PMCLOG_OK);
38215139246SJoseph Koshy switch (ev.pl_type) {
383b6010f9eSJoseph Koshy case PMCLOG_TYPE_CALLCHAIN:
3840b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("callchain",
385b6010f9eSJoseph Koshy "%d 0x%x %d %d %c", ev.pl_u.pl_cc.pl_pid,
386b6010f9eSJoseph Koshy ev.pl_u.pl_cc.pl_pmcid,
387b6010f9eSJoseph Koshy PMC_CALLCHAIN_CPUFLAGS_TO_CPU(ev.pl_u.pl_cc. \
388b6010f9eSJoseph Koshy pl_cpuflags), ev.pl_u.pl_cc.pl_npc,
389b6010f9eSJoseph Koshy PMC_CALLCHAIN_CPUFLAGS_TO_USERMODE(ev.pl_u.pl_cc.\
390b6010f9eSJoseph Koshy pl_cpuflags) ? 'u' : 's');
391b6010f9eSJoseph Koshy for (npc = 0; npc < ev.pl_u.pl_cc.pl_npc; npc++)
3920b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("...", "%p",
393b6010f9eSJoseph Koshy (void *) ev.pl_u.pl_cc.pl_pc[npc]);
394b6010f9eSJoseph Koshy break;
39515139246SJoseph Koshy case PMCLOG_TYPE_CLOSELOG:
3960b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("closelog",);
39715139246SJoseph Koshy break;
39815139246SJoseph Koshy case PMCLOG_TYPE_DROPNOTIFY:
3990b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("drop",);
40015139246SJoseph Koshy break;
40115139246SJoseph Koshy case PMCLOG_TYPE_INITIALIZE:
4020b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("initlog","0x%x \"%s\"",
40315139246SJoseph Koshy ev.pl_u.pl_i.pl_version,
40415139246SJoseph Koshy pmc_name_of_cputype(ev.pl_u.pl_i.pl_arch));
4053ab065b6SJoseph Koshy if ((ev.pl_u.pl_i.pl_version & 0xFF000000) !=
40695104040SMatt Macy PMC_VERSION_MAJOR << 24)
40737d6f8a9SDavid E. O'Brien warnx(
40837d6f8a9SDavid E. O'Brien "WARNING: Log version 0x%x != expected version 0x%x.",
40937d6f8a9SDavid E. O'Brien ev.pl_u.pl_i.pl_version, PMC_VERSION);
41015139246SJoseph Koshy break;
41149874f6eSJoseph Koshy case PMCLOG_TYPE_MAP_IN:
4120b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("map-in","%d %p \"%s\"",
41349874f6eSJoseph Koshy ev.pl_u.pl_mi.pl_pid,
41449874f6eSJoseph Koshy (void *) ev.pl_u.pl_mi.pl_start,
41549874f6eSJoseph Koshy ev.pl_u.pl_mi.pl_pathname);
41649874f6eSJoseph Koshy break;
41749874f6eSJoseph Koshy case PMCLOG_TYPE_MAP_OUT:
4180b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("map-out","%d %p %p",
41949874f6eSJoseph Koshy ev.pl_u.pl_mo.pl_pid,
42049874f6eSJoseph Koshy (void *) ev.pl_u.pl_mo.pl_start,
42149874f6eSJoseph Koshy (void *) ev.pl_u.pl_mo.pl_end);
42215139246SJoseph Koshy break;
42315139246SJoseph Koshy case PMCLOG_TYPE_PMCALLOCATE:
4240b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("allocate","0x%x \"%s\" 0x%x",
42515139246SJoseph Koshy ev.pl_u.pl_a.pl_pmcid,
42615139246SJoseph Koshy ev.pl_u.pl_a.pl_evname,
42715139246SJoseph Koshy ev.pl_u.pl_a.pl_flags);
42815139246SJoseph Koshy break;
429f5f9340bSFabien Thomas case PMCLOG_TYPE_PMCALLOCATEDYN:
430f5f9340bSFabien Thomas PMCSTAT_PRINT_ENTRY("allocatedyn","0x%x \"%s\" 0x%x",
431f5f9340bSFabien Thomas ev.pl_u.pl_ad.pl_pmcid,
432f5f9340bSFabien Thomas ev.pl_u.pl_ad.pl_evname,
433f5f9340bSFabien Thomas ev.pl_u.pl_ad.pl_flags);
434f5f9340bSFabien Thomas break;
43515139246SJoseph Koshy case PMCLOG_TYPE_PMCATTACH:
4360b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("attach","0x%x %d \"%s\"",
43715139246SJoseph Koshy ev.pl_u.pl_t.pl_pmcid,
43815139246SJoseph Koshy ev.pl_u.pl_t.pl_pid,
43915139246SJoseph Koshy ev.pl_u.pl_t.pl_pathname);
44015139246SJoseph Koshy break;
44115139246SJoseph Koshy case PMCLOG_TYPE_PMCDETACH:
4420b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("detach","0x%x %d",
44315139246SJoseph Koshy ev.pl_u.pl_d.pl_pmcid,
44415139246SJoseph Koshy ev.pl_u.pl_d.pl_pid);
44515139246SJoseph Koshy break;
44615139246SJoseph Koshy case PMCLOG_TYPE_PROCCSW:
4470b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("cswval","0x%x %d %jd",
44815139246SJoseph Koshy ev.pl_u.pl_c.pl_pmcid,
44915139246SJoseph Koshy ev.pl_u.pl_c.pl_pid,
45015139246SJoseph Koshy ev.pl_u.pl_c.pl_value);
45115139246SJoseph Koshy break;
4529fd96b41SAndrew Turner case PMCLOG_TYPE_PROC_CREATE:
4539fd96b41SAndrew Turner PMCSTAT_PRINT_ENTRY("create","%d %x \"%s\"",
4549fd96b41SAndrew Turner ev.pl_u.pl_pc.pl_pid,
4559fd96b41SAndrew Turner ev.pl_u.pl_pc.pl_flags,
4569fd96b41SAndrew Turner ev.pl_u.pl_pc.pl_pcomm);
4579fd96b41SAndrew Turner break;
45815139246SJoseph Koshy case PMCLOG_TYPE_PROCEXEC:
45994426d21SJessica Clarke PMCSTAT_PRINT_ENTRY("exec","0x%x %d %p %p \"%s\"",
46015139246SJoseph Koshy ev.pl_u.pl_x.pl_pmcid,
46115139246SJoseph Koshy ev.pl_u.pl_x.pl_pid,
46294426d21SJessica Clarke (void *)ev.pl_u.pl_x.pl_baseaddr,
46394426d21SJessica Clarke (void *)ev.pl_u.pl_x.pl_dynaddr,
46415139246SJoseph Koshy ev.pl_u.pl_x.pl_pathname);
46515139246SJoseph Koshy break;
46615139246SJoseph Koshy case PMCLOG_TYPE_PROCEXIT:
4670b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("exitval","0x%x %d %jd",
46815139246SJoseph Koshy ev.pl_u.pl_e.pl_pmcid,
46915139246SJoseph Koshy ev.pl_u.pl_e.pl_pid,
47015139246SJoseph Koshy ev.pl_u.pl_e.pl_value);
47115139246SJoseph Koshy break;
47215139246SJoseph Koshy case PMCLOG_TYPE_PROCFORK:
4730b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("fork","%d %d",
47415139246SJoseph Koshy ev.pl_u.pl_f.pl_oldpid,
47515139246SJoseph Koshy ev.pl_u.pl_f.pl_newpid);
47615139246SJoseph Koshy break;
47715139246SJoseph Koshy case PMCLOG_TYPE_USERDATA:
4780b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("userdata","0x%x",
47915139246SJoseph Koshy ev.pl_u.pl_u.pl_userdata);
48015139246SJoseph Koshy break;
48115139246SJoseph Koshy case PMCLOG_TYPE_SYSEXIT:
4820b86b1bbSFabien Thomas PMCSTAT_PRINT_ENTRY("exit","%d",
48315139246SJoseph Koshy ev.pl_u.pl_se.pl_pid);
48415139246SJoseph Koshy break;
4859fd96b41SAndrew Turner case PMCLOG_TYPE_THR_CREATE:
4869fd96b41SAndrew Turner PMCSTAT_PRINT_ENTRY("thr-create","%d %d %x \"%s\"",
4879fd96b41SAndrew Turner ev.pl_u.pl_tc.pl_tid,
4889fd96b41SAndrew Turner ev.pl_u.pl_tc.pl_pid,
4899fd96b41SAndrew Turner ev.pl_u.pl_tc.pl_flags,
4909fd96b41SAndrew Turner ev.pl_u.pl_tc.pl_tdname);
4919fd96b41SAndrew Turner break;
4929fd96b41SAndrew Turner case PMCLOG_TYPE_THR_EXIT:
4939fd96b41SAndrew Turner PMCSTAT_PRINT_ENTRY("thr-exit","%d",
4949fd96b41SAndrew Turner ev.pl_u.pl_tc.pl_tid);
4959fd96b41SAndrew Turner break;
49615139246SJoseph Koshy default:
4970b86b1bbSFabien Thomas fprintf(args.pa_printfile, "unknown event (type %d).\n",
49815139246SJoseph Koshy ev.pl_type);
49915139246SJoseph Koshy }
50015139246SJoseph Koshy }
50115139246SJoseph Koshy
50215139246SJoseph Koshy if (ev.pl_state == PMCLOG_EOF)
50349874f6eSJoseph Koshy return (PMCSTAT_FINISHED);
50415139246SJoseph Koshy else if (ev.pl_state == PMCLOG_REQUIRE_DATA)
50549874f6eSJoseph Koshy return (PMCSTAT_RUNNING);
50615139246SJoseph Koshy
50737d6f8a9SDavid E. O'Brien errx(EX_DATAERR,
50837d6f8a9SDavid E. O'Brien "ERROR: event parsing failed (record %jd, offset 0x%jx).",
50915139246SJoseph Koshy (uintmax_t) ev.pl_count + 1, ev.pl_offset);
51015139246SJoseph Koshy /*NOTREACHED*/
51115139246SJoseph Koshy }
51215139246SJoseph Koshy
51315139246SJoseph Koshy /*
51449874f6eSJoseph Koshy * Public Interfaces.
51549874f6eSJoseph Koshy */
51649874f6eSJoseph Koshy
51749874f6eSJoseph Koshy /*
51815139246SJoseph Koshy * Process a log file in offline analysis mode.
51915139246SJoseph Koshy */
52015139246SJoseph Koshy
521dc1d9d2eSJoseph Koshy int
pmcstat_process_log(void)5220b86b1bbSFabien Thomas pmcstat_process_log(void)
52315139246SJoseph Koshy {
52415139246SJoseph Koshy
52515139246SJoseph Koshy /*
526b6010f9eSJoseph Koshy * If analysis has not been asked for, just print the log to
527b6010f9eSJoseph Koshy * the current output file.
52815139246SJoseph Koshy */
5290b86b1bbSFabien Thomas if (args.pa_flags & FLAG_DO_PRINT)
5300b86b1bbSFabien Thomas return (pmcstat_print_log());
53115139246SJoseph Koshy else
532d27927f7SRuslan Bukin return (pmcstat_analyze_log(&args, plugins, &pmcstat_stats, pmcstat_kernproc,
533d27927f7SRuslan Bukin pmcstat_mergepmc, &pmcstat_npmcs, &ps_samples_period));
5340b86b1bbSFabien Thomas }
5350b86b1bbSFabien Thomas
5360b86b1bbSFabien Thomas /*
5370b86b1bbSFabien Thomas * Refresh top display.
5380b86b1bbSFabien Thomas */
5390b86b1bbSFabien Thomas
5400b86b1bbSFabien Thomas static void
pmcstat_refresh_top(void)5410b86b1bbSFabien Thomas pmcstat_refresh_top(void)
5420b86b1bbSFabien Thomas {
543c86819ecSFabien Thomas int v_attrs;
544c86819ecSFabien Thomas float v;
5450b86b1bbSFabien Thomas char pmcname[40];
546c86819ecSFabien Thomas struct pmcstat_pmcrecord *pmcpr;
5470b86b1bbSFabien Thomas
5480b86b1bbSFabien Thomas /* If in pause mode do not refresh display. */
5490b86b1bbSFabien Thomas if (pmcstat_pause)
5500b86b1bbSFabien Thomas return;
5510b86b1bbSFabien Thomas
5529ba84a88SFabien Thomas /* Wait until PMC pop in the log. */
553c86819ecSFabien Thomas pmcpr = pmcstat_pmcindex_to_pmcr(pmcstat_pmcinfilter);
554c86819ecSFabien Thomas if (pmcpr == NULL)
5559ba84a88SFabien Thomas return;
5569ba84a88SFabien Thomas
5570b86b1bbSFabien Thomas /* Format PMC name. */
5580b86b1bbSFabien Thomas if (pmcstat_mergepmc)
559c86819ecSFabien Thomas snprintf(pmcname, sizeof(pmcname), "[%s]",
560c86819ecSFabien Thomas pmcstat_string_unintern(pmcpr->pr_pmcname));
5610b86b1bbSFabien Thomas else
5620b86b1bbSFabien Thomas snprintf(pmcname, sizeof(pmcname), "%s.%d",
563c86819ecSFabien Thomas pmcstat_string_unintern(pmcpr->pr_pmcname),
564c86819ecSFabien Thomas pmcstat_pmcinfilter);
565c86819ecSFabien Thomas
566c86819ecSFabien Thomas /* Format samples count. */
567ac708fddSFabien Thomas if (ps_samples_period > 0)
568ac708fddSFabien Thomas v = (pmcpr->pr_samples * 100.0) / ps_samples_period;
569c86819ecSFabien Thomas else
570c86819ecSFabien Thomas v = 0.;
571c86819ecSFabien Thomas v_attrs = PMCSTAT_ATTRPERCENT(v);
5720b86b1bbSFabien Thomas
5730b86b1bbSFabien Thomas PMCSTAT_PRINTBEGIN();
574c86819ecSFabien Thomas PMCSTAT_PRINTW("PMC: %s Samples: %u ",
5750b86b1bbSFabien Thomas pmcname,
576c86819ecSFabien Thomas pmcpr->pr_samples);
577c86819ecSFabien Thomas PMCSTAT_ATTRON(v_attrs);
578c86819ecSFabien Thomas PMCSTAT_PRINTW("(%.1f%%) ", v);
579c86819ecSFabien Thomas PMCSTAT_ATTROFF(v_attrs);
580c86819ecSFabien Thomas PMCSTAT_PRINTW(", %u unresolved\n\n",
581c86819ecSFabien Thomas pmcpr->pr_dubious_frames);
5820b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_topdisplay != NULL)
5830b86b1bbSFabien Thomas plugins[args.pa_plugin].pl_topdisplay();
5840b86b1bbSFabien Thomas PMCSTAT_PRINTEND();
5850b86b1bbSFabien Thomas }
5860b86b1bbSFabien Thomas
5870b86b1bbSFabien Thomas /*
5880b86b1bbSFabien Thomas * Find the next pmc index to display.
5890b86b1bbSFabien Thomas */
5900b86b1bbSFabien Thomas
5910b86b1bbSFabien Thomas static void
pmcstat_changefilter(void)5920b86b1bbSFabien Thomas pmcstat_changefilter(void)
5930b86b1bbSFabien Thomas {
5940b86b1bbSFabien Thomas int pmcin;
5950b86b1bbSFabien Thomas struct pmcstat_pmcrecord *pmcr;
5960b86b1bbSFabien Thomas
5970b86b1bbSFabien Thomas /*
5980b86b1bbSFabien Thomas * Find the next merge target.
5990b86b1bbSFabien Thomas */
6000b86b1bbSFabien Thomas if (pmcstat_mergepmc) {
6010b86b1bbSFabien Thomas pmcin = pmcstat_pmcinfilter;
6020b86b1bbSFabien Thomas
6030b86b1bbSFabien Thomas do {
6040b86b1bbSFabien Thomas pmcr = pmcstat_pmcindex_to_pmcr(pmcstat_pmcinfilter);
605ac708fddSFabien Thomas if (pmcr == NULL || pmcr == pmcr->pr_merge)
6060b86b1bbSFabien Thomas break;
6070b86b1bbSFabien Thomas
6080b86b1bbSFabien Thomas pmcstat_pmcinfilter++;
6090b86b1bbSFabien Thomas if (pmcstat_pmcinfilter >= pmcstat_npmcs)
6100b86b1bbSFabien Thomas pmcstat_pmcinfilter = 0;
6110b86b1bbSFabien Thomas
6120b86b1bbSFabien Thomas } while (pmcstat_pmcinfilter != pmcin);
6130b86b1bbSFabien Thomas }
6140b86b1bbSFabien Thomas }
6150b86b1bbSFabien Thomas
6160b86b1bbSFabien Thomas /*
6170b86b1bbSFabien Thomas * Top mode keypress.
6180b86b1bbSFabien Thomas */
6190b86b1bbSFabien Thomas
6200b86b1bbSFabien Thomas int
pmcstat_keypress_log(void)6210b86b1bbSFabien Thomas pmcstat_keypress_log(void)
6220b86b1bbSFabien Thomas {
6230b86b1bbSFabien Thomas int c, ret = 0;
6240b86b1bbSFabien Thomas WINDOW *w;
6250b86b1bbSFabien Thomas
6260b86b1bbSFabien Thomas w = newwin(1, 0, 1, 0);
6270b86b1bbSFabien Thomas c = wgetch(w);
6280b86b1bbSFabien Thomas wprintw(w, "Key: %c => ", c);
6290b86b1bbSFabien Thomas switch (c) {
63094e9ef85SMateusz Guzik case 'A':
63194e9ef85SMateusz Guzik if (args.pa_flags & FLAG_SKIP_TOP_FN_RES)
63294e9ef85SMateusz Guzik args.pa_flags &= ~FLAG_SKIP_TOP_FN_RES;
63394e9ef85SMateusz Guzik else
63494e9ef85SMateusz Guzik args.pa_flags |= FLAG_SKIP_TOP_FN_RES;
63594e9ef85SMateusz Guzik break;
6360b86b1bbSFabien Thomas case 'c':
6370b86b1bbSFabien Thomas wprintw(w, "enter mode 'd' or 'a' => ");
6380b86b1bbSFabien Thomas c = wgetch(w);
6390b86b1bbSFabien Thomas if (c == 'd') {
6400b86b1bbSFabien Thomas args.pa_topmode = PMCSTAT_TOP_DELTA;
6410b86b1bbSFabien Thomas wprintw(w, "switching to delta mode");
6420b86b1bbSFabien Thomas } else {
6430b86b1bbSFabien Thomas args.pa_topmode = PMCSTAT_TOP_ACCUM;
6440b86b1bbSFabien Thomas wprintw(w, "switching to accumulation mode");
6450b86b1bbSFabien Thomas }
6460b86b1bbSFabien Thomas break;
64794e9ef85SMateusz Guzik case 'I':
64894e9ef85SMateusz Guzik if (args.pa_flags & FLAG_SHOW_OFFSET)
64994e9ef85SMateusz Guzik args.pa_flags &= ~FLAG_SHOW_OFFSET;
65094e9ef85SMateusz Guzik else
65194e9ef85SMateusz Guzik args.pa_flags |= FLAG_SHOW_OFFSET;
65294e9ef85SMateusz Guzik break;
6530b86b1bbSFabien Thomas case 'm':
6540b86b1bbSFabien Thomas pmcstat_mergepmc = !pmcstat_mergepmc;
6550b86b1bbSFabien Thomas /*
6560b86b1bbSFabien Thomas * Changing merge state require data reset.
6570b86b1bbSFabien Thomas */
6580b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_shutdown != NULL)
6590b86b1bbSFabien Thomas plugins[args.pa_plugin].pl_shutdown(NULL);
660ac708fddSFabien Thomas pmcstat_stats_reset(0);
6610b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_init != NULL)
6620b86b1bbSFabien Thomas plugins[args.pa_plugin].pl_init();
6630b86b1bbSFabien Thomas
6640b86b1bbSFabien Thomas /* Update filter to be on a merge target. */
6650b86b1bbSFabien Thomas pmcstat_changefilter();
6660b86b1bbSFabien Thomas wprintw(w, "merge PMC %s", pmcstat_mergepmc ? "on" : "off");
6670b86b1bbSFabien Thomas break;
6680b86b1bbSFabien Thomas case 'n':
6690b86b1bbSFabien Thomas /* Close current plugin. */
6700b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_shutdown != NULL)
6710b86b1bbSFabien Thomas plugins[args.pa_plugin].pl_shutdown(NULL);
6720b86b1bbSFabien Thomas
6730b86b1bbSFabien Thomas /* Find next top display available. */
6740b86b1bbSFabien Thomas do {
6750b86b1bbSFabien Thomas args.pa_plugin++;
6760b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_name == NULL)
6770b86b1bbSFabien Thomas args.pa_plugin = 0;
6780b86b1bbSFabien Thomas } while (plugins[args.pa_plugin].pl_topdisplay == NULL);
6790b86b1bbSFabien Thomas
6800b86b1bbSFabien Thomas /* Open new plugin. */
681ac708fddSFabien Thomas pmcstat_stats_reset(0);
6820b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_init != NULL)
6830b86b1bbSFabien Thomas plugins[args.pa_plugin].pl_init();
6840b86b1bbSFabien Thomas wprintw(w, "switching to plugin %s",
6850b86b1bbSFabien Thomas plugins[args.pa_plugin].pl_name);
6860b86b1bbSFabien Thomas break;
6870b86b1bbSFabien Thomas case 'p':
6880b86b1bbSFabien Thomas pmcstat_pmcinfilter++;
6890b86b1bbSFabien Thomas if (pmcstat_pmcinfilter >= pmcstat_npmcs)
6900b86b1bbSFabien Thomas pmcstat_pmcinfilter = 0;
6910b86b1bbSFabien Thomas pmcstat_changefilter();
6920b86b1bbSFabien Thomas wprintw(w, "switching to PMC %s.%d",
6930b86b1bbSFabien Thomas pmcstat_pmcindex_to_name(pmcstat_pmcinfilter),
6940b86b1bbSFabien Thomas pmcstat_pmcinfilter);
6950b86b1bbSFabien Thomas break;
6960b86b1bbSFabien Thomas case ' ':
6970b86b1bbSFabien Thomas pmcstat_pause = !pmcstat_pause;
6980b86b1bbSFabien Thomas if (pmcstat_pause)
6990b86b1bbSFabien Thomas wprintw(w, "pause => press space again to continue");
7000b86b1bbSFabien Thomas break;
7010b86b1bbSFabien Thomas case 'q':
7020b86b1bbSFabien Thomas wprintw(w, "exiting...");
7030b86b1bbSFabien Thomas ret = 1;
7045c15d3c8SFabien Thomas break;
7050b86b1bbSFabien Thomas default:
7060b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_topkeypress != NULL)
707d27927f7SRuslan Bukin if (plugins[args.pa_plugin].pl_topkeypress(c, (void *)w))
7080b86b1bbSFabien Thomas ret = 1;
7090b86b1bbSFabien Thomas }
7100b86b1bbSFabien Thomas
7110b86b1bbSFabien Thomas wrefresh(w);
7120b86b1bbSFabien Thomas delwin(w);
7130b86b1bbSFabien Thomas return ret;
7140b86b1bbSFabien Thomas }
7150b86b1bbSFabien Thomas
7160b86b1bbSFabien Thomas
7170b86b1bbSFabien Thomas /*
7180b86b1bbSFabien Thomas * Top mode display.
7190b86b1bbSFabien Thomas */
7200b86b1bbSFabien Thomas
7210b86b1bbSFabien Thomas void
pmcstat_display_log(void)7220b86b1bbSFabien Thomas pmcstat_display_log(void)
7230b86b1bbSFabien Thomas {
7240b86b1bbSFabien Thomas
7250b86b1bbSFabien Thomas pmcstat_refresh_top();
7260b86b1bbSFabien Thomas
727*b8b97d31SElyes Haouas /* Reset everything if delta mode. */
7280b86b1bbSFabien Thomas if (args.pa_topmode == PMCSTAT_TOP_DELTA) {
7290b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_shutdown != NULL)
7300b86b1bbSFabien Thomas plugins[args.pa_plugin].pl_shutdown(NULL);
731ac708fddSFabien Thomas pmcstat_stats_reset(0);
7320b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_init != NULL)
7330b86b1bbSFabien Thomas plugins[args.pa_plugin].pl_init();
7340b86b1bbSFabien Thomas }
7350b86b1bbSFabien Thomas }
7360b86b1bbSFabien Thomas
7370b86b1bbSFabien Thomas /*
7380b86b1bbSFabien Thomas * Configure a plugins.
7390b86b1bbSFabien Thomas */
7400b86b1bbSFabien Thomas
7410b86b1bbSFabien Thomas void
pmcstat_pluginconfigure_log(char * opt)7420b86b1bbSFabien Thomas pmcstat_pluginconfigure_log(char *opt)
7430b86b1bbSFabien Thomas {
7440b86b1bbSFabien Thomas
7450b86b1bbSFabien Thomas if (strncmp(opt, "threshold=", 10) == 0) {
7460b86b1bbSFabien Thomas pmcstat_threshold = atof(opt+10);
7470b86b1bbSFabien Thomas } else {
7480b86b1bbSFabien Thomas if (plugins[args.pa_plugin].pl_configure != NULL) {
7490b86b1bbSFabien Thomas if (!plugins[args.pa_plugin].pl_configure(opt))
7500b86b1bbSFabien Thomas err(EX_USAGE,
7510b86b1bbSFabien Thomas "ERROR: unknown option <%s>.", opt);
7520b86b1bbSFabien Thomas }
7530b86b1bbSFabien Thomas }
75415139246SJoseph Koshy }
75515139246SJoseph Koshy
756d27927f7SRuslan Bukin void
pmcstat_log_shutdown_logging(void)757d27927f7SRuslan Bukin pmcstat_log_shutdown_logging(void)
758d27927f7SRuslan Bukin {
759d27927f7SRuslan Bukin
760d27927f7SRuslan Bukin pmcstat_shutdown_logging(&args, plugins, &pmcstat_stats);
761d27927f7SRuslan Bukin }
76249874f6eSJoseph Koshy
76315139246SJoseph Koshy void
pmcstat_log_initialize_logging(void)764d27927f7SRuslan Bukin pmcstat_log_initialize_logging(void)
76515139246SJoseph Koshy {
76649874f6eSJoseph Koshy
767d27927f7SRuslan Bukin pmcstat_initialize_logging(&pmcstat_kernproc,
768d27927f7SRuslan Bukin &args, plugins, &pmcstat_npmcs, &pmcstat_mergepmc);
76915139246SJoseph Koshy }
770