1*3adde0e5SAli Mashtizadeh /*-
2*3adde0e5SAli Mashtizadeh * SPDX-License-Identifier: BSD-2-Clause
3*3adde0e5SAli Mashtizadeh *
4*3adde0e5SAli Mashtizadeh * Copyright (c) 2026, Netflix, Inc.
5*3adde0e5SAli Mashtizadeh *
6*3adde0e5SAli Mashtizadeh * This software was developed by Ali Mashtizadeh under the sponsorship from
7*3adde0e5SAli Mashtizadeh * Netflix, Inc.
8*3adde0e5SAli Mashtizadeh *
9*3adde0e5SAli Mashtizadeh * Redistribution and use in source and binary forms, with or without
10*3adde0e5SAli Mashtizadeh * modification, are permitted provided that the following conditions
11*3adde0e5SAli Mashtizadeh * are met:
12*3adde0e5SAli Mashtizadeh * 1. Redistributions of source code must retain the above copyright
13*3adde0e5SAli Mashtizadeh * notice, this list of conditions and the following disclaimer.
14*3adde0e5SAli Mashtizadeh * 2. Redistributions in binary form must reproduce the above copyright
15*3adde0e5SAli Mashtizadeh * notice, this list of conditions and the following disclaimer in the
16*3adde0e5SAli Mashtizadeh * documentation and/or other materials provided with the distribution.
17*3adde0e5SAli Mashtizadeh *
18*3adde0e5SAli Mashtizadeh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19*3adde0e5SAli Mashtizadeh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*3adde0e5SAli Mashtizadeh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*3adde0e5SAli Mashtizadeh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22*3adde0e5SAli Mashtizadeh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23*3adde0e5SAli Mashtizadeh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24*3adde0e5SAli Mashtizadeh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25*3adde0e5SAli Mashtizadeh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26*3adde0e5SAli Mashtizadeh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27*3adde0e5SAli Mashtizadeh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28*3adde0e5SAli Mashtizadeh * SUCH DAMAGE.
29*3adde0e5SAli Mashtizadeh *
30*3adde0e5SAli Mashtizadeh */
31*3adde0e5SAli Mashtizadeh
32*3adde0e5SAli Mashtizadeh #include <sys/param.h>
33*3adde0e5SAli Mashtizadeh #include <sys/cpuset.h>
34*3adde0e5SAli Mashtizadeh #include <sys/event.h>
35*3adde0e5SAli Mashtizadeh #include <sys/queue.h>
36*3adde0e5SAli Mashtizadeh #include <sys/socket.h>
37*3adde0e5SAli Mashtizadeh #include <sys/stat.h>
38*3adde0e5SAli Mashtizadeh #include <sys/sysctl.h>
39*3adde0e5SAli Mashtizadeh #include <sys/time.h>
40*3adde0e5SAli Mashtizadeh #include <sys/ttycom.h>
41*3adde0e5SAli Mashtizadeh #include <sys/user.h>
42*3adde0e5SAli Mashtizadeh #include <sys/wait.h>
43*3adde0e5SAli Mashtizadeh
44*3adde0e5SAli Mashtizadeh #include <assert.h>
45*3adde0e5SAli Mashtizadeh #include <curses.h>
46*3adde0e5SAli Mashtizadeh #include <err.h>
47*3adde0e5SAli Mashtizadeh #include <errno.h>
48*3adde0e5SAli Mashtizadeh #include <fcntl.h>
49*3adde0e5SAli Mashtizadeh #include <getopt.h>
50*3adde0e5SAli Mashtizadeh #include <kvm.h>
51*3adde0e5SAli Mashtizadeh #include <libgen.h>
52*3adde0e5SAli Mashtizadeh #include <limits.h>
53*3adde0e5SAli Mashtizadeh #include <locale.h>
54*3adde0e5SAli Mashtizadeh #include <math.h>
55*3adde0e5SAli Mashtizadeh #include <pmc.h>
56*3adde0e5SAli Mashtizadeh #include <pmclog.h>
57*3adde0e5SAli Mashtizadeh #include <regex.h>
58*3adde0e5SAli Mashtizadeh #include <signal.h>
59*3adde0e5SAli Mashtizadeh #include <stdarg.h>
60*3adde0e5SAli Mashtizadeh #include <stdint.h>
61*3adde0e5SAli Mashtizadeh #include <stdio.h>
62*3adde0e5SAli Mashtizadeh #include <stdlib.h>
63*3adde0e5SAli Mashtizadeh #include <stddef.h>
64*3adde0e5SAli Mashtizadeh #include <string.h>
65*3adde0e5SAli Mashtizadeh #include <sysexits.h>
66*3adde0e5SAli Mashtizadeh #include <unistd.h>
67*3adde0e5SAli Mashtizadeh
68*3adde0e5SAli Mashtizadeh #include "cmd_pmc.h"
69*3adde0e5SAli Mashtizadeh
70*3adde0e5SAli Mashtizadeh #include <iostream>
71*3adde0e5SAli Mashtizadeh #include <map>
72*3adde0e5SAli Mashtizadeh #include <set>
73*3adde0e5SAli Mashtizadeh #include <string>
74*3adde0e5SAli Mashtizadeh #include <unordered_map>
75*3adde0e5SAli Mashtizadeh #include <unordered_set>
76*3adde0e5SAli Mashtizadeh #include <vector>
77*3adde0e5SAli Mashtizadeh
78*3adde0e5SAli Mashtizadeh #include "display.hh"
79*3adde0e5SAli Mashtizadeh #include "view.hh"
80*3adde0e5SAli Mashtizadeh
81*3adde0e5SAli Mashtizadeh class info_view : public pmcview
82*3adde0e5SAli Mashtizadeh {
83*3adde0e5SAli Mashtizadeh public:
84*3adde0e5SAli Mashtizadeh virtual void
callchain(struct pmclog_ev_callchain & p)85*3adde0e5SAli Mashtizadeh callchain(struct pmclog_ev_callchain &p)
86*3adde0e5SAli Mashtizadeh {
87*3adde0e5SAli Mashtizadeh uint64_t eventid = pmcidtoeventid(p.pl_pmcid);
88*3adde0e5SAli Mashtizadeh
89*3adde0e5SAli Mashtizadeh pmcinfo[eventid].count++;
90*3adde0e5SAli Mashtizadeh }
91*3adde0e5SAli Mashtizadeh
92*3adde0e5SAli Mashtizadeh virtual void
print()93*3adde0e5SAli Mashtizadeh print()
94*3adde0e5SAli Mashtizadeh {
95*3adde0e5SAli Mashtizadeh title("PMC Info");
96*3adde0e5SAli Mashtizadeh
97*3adde0e5SAli Mashtizadeh header("System Info");
98*3adde0e5SAli Mashtizadeh printf("CPU Model: %s\n", cpumodel.c_str());
99*3adde0e5SAli Mashtizadeh printf("OS Release: %s\n", osrelease.c_str());
100*3adde0e5SAli Mashtizadeh printf("Build ID: %s\n", buildid.c_str());
101*3adde0e5SAli Mashtizadeh printf("\n");
102*3adde0e5SAli Mashtizadeh
103*3adde0e5SAli Mashtizadeh if (arch == PMC_ARCH_AMD64) {
104*3adde0e5SAli Mashtizadeh header("CPUID");
105*3adde0e5SAli Mashtizadeh for (auto &c : cpuid)
106*3adde0e5SAli Mashtizadeh printf("0x%08x: 0x%08x 0x%08x 0x%08x 0x%08x\n",
107*3adde0e5SAli Mashtizadeh c.first, c.second.eax, c.second.ebx,
108*3adde0e5SAli Mashtizadeh c.second.ecx, c.second.edx);
109*3adde0e5SAli Mashtizadeh printf("\n");
110*3adde0e5SAli Mashtizadeh }
111*3adde0e5SAli Mashtizadeh
112*3adde0e5SAli Mashtizadeh header("PMC Info");
113*3adde0e5SAli Mashtizadeh for (auto &p : extpmcinfo)
114*3adde0e5SAli Mashtizadeh printf("%s\n", p.event.c_str());
115*3adde0e5SAli Mashtizadeh printf("\n");
116*3adde0e5SAli Mashtizadeh
117*3adde0e5SAli Mashtizadeh table t = table();
118*3adde0e5SAli Mashtizadeh t.addcolumn("Counter", true);
119*3adde0e5SAli Mashtizadeh t.addcolumn("Counts", true);
120*3adde0e5SAli Mashtizadeh
121*3adde0e5SAli Mashtizadeh for (auto &p : pmcinfo) {
122*3adde0e5SAli Mashtizadeh std::vector<field> r;
123*3adde0e5SAli Mashtizadeh
124*3adde0e5SAli Mashtizadeh r.emplace_back(p.second.name);
125*3adde0e5SAli Mashtizadeh r.emplace_back((int64_t)p.second.count);
126*3adde0e5SAli Mashtizadeh
127*3adde0e5SAli Mashtizadeh t.addrow(r);
128*3adde0e5SAli Mashtizadeh }
129*3adde0e5SAli Mashtizadeh
130*3adde0e5SAli Mashtizadeh t.print();
131*3adde0e5SAli Mashtizadeh }
132*3adde0e5SAli Mashtizadeh };
133*3adde0e5SAli Mashtizadeh
134*3adde0e5SAli Mashtizadeh static struct option longopts[] = {
135*3adde0e5SAli Mashtizadeh PMCFILTER_LOPTS,
136*3adde0e5SAli Mashtizadeh { NULL, 0, NULL, 0 }
137*3adde0e5SAli Mashtizadeh };
138*3adde0e5SAli Mashtizadeh
139*3adde0e5SAli Mashtizadeh static void
usage(void)140*3adde0e5SAli Mashtizadeh usage(void)
141*3adde0e5SAli Mashtizadeh {
142*3adde0e5SAli Mashtizadeh printf("Usage: pmc info [options] [pmclog]\n\n");
143*3adde0e5SAli Mashtizadeh printf("Display a log summary\n\n");
144*3adde0e5SAli Mashtizadeh printf("Options:\n");
145*3adde0e5SAli Mashtizadeh PMCFILTER_PRINTOPTS();
146*3adde0e5SAli Mashtizadeh }
147*3adde0e5SAli Mashtizadeh
148*3adde0e5SAli Mashtizadeh int
cmd_pmc_info(int argc,char ** argv)149*3adde0e5SAli Mashtizadeh cmd_pmc_info(int argc, char **argv)
150*3adde0e5SAli Mashtizadeh {
151*3adde0e5SAli Mashtizadeh struct pmcfilter filter = pmcfilter();
152*3adde0e5SAli Mashtizadeh const char *logfile = "default.log";
153*3adde0e5SAli Mashtizadeh int option, logfd;
154*3adde0e5SAli Mashtizadeh
155*3adde0e5SAli Mashtizadeh while ((option = getopt_long(argc, argv, PMCFILTER_SOPTS "s:", longopts, NULL)) != -1) {
156*3adde0e5SAli Mashtizadeh switch (option) {
157*3adde0e5SAli Mashtizadeh PMCFILTER_CASE(filter);
158*3adde0e5SAli Mashtizadeh case '?':
159*3adde0e5SAli Mashtizadeh default:
160*3adde0e5SAli Mashtizadeh usage();
161*3adde0e5SAli Mashtizadeh }
162*3adde0e5SAli Mashtizadeh }
163*3adde0e5SAli Mashtizadeh argc -= optind;
164*3adde0e5SAli Mashtizadeh argv += optind;
165*3adde0e5SAli Mashtizadeh if (argc != 0 && argc != 1) {
166*3adde0e5SAli Mashtizadeh usage();
167*3adde0e5SAli Mashtizadeh exit(EX_USAGE);
168*3adde0e5SAli Mashtizadeh }
169*3adde0e5SAli Mashtizadeh if (argc == 1)
170*3adde0e5SAli Mashtizadeh logfile = argv[0];
171*3adde0e5SAli Mashtizadeh
172*3adde0e5SAli Mashtizadeh setup_screen();
173*3adde0e5SAli Mashtizadeh
174*3adde0e5SAli Mashtizadeh if ((logfd = open(logfile, O_RDONLY)) < 0) {
175*3adde0e5SAli Mashtizadeh errx(EX_OSERR, "ERROR: Cannot open \"%s\" for reading: %s.", logfile,
176*3adde0e5SAli Mashtizadeh strerror(errno));
177*3adde0e5SAli Mashtizadeh return (EX_NOINPUT);
178*3adde0e5SAli Mashtizadeh }
179*3adde0e5SAli Mashtizadeh
180*3adde0e5SAli Mashtizadeh info_view s = info_view();
181*3adde0e5SAli Mashtizadeh s.setfilter(filter);
182*3adde0e5SAli Mashtizadeh s.process(logfd);
183*3adde0e5SAli Mashtizadeh s.print();
184*3adde0e5SAli Mashtizadeh
185*3adde0e5SAli Mashtizadeh return (EX_OK);
186*3adde0e5SAli Mashtizadeh }
187