xref: /freebsd/usr.sbin/pmc/cmd_pmc_info.cc (revision 3adde0e55d7c01018b0877e1407aede7e757ce04)
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