xref: /titanic_53/usr/src/tools/cpcgen/cpcgen.c (revision 53548f91e84cd97a638c23b5b295cc69089a5030)
1*53548f91SRobert Mustacchi /*
2*53548f91SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*53548f91SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*53548f91SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*53548f91SRobert Mustacchi  * 1.0 of the CDDL.
6*53548f91SRobert Mustacchi  *
7*53548f91SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*53548f91SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*53548f91SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*53548f91SRobert Mustacchi  */
11*53548f91SRobert Mustacchi 
12*53548f91SRobert Mustacchi /*
13*53548f91SRobert Mustacchi  * Copyright (c) 2018, Joyent, Inc.
14*53548f91SRobert Mustacchi  */
15*53548f91SRobert Mustacchi 
16*53548f91SRobert Mustacchi /*
17*53548f91SRobert Mustacchi  * This file transforms the perfmon data files into C files and manual pages.
18*53548f91SRobert Mustacchi  */
19*53548f91SRobert Mustacchi 
20*53548f91SRobert Mustacchi #include <stdio.h>
21*53548f91SRobert Mustacchi #include <stdarg.h>
22*53548f91SRobert Mustacchi #include <unistd.h>
23*53548f91SRobert Mustacchi #include <err.h>
24*53548f91SRobert Mustacchi #include <libgen.h>
25*53548f91SRobert Mustacchi #include <libnvpair.h>
26*53548f91SRobert Mustacchi #include <strings.h>
27*53548f91SRobert Mustacchi #include <errno.h>
28*53548f91SRobert Mustacchi #include <limits.h>
29*53548f91SRobert Mustacchi #include <sys/mman.h>
30*53548f91SRobert Mustacchi #include <sys/param.h>
31*53548f91SRobert Mustacchi #include <assert.h>
32*53548f91SRobert Mustacchi #include <ctype.h>
33*53548f91SRobert Mustacchi #include <sys/types.h>
34*53548f91SRobert Mustacchi #include <sys/stat.h>
35*53548f91SRobert Mustacchi #include <fcntl.h>
36*53548f91SRobert Mustacchi 
37*53548f91SRobert Mustacchi #include <json_nvlist.h>
38*53548f91SRobert Mustacchi 
39*53548f91SRobert Mustacchi #define	EXIT_USAGE	2
40*53548f91SRobert Mustacchi 
41*53548f91SRobert Mustacchi 
42*53548f91SRobert Mustacchi typedef struct cpc_proc {
43*53548f91SRobert Mustacchi 	struct cpc_proc *cproc_next;
44*53548f91SRobert Mustacchi 	uint_t		cproc_family;
45*53548f91SRobert Mustacchi 	uint_t		cproc_model;
46*53548f91SRobert Mustacchi } cpc_proc_t;
47*53548f91SRobert Mustacchi 
48*53548f91SRobert Mustacchi typedef enum cpc_file_type {
49*53548f91SRobert Mustacchi 	CPC_FILE_CORE		= 1 << 0,
50*53548f91SRobert Mustacchi 	CPC_FILE_OFF_CORE	= 1 << 1,
51*53548f91SRobert Mustacchi 	CPC_FILE_UNCORE		= 1 << 2,
52*53548f91SRobert Mustacchi 	CPC_FILE_FP_MATH	= 1 << 3,
53*53548f91SRobert Mustacchi 	CPC_FILE_UNCORE_EXP	= 1 << 4
54*53548f91SRobert Mustacchi } cpc_type_t;
55*53548f91SRobert Mustacchi 
56*53548f91SRobert Mustacchi typedef struct cpc_map {
57*53548f91SRobert Mustacchi 	struct cpc_map	*cmap_next;
58*53548f91SRobert Mustacchi 	cpc_type_t	cmap_type;
59*53548f91SRobert Mustacchi 	nvlist_t	*cmap_data;
60*53548f91SRobert Mustacchi 	char		*cmap_path;
61*53548f91SRobert Mustacchi 	const char	*cmap_name;
62*53548f91SRobert Mustacchi 	cpc_proc_t	*cmap_procs;
63*53548f91SRobert Mustacchi } cpc_map_t;
64*53548f91SRobert Mustacchi 
65*53548f91SRobert Mustacchi typedef struct cpc_whitelist {
66*53548f91SRobert Mustacchi 	const char	*cwhite_short;
67*53548f91SRobert Mustacchi 	const char	*cwhite_human;
68*53548f91SRobert Mustacchi 	uint_t		cwhite_mask;
69*53548f91SRobert Mustacchi } cpc_whitelist_t;
70*53548f91SRobert Mustacchi 
71*53548f91SRobert Mustacchi /*
72*53548f91SRobert Mustacchi  * List of architectures that we support generating this data for. This is done
73*53548f91SRobert Mustacchi  * so that processors that illumos doesn't support or run on aren't generated
74*53548f91SRobert Mustacchi  * (generally the Xeon Phi).
75*53548f91SRobert Mustacchi  */
76*53548f91SRobert Mustacchi static cpc_whitelist_t cpcgen_whitelist[] = {
77*53548f91SRobert Mustacchi 	/* Nehalem */
78*53548f91SRobert Mustacchi 	{ "NHM-EP", "nhm_ep", CPC_FILE_CORE },
79*53548f91SRobert Mustacchi 	{ "NHM-EX", "nhm_ex", CPC_FILE_CORE },
80*53548f91SRobert Mustacchi 	/* Westmere */
81*53548f91SRobert Mustacchi 	{ "WSM-EP-DP", "wsm_ep_dp", CPC_FILE_CORE },
82*53548f91SRobert Mustacchi 	{ "WSM-EP-SP", "wsm_ep_sp", CPC_FILE_CORE },
83*53548f91SRobert Mustacchi 	{ "WSM-EX", "wsm_ex", CPC_FILE_CORE },
84*53548f91SRobert Mustacchi 	/* Sandy Bridge */
85*53548f91SRobert Mustacchi 	{ "SNB", "snb", CPC_FILE_CORE },
86*53548f91SRobert Mustacchi 	{ "JKT", "jkt", CPC_FILE_CORE },
87*53548f91SRobert Mustacchi 	/* Ivy Bridge */
88*53548f91SRobert Mustacchi 	{ "IVB", "ivb", CPC_FILE_CORE },
89*53548f91SRobert Mustacchi 	{ "IVT", "ivt", CPC_FILE_CORE },
90*53548f91SRobert Mustacchi 	/* Haswell */
91*53548f91SRobert Mustacchi 	{ "HSW", "hsw", CPC_FILE_CORE },
92*53548f91SRobert Mustacchi 	{ "HSX", "hsx", CPC_FILE_CORE },
93*53548f91SRobert Mustacchi 	/* Broadwell */
94*53548f91SRobert Mustacchi 	{ "BDW", "bdw", CPC_FILE_CORE },
95*53548f91SRobert Mustacchi 	{ "BDW-DE", "bdw_de", CPC_FILE_CORE },
96*53548f91SRobert Mustacchi 	{ "BDX", "bdx", CPC_FILE_CORE },
97*53548f91SRobert Mustacchi 	/* Skylake */
98*53548f91SRobert Mustacchi 	{ "SKL", "skl", CPC_FILE_CORE },
99*53548f91SRobert Mustacchi 	{ "SKX", "skx", CPC_FILE_CORE },
100*53548f91SRobert Mustacchi 	/* Atom */
101*53548f91SRobert Mustacchi 	{ "BNL", "bnl", CPC_FILE_CORE },
102*53548f91SRobert Mustacchi 	{ "SLM", "slm", CPC_FILE_CORE },
103*53548f91SRobert Mustacchi 	{ "GLM", "glm", CPC_FILE_CORE },
104*53548f91SRobert Mustacchi 	{ "GLP", "glp", CPC_FILE_CORE },
105*53548f91SRobert Mustacchi 	{ NULL }
106*53548f91SRobert Mustacchi };
107*53548f91SRobert Mustacchi 
108*53548f91SRobert Mustacchi typedef struct cpc_papi {
109*53548f91SRobert Mustacchi 	const char	*cpapi_intc;
110*53548f91SRobert Mustacchi 	const char	*cpapi_papi;
111*53548f91SRobert Mustacchi } cpc_papi_t;
112*53548f91SRobert Mustacchi 
113*53548f91SRobert Mustacchi /*
114*53548f91SRobert Mustacchi  * This table maps events with an Intel specific name to the corresponding PAPI
115*53548f91SRobert Mustacchi  * name. There may be multiple INtel events which map to the same PAPI event.
116*53548f91SRobert Mustacchi  * This is usually because different processors have different names for an
117*53548f91SRobert Mustacchi  * event. We use the title as opposed to the event codes because those can
118*53548f91SRobert Mustacchi  * change somewhat arbitrarily between processor generations.
119*53548f91SRobert Mustacchi  */
120*53548f91SRobert Mustacchi static cpc_papi_t cpcgen_papi_map[] = {
121*53548f91SRobert Mustacchi 	{ "CPU_CLK_UNHALTED.THREAD_P", "PAPI_tot_cyc" },
122*53548f91SRobert Mustacchi 	{ "INST_RETIRED.ANY_P", "PAPI_tot_ins" },
123*53548f91SRobert Mustacchi 	{ "BR_INST_RETIRED.ALL_BRANCHES", "PAPI_br_ins" },
124*53548f91SRobert Mustacchi 	{ "BR_MISP_RETIRED.ALL_BRANCHES", "PAPI_br_msp" },
125*53548f91SRobert Mustacchi 	{ "BR_INST_RETIRED.CONDITIONAL", "PAPI_br_cn" },
126*53548f91SRobert Mustacchi 	{ "CYCLE_ACTIVITY.CYCLES_L1D_MISS", "PAPI_l1_dcm" },
127*53548f91SRobert Mustacchi 	{ "L1I.HITS", "PAPI_l1_ich" },
128*53548f91SRobert Mustacchi 	{ "ICACHE.HIT", "PAPI_l1_ich" },
129*53548f91SRobert Mustacchi 	{ "L1I.MISS", "PAPI_L1_icm" },
130*53548f91SRobert Mustacchi 	{ "ICACHE.MISSES", "PAPI_l1_icm" },
131*53548f91SRobert Mustacchi 	{ "L1I.READS", "PAPI_l1_ica" },
132*53548f91SRobert Mustacchi 	{ "ICACHE.ACCESSES", "PAPI_l1_ica" },
133*53548f91SRobert Mustacchi 	{ "L1I.READS", "PAPI_l1_icr" },
134*53548f91SRobert Mustacchi 	{ "ICACHE.ACCESSES", "PAPI_l1_icr" },
135*53548f91SRobert Mustacchi 	{ "L2_RQSTS.CODE_RD_MISS", "PAPI_l2_icm" },
136*53548f91SRobert Mustacchi 	{ "L2_RQSTS.MISS", "PAPI_l2_tcm" },
137*53548f91SRobert Mustacchi 	{ "ITLB_MISSES.MISS_CAUSES_A_WALK", "PAPI_tlb_im" },
138*53548f91SRobert Mustacchi 	{ "DTLB_LOAD_MISSES.MISS_CAUSES_A_WALK", "PAPI_tlb_dm" },
139*53548f91SRobert Mustacchi 	{ "PAGE_WALKS.D_SIDE_WALKS", "PAPI_tlb_dm" },
140*53548f91SRobert Mustacchi 	{ "PAGE_WALKS.I_SIDE_WALKS", "PAPI_tlb_im" },
141*53548f91SRobert Mustacchi 	{ "PAGE_WALKS.WALKS", "PAPI_tlb_tl" },
142*53548f91SRobert Mustacchi 	{ "INST_QUEUE_WRITES", "PAPI_tot_iis" },
143*53548f91SRobert Mustacchi 	{ "MEM_INST_RETIRED.STORES" "PAPI_sr_ins" },
144*53548f91SRobert Mustacchi 	{ "MEM_INST_RETIRED.LOADS" "PAPI_ld_ins" },
145*53548f91SRobert Mustacchi 	{ NULL, NULL }
146*53548f91SRobert Mustacchi };
147*53548f91SRobert Mustacchi 
148*53548f91SRobert Mustacchi typedef struct cpcgen_ops {
149*53548f91SRobert Mustacchi 	char *(*cgen_op_name)(cpc_map_t *);
150*53548f91SRobert Mustacchi 	boolean_t (*cgen_op_file_before)(FILE *, cpc_map_t *);
151*53548f91SRobert Mustacchi 	boolean_t (*cgen_op_file_after)(FILE *, cpc_map_t *);
152*53548f91SRobert Mustacchi 	boolean_t (*cgen_op_event)(FILE *, nvlist_t *, const char *, uint32_t);
153*53548f91SRobert Mustacchi } cpcgen_ops_t;
154*53548f91SRobert Mustacchi 
155*53548f91SRobert Mustacchi static cpcgen_ops_t cpcgen_ops;
156*53548f91SRobert Mustacchi static const char *cpcgen_mapfile = "/mapfile.csv";
157*53548f91SRobert Mustacchi static const char *cpcgen_progname;
158*53548f91SRobert Mustacchi static cpc_map_t *cpcgen_maps;
159*53548f91SRobert Mustacchi 
160*53548f91SRobert Mustacchi /*
161*53548f91SRobert Mustacchi  * Constants used for generating data.
162*53548f91SRobert Mustacchi  */
163*53548f91SRobert Mustacchi /* BEGIN CSTYLED */
164*53548f91SRobert Mustacchi static const char *cpcgen_cfile_header = ""
165*53548f91SRobert Mustacchi "/*\n"
166*53548f91SRobert Mustacchi " *  Copyright (c) 2018, Intel Corporation\n"
167*53548f91SRobert Mustacchi " *  Copyright (c) 2018, Joyent, Inc\n"
168*53548f91SRobert Mustacchi " *  All rights reserved.\n"
169*53548f91SRobert Mustacchi " *\n"
170*53548f91SRobert Mustacchi " *  Redistribution and use in source and binary forms, with or without\n"
171*53548f91SRobert Mustacchi " *  modification, are permitted provided that the following conditions are met:\n"
172*53548f91SRobert Mustacchi " * \n"
173*53548f91SRobert Mustacchi " *   1. Redistributions of source code must retain the above copyright notice,\n"
174*53548f91SRobert Mustacchi " *      this list of conditions and the following disclaimer.\n"
175*53548f91SRobert Mustacchi " * \n"
176*53548f91SRobert Mustacchi " *   2. Redistributions in binary form must reproduce the above copyright \n"
177*53548f91SRobert Mustacchi " *      notice, this list of conditions and the following disclaimer in the\n"
178*53548f91SRobert Mustacchi " *      documentation and/or other materials provided with the distribution.\n"
179*53548f91SRobert Mustacchi " * \n"
180*53548f91SRobert Mustacchi " *   3. Neither the name of the Intel Corporation nor the names of its \n"
181*53548f91SRobert Mustacchi " *      contributors may be used to endorse or promote products derived from\n"
182*53548f91SRobert Mustacchi " *      this software without specific prior written permission.\n"
183*53548f91SRobert Mustacchi " *\n"
184*53548f91SRobert Mustacchi " *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n"
185*53548f91SRobert Mustacchi " *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n"
186*53548f91SRobert Mustacchi " *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
187*53548f91SRobert Mustacchi " *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n"
188*53548f91SRobert Mustacchi " *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n"
189*53548f91SRobert Mustacchi " *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n"
190*53548f91SRobert Mustacchi " *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n"
191*53548f91SRobert Mustacchi " *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n"
192*53548f91SRobert Mustacchi " *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n"
193*53548f91SRobert Mustacchi " *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n"
194*53548f91SRobert Mustacchi " *  POSSIBILITY OF SUCH DAMAGE.\n"
195*53548f91SRobert Mustacchi " *\n"
196*53548f91SRobert Mustacchi " * This file was automatically generated by cpcgen from the data file\n"
197*53548f91SRobert Mustacchi " * data/perfmon%s\n"
198*53548f91SRobert Mustacchi " *\n"
199*53548f91SRobert Mustacchi " * Do not modify this file. Your changes will be lost!\n"
200*53548f91SRobert Mustacchi " */\n"
201*53548f91SRobert Mustacchi "\n";
202*53548f91SRobert Mustacchi /* END CSTYLED */
203*53548f91SRobert Mustacchi 
204*53548f91SRobert Mustacchi static const char *cpcgen_cfile_table_start = ""
205*53548f91SRobert Mustacchi "#include <core_pcbe_table.h>\n"
206*53548f91SRobert Mustacchi "\n"
207*53548f91SRobert Mustacchi "const struct events_table_t pcbe_core_events_%s[] = {\n";
208*53548f91SRobert Mustacchi 
209*53548f91SRobert Mustacchi static const char *cpcgen_cfile_table_end = ""
210*53548f91SRobert Mustacchi "\t{ NT_END, 0, 0, \"\" }\n"
211*53548f91SRobert Mustacchi "};\n";
212*53548f91SRobert Mustacchi 
213*53548f91SRobert Mustacchi /* BEGIN CSTYLED */
214*53548f91SRobert Mustacchi static const char *cpcgen_manual_header = ""
215*53548f91SRobert Mustacchi ".\\\" Copyright (c) 2018, Intel Corporation \n"
216*53548f91SRobert Mustacchi ".\\\" Copyright (c) 2018, Joyent, Inc.\n"
217*53548f91SRobert Mustacchi ".\\\" All rights reserved.\n"
218*53548f91SRobert Mustacchi ".\\\"\n"
219*53548f91SRobert Mustacchi ".\\\" Redistribution and use in source and binary forms, with or without \n"
220*53548f91SRobert Mustacchi ".\\\" modification, are permitted provided that the following conditions are met:\n"
221*53548f91SRobert Mustacchi ".\\\"\n"
222*53548f91SRobert Mustacchi ".\\\"  1. Redistributions of source code must retain the above copyright notice,\n"
223*53548f91SRobert Mustacchi ".\\\"     this list of conditions and the following disclaimer.\n"
224*53548f91SRobert Mustacchi ".\\\"\n"
225*53548f91SRobert Mustacchi ".\\\"  2. Redistributions in binary form must reproduce the above copyright\n"
226*53548f91SRobert Mustacchi ".\\\"     notice, this list of conditions and the following disclaimer in the\n"
227*53548f91SRobert Mustacchi ".\\\"     documentation and/or other materials provided with the distribution.\n"
228*53548f91SRobert Mustacchi ".\\\"\n"
229*53548f91SRobert Mustacchi ".\\\"  3. Neither the name of the Intel Corporation nor the names of its\n"
230*53548f91SRobert Mustacchi ".\\\"     contributors may be used to endorse or promote products derived from\n"
231*53548f91SRobert Mustacchi ".\\\"     this software without specific prior written permission.\n"
232*53548f91SRobert Mustacchi ".\\\"\n"
233*53548f91SRobert Mustacchi ".\\\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n"
234*53548f91SRobert Mustacchi ".\\\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n"
235*53548f91SRobert Mustacchi ".\\\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
236*53548f91SRobert Mustacchi ".\\\" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n"
237*53548f91SRobert Mustacchi ".\\\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n"
238*53548f91SRobert Mustacchi ".\\\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n"
239*53548f91SRobert Mustacchi ".\\\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n"
240*53548f91SRobert Mustacchi ".\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n"
241*53548f91SRobert Mustacchi ".\\\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n"
242*53548f91SRobert Mustacchi ".\\\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n"
243*53548f91SRobert Mustacchi ".\\\" POSSIBILITY OF SUCH DAMAGE.\n"
244*53548f91SRobert Mustacchi ".\\\"\n"
245*53548f91SRobert Mustacchi ".\\\" This file was automatically generated by cpcgen from the data file\n"
246*53548f91SRobert Mustacchi ".\\\" data/perfmon%s\n"
247*53548f91SRobert Mustacchi ".\\\"\n"
248*53548f91SRobert Mustacchi ".\\\" Do not modify this file. Your changes will be lost!\n"
249*53548f91SRobert Mustacchi ".\\\"\n"
250*53548f91SRobert Mustacchi ".\\\" We would like to thank Intel for providing the perfmon data for use in\n"
251*53548f91SRobert Mustacchi ".\\\" our manual pages.\n"
252*53548f91SRobert Mustacchi ".Dd June 18, 2018\n"
253*53548f91SRobert Mustacchi ".Dt %s_EVENTS 3CPC\n"
254*53548f91SRobert Mustacchi ".Os\n"
255*53548f91SRobert Mustacchi ".Sh NAME\n"
256*53548f91SRobert Mustacchi ".Nm %s_events\n"
257*53548f91SRobert Mustacchi ".Nd processor model specific performance counter events\n"
258*53548f91SRobert Mustacchi ".Sh DESCRIPTION\n"
259*53548f91SRobert Mustacchi "This manual page describes events specific to the following Intel CPU\n"
260*53548f91SRobert Mustacchi "models and is derived from Intel's perfmon data.\n"
261*53548f91SRobert Mustacchi "For more information, please consult the Intel Software Developer's Manual "
262*53548f91SRobert Mustacchi "or Intel's perfmon website.\n"
263*53548f91SRobert Mustacchi ".Pp\n"
264*53548f91SRobert Mustacchi "CPU models described by this document:\n"
265*53548f91SRobert Mustacchi ".Bl -bullet\n";
266*53548f91SRobert Mustacchi /* END CSTYLED */
267*53548f91SRobert Mustacchi 
268*53548f91SRobert Mustacchi static const char *cpcgen_manual_data = ""
269*53548f91SRobert Mustacchi ".El\n"
270*53548f91SRobert Mustacchi ".Pp\n"
271*53548f91SRobert Mustacchi "The following events are supported:\n"
272*53548f91SRobert Mustacchi ".Bl -tag -width Sy\n";
273*53548f91SRobert Mustacchi 
274*53548f91SRobert Mustacchi static const char *cpcgen_manual_trailer = ""
275*53548f91SRobert Mustacchi ".El\n"
276*53548f91SRobert Mustacchi ".Sh SEE ALSO\n"
277*53548f91SRobert Mustacchi ".Xr cpc 3CPC\n"
278*53548f91SRobert Mustacchi ".Pp\n"
279*53548f91SRobert Mustacchi ".Lk https://download.01.org/perfmon/index/";
280*53548f91SRobert Mustacchi 
281*53548f91SRobert Mustacchi static cpc_map_t *
282*53548f91SRobert Mustacchi cpcgen_map_lookup(const char *path)
283*53548f91SRobert Mustacchi {
284*53548f91SRobert Mustacchi 	cpc_map_t *m;
285*53548f91SRobert Mustacchi 
286*53548f91SRobert Mustacchi 	for (m = cpcgen_maps; m != NULL; m = m->cmap_next) {
287*53548f91SRobert Mustacchi 		if (strcmp(path, m->cmap_path) == 0) {
288*53548f91SRobert Mustacchi 			return (m);
289*53548f91SRobert Mustacchi 		}
290*53548f91SRobert Mustacchi 	}
291*53548f91SRobert Mustacchi 
292*53548f91SRobert Mustacchi 	return (NULL);
293*53548f91SRobert Mustacchi }
294*53548f91SRobert Mustacchi 
295*53548f91SRobert Mustacchi /*
296*53548f91SRobert Mustacchi  * Parse a string of the form 'GenuineIntel-6-2E' and get out the family and
297*53548f91SRobert Mustacchi  * model.
298*53548f91SRobert Mustacchi  */
299*53548f91SRobert Mustacchi static void
300*53548f91SRobert Mustacchi cpcgen_parse_model(char *fsr, uint_t *family, uint_t *model)
301*53548f91SRobert Mustacchi {
302*53548f91SRobert Mustacchi 	const char *bstr = "GenuineIntel";
303*53548f91SRobert Mustacchi 	const char *brand, *fam, *mod;
304*53548f91SRobert Mustacchi 	char *last;
305*53548f91SRobert Mustacchi 	long l;
306*53548f91SRobert Mustacchi 
307*53548f91SRobert Mustacchi 	if ((brand = strtok_r(fsr, "-", &last)) == NULL ||
308*53548f91SRobert Mustacchi 	    (fam = strtok_r(NULL, "-", &last)) == NULL ||
309*53548f91SRobert Mustacchi 	    (mod = strtok_r(NULL, "-", &last)) == NULL) {
310*53548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse processor id \"%s\"", fsr);
311*53548f91SRobert Mustacchi 	}
312*53548f91SRobert Mustacchi 
313*53548f91SRobert Mustacchi 	if (strcmp(bstr, brand) != 0) {
314*53548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "brand string \"%s\" did not match \"%s\"",
315*53548f91SRobert Mustacchi 		    brand, bstr);
316*53548f91SRobert Mustacchi 	}
317*53548f91SRobert Mustacchi 
318*53548f91SRobert Mustacchi 	errno = 0;
319*53548f91SRobert Mustacchi 	l = strtol(fam, &last, 16);
320*53548f91SRobert Mustacchi 	if (errno != 0 || l < 0 || l > UINT_MAX || *last != '\0') {
321*53548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse family \"%s\"", fam);
322*53548f91SRobert Mustacchi 	}
323*53548f91SRobert Mustacchi 	*family = (uint_t)l;
324*53548f91SRobert Mustacchi 
325*53548f91SRobert Mustacchi 	l = strtol(mod, &last, 16);
326*53548f91SRobert Mustacchi 	if (errno != 0 || l < 0 || l > UINT_MAX || *last != '\0') {
327*53548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse model \"%s\"", mod);
328*53548f91SRobert Mustacchi 	}
329*53548f91SRobert Mustacchi 	*model = (uint_t)l;
330*53548f91SRobert Mustacchi }
331*53548f91SRobert Mustacchi 
332*53548f91SRobert Mustacchi static nvlist_t *
333*53548f91SRobert Mustacchi cpcgen_read_datafile(const char *datadir, const char *file)
334*53548f91SRobert Mustacchi {
335*53548f91SRobert Mustacchi 	int fd;
336*53548f91SRobert Mustacchi 	char *path;
337*53548f91SRobert Mustacchi 	struct stat st;
338*53548f91SRobert Mustacchi 	void *map;
339*53548f91SRobert Mustacchi 	nvlist_t *nvl;
340*53548f91SRobert Mustacchi 	nvlist_parse_json_error_t jerr;
341*53548f91SRobert Mustacchi 
342*53548f91SRobert Mustacchi 	if (asprintf(&path, "%s/%s", datadir, file) == -1) {
343*53548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct path to data file %s",
344*53548f91SRobert Mustacchi 		    file);
345*53548f91SRobert Mustacchi 	}
346*53548f91SRobert Mustacchi 
347*53548f91SRobert Mustacchi 	if ((fd = open(path, O_RDONLY)) < 0) {
348*53548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to open data file %s", path);
349*53548f91SRobert Mustacchi 	}
350*53548f91SRobert Mustacchi 
351*53548f91SRobert Mustacchi 	if (fstat(fd, &st) != 0) {
352*53548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to stat %s", path);
353*53548f91SRobert Mustacchi 	}
354*53548f91SRobert Mustacchi 
355*53548f91SRobert Mustacchi 	if ((map = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
356*53548f91SRobert Mustacchi 	    fd, 0)) == MAP_FAILED) {
357*53548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to mmap %s", path);
358*53548f91SRobert Mustacchi 	}
359*53548f91SRobert Mustacchi 
360*53548f91SRobert Mustacchi 	if (nvlist_parse_json(map, st.st_size, &nvl, NVJSON_FORCE_INTEGER,
361*53548f91SRobert Mustacchi 	    &jerr) != 0) {
362*53548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse file %s at pos %ld: %s",
363*53548f91SRobert Mustacchi 		    path, jerr.nje_pos, jerr.nje_message);
364*53548f91SRobert Mustacchi 	}
365*53548f91SRobert Mustacchi 
366*53548f91SRobert Mustacchi 	if (munmap(map, st.st_size) != 0) {
367*53548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to munmap %s", path);
368*53548f91SRobert Mustacchi 	}
369*53548f91SRobert Mustacchi 
370*53548f91SRobert Mustacchi 	if (close(fd) != 0) {
371*53548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to close data file %s", path);
372*53548f91SRobert Mustacchi 	}
373*53548f91SRobert Mustacchi 	free(path);
374*53548f91SRobert Mustacchi 
375*53548f91SRobert Mustacchi 	return (nvl);
376*53548f91SRobert Mustacchi }
377*53548f91SRobert Mustacchi 
378*53548f91SRobert Mustacchi /*
379*53548f91SRobert Mustacchi  * Check the whitelist to see if we should use this model.
380*53548f91SRobert Mustacchi  */
381*53548f91SRobert Mustacchi static const char *
382*53548f91SRobert Mustacchi cpcgen_use_arch(const char *path, cpc_type_t type, const char *platform)
383*53548f91SRobert Mustacchi {
384*53548f91SRobert Mustacchi 	const char *slash;
385*53548f91SRobert Mustacchi 	size_t len;
386*53548f91SRobert Mustacchi 	uint_t i;
387*53548f91SRobert Mustacchi 
388*53548f91SRobert Mustacchi 	if (*path != '/') {
389*53548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "invalid path in mapfile: \"%s\": missing "
390*53548f91SRobert Mustacchi 		    "leading '/'", path);
391*53548f91SRobert Mustacchi 	}
392*53548f91SRobert Mustacchi 	if ((slash = strchr(path + 1, '/')) == NULL) {
393*53548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "invalid path in mapfile: \"%s\": missing "
394*53548f91SRobert Mustacchi 		    "second '/'", path);
395*53548f91SRobert Mustacchi 	}
396*53548f91SRobert Mustacchi 	/* Account for the last '/' character. */
397*53548f91SRobert Mustacchi 	len = slash - path - 1;
398*53548f91SRobert Mustacchi 	assert(len > 0);
399*53548f91SRobert Mustacchi 
400*53548f91SRobert Mustacchi 	for (i = 0; cpcgen_whitelist[i].cwhite_short != NULL; i++) {
401*53548f91SRobert Mustacchi 		if (platform != NULL && strcasecmp(platform,
402*53548f91SRobert Mustacchi 		    cpcgen_whitelist[i].cwhite_short) != 0)
403*53548f91SRobert Mustacchi 			continue;
404*53548f91SRobert Mustacchi 		if (strncmp(path + 1, cpcgen_whitelist[i].cwhite_short,
405*53548f91SRobert Mustacchi 		    len) == 0 &&
406*53548f91SRobert Mustacchi 		    (cpcgen_whitelist[i].cwhite_mask & type) == type) {
407*53548f91SRobert Mustacchi 			return (cpcgen_whitelist[i].cwhite_human);
408*53548f91SRobert Mustacchi 		}
409*53548f91SRobert Mustacchi 	}
410*53548f91SRobert Mustacchi 
411*53548f91SRobert Mustacchi 	return (NULL);
412*53548f91SRobert Mustacchi }
413*53548f91SRobert Mustacchi 
414*53548f91SRobert Mustacchi /*
415*53548f91SRobert Mustacchi  * Read in the mapfile.csv that is used to map between processor families and
416*53548f91SRobert Mustacchi  * parse this. Each line has a comma separated value.
417*53548f91SRobert Mustacchi  */
418*53548f91SRobert Mustacchi static void
419*53548f91SRobert Mustacchi cpcgen_read_mapfile(const char *datadir, const char *platform)
420*53548f91SRobert Mustacchi {
421*53548f91SRobert Mustacchi 	FILE *map;
422*53548f91SRobert Mustacchi 	char *mappath, *last;
423*53548f91SRobert Mustacchi 	char *data = NULL;
424*53548f91SRobert Mustacchi 	size_t datalen = 0;
425*53548f91SRobert Mustacchi 	uint_t lineno;
426*53548f91SRobert Mustacchi 
427*53548f91SRobert Mustacchi 	if (asprintf(&mappath, "%s/%s", datadir, cpcgen_mapfile) == -1) {
428*53548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct path to mapfile");
429*53548f91SRobert Mustacchi 	}
430*53548f91SRobert Mustacchi 
431*53548f91SRobert Mustacchi 	if ((map = fopen(mappath, "r")) == NULL) {
432*53548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to open data mapfile %s", mappath);
433*53548f91SRobert Mustacchi 	}
434*53548f91SRobert Mustacchi 
435*53548f91SRobert Mustacchi 	lineno = 0;
436*53548f91SRobert Mustacchi 	while (getline(&data, &datalen, map) != -1) {
437*53548f91SRobert Mustacchi 		char *fstr, *path, *tstr;
438*53548f91SRobert Mustacchi 		const char *name;
439*53548f91SRobert Mustacchi 		uint_t family, model;
440*53548f91SRobert Mustacchi 		cpc_type_t type;
441*53548f91SRobert Mustacchi 		cpc_map_t *map;
442*53548f91SRobert Mustacchi 		cpc_proc_t *proc;
443*53548f91SRobert Mustacchi 
444*53548f91SRobert Mustacchi 		/*
445*53548f91SRobert Mustacchi 		 * The first line contains the header:
446*53548f91SRobert Mustacchi 		 * Family-model,Version,Filename,EventType
447*53548f91SRobert Mustacchi 		 */
448*53548f91SRobert Mustacchi 		lineno++;
449*53548f91SRobert Mustacchi 		if (lineno == 1) {
450*53548f91SRobert Mustacchi 			continue;
451*53548f91SRobert Mustacchi 		}
452*53548f91SRobert Mustacchi 
453*53548f91SRobert Mustacchi 		if ((fstr = strtok_r(data, ",", &last)) == NULL ||
454*53548f91SRobert Mustacchi 		    strtok_r(NULL, ",", &last) == NULL ||
455*53548f91SRobert Mustacchi 		    (path = strtok_r(NULL, ",", &last)) == NULL ||
456*53548f91SRobert Mustacchi 		    (tstr = strtok_r(NULL, "\n", &last)) == NULL) {
457*53548f91SRobert Mustacchi 			errx(EXIT_FAILURE, "failed to parse mapfile line "
458*53548f91SRobert Mustacchi 			    "%u in %s", lineno, mappath);
459*53548f91SRobert Mustacchi 		}
460*53548f91SRobert Mustacchi 
461*53548f91SRobert Mustacchi 		cpcgen_parse_model(fstr, &family, &model);
462*53548f91SRobert Mustacchi 
463*53548f91SRobert Mustacchi 		if (strcmp(tstr, "core") == 0) {
464*53548f91SRobert Mustacchi 			type = CPC_FILE_CORE;
465*53548f91SRobert Mustacchi 		} else if (strcmp(tstr, "offcore") == 0) {
466*53548f91SRobert Mustacchi 			type = CPC_FILE_OFF_CORE;
467*53548f91SRobert Mustacchi 		} else if (strcmp(tstr, "uncore") == 0) {
468*53548f91SRobert Mustacchi 			type = CPC_FILE_UNCORE;
469*53548f91SRobert Mustacchi 		} else if (strcmp(tstr, "fp_arith_inst") == 0) {
470*53548f91SRobert Mustacchi 			type = CPC_FILE_FP_MATH;
471*53548f91SRobert Mustacchi 		} else if (strcmp(tstr, "uncore experimental") == 0) {
472*53548f91SRobert Mustacchi 			type = CPC_FILE_UNCORE_EXP;
473*53548f91SRobert Mustacchi 		} else {
474*53548f91SRobert Mustacchi 			errx(EXIT_FAILURE, "unknown file type \"%s\" on line "
475*53548f91SRobert Mustacchi 			    "%u", tstr, lineno);
476*53548f91SRobert Mustacchi 		}
477*53548f91SRobert Mustacchi 
478*53548f91SRobert Mustacchi 		if ((name = cpcgen_use_arch(path, type, platform)) == NULL)
479*53548f91SRobert Mustacchi 			continue;
480*53548f91SRobert Mustacchi 
481*53548f91SRobert Mustacchi 		if ((map = cpcgen_map_lookup(path)) == NULL) {
482*53548f91SRobert Mustacchi 			nvlist_t *parsed;
483*53548f91SRobert Mustacchi 
484*53548f91SRobert Mustacchi 			parsed = cpcgen_read_datafile(datadir, path);
485*53548f91SRobert Mustacchi 
486*53548f91SRobert Mustacchi 			if ((map = calloc(1, sizeof (cpc_map_t))) == NULL) {
487*53548f91SRobert Mustacchi 				err(EXIT_FAILURE, "failed to allocate space "
488*53548f91SRobert Mustacchi 				    "for cpc file");
489*53548f91SRobert Mustacchi 			}
490*53548f91SRobert Mustacchi 
491*53548f91SRobert Mustacchi 			if ((map->cmap_path = strdup(path)) == NULL) {
492*53548f91SRobert Mustacchi 				err(EXIT_FAILURE, "failed to duplicate path "
493*53548f91SRobert Mustacchi 				    "string");
494*53548f91SRobert Mustacchi 			}
495*53548f91SRobert Mustacchi 
496*53548f91SRobert Mustacchi 			map->cmap_type = type;
497*53548f91SRobert Mustacchi 			map->cmap_data = parsed;
498*53548f91SRobert Mustacchi 			map->cmap_next = cpcgen_maps;
499*53548f91SRobert Mustacchi 			map->cmap_name = name;
500*53548f91SRobert Mustacchi 			cpcgen_maps = map;
501*53548f91SRobert Mustacchi 		}
502*53548f91SRobert Mustacchi 
503*53548f91SRobert Mustacchi 		if ((proc = malloc(sizeof (cpc_proc_t))) == NULL) {
504*53548f91SRobert Mustacchi 			err(EXIT_FAILURE, "failed to allocate memory for "
505*53548f91SRobert Mustacchi 			    "family and model tracking");
506*53548f91SRobert Mustacchi 		}
507*53548f91SRobert Mustacchi 
508*53548f91SRobert Mustacchi 		proc->cproc_family = family;
509*53548f91SRobert Mustacchi 		proc->cproc_model = model;
510*53548f91SRobert Mustacchi 		proc->cproc_next = map->cmap_procs;
511*53548f91SRobert Mustacchi 		map->cmap_procs = proc;
512*53548f91SRobert Mustacchi 	}
513*53548f91SRobert Mustacchi 
514*53548f91SRobert Mustacchi 	if (errno != 0 || ferror(map)) {
515*53548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to read %s", mappath);
516*53548f91SRobert Mustacchi 	}
517*53548f91SRobert Mustacchi 
518*53548f91SRobert Mustacchi 	if (fclose(map) == EOF) {
519*53548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to close %s", mappath);
520*53548f91SRobert Mustacchi 	}
521*53548f91SRobert Mustacchi 	free(data);
522*53548f91SRobert Mustacchi 	free(mappath);
523*53548f91SRobert Mustacchi }
524*53548f91SRobert Mustacchi 
525*53548f91SRobert Mustacchi static char *
526*53548f91SRobert Mustacchi cpcgen_manual_name(cpc_map_t *map)
527*53548f91SRobert Mustacchi {
528*53548f91SRobert Mustacchi 	char *name;
529*53548f91SRobert Mustacchi 
530*53548f91SRobert Mustacchi 	if (asprintf(&name, "%s_events.3cpc", map->cmap_name) == -1) {
531*53548f91SRobert Mustacchi 		warn("failed to assemble manual page name for %s",
532*53548f91SRobert Mustacchi 		    map->cmap_path);
533*53548f91SRobert Mustacchi 		return (NULL);
534*53548f91SRobert Mustacchi 	}
535*53548f91SRobert Mustacchi 
536*53548f91SRobert Mustacchi 	return (name);
537*53548f91SRobert Mustacchi }
538*53548f91SRobert Mustacchi 
539*53548f91SRobert Mustacchi static boolean_t
540*53548f91SRobert Mustacchi cpcgen_manual_file_before(FILE *f, cpc_map_t *map)
541*53548f91SRobert Mustacchi {
542*53548f91SRobert Mustacchi 	size_t i;
543*53548f91SRobert Mustacchi 	char *upper;
544*53548f91SRobert Mustacchi 	cpc_proc_t *proc;
545*53548f91SRobert Mustacchi 
546*53548f91SRobert Mustacchi 	if ((upper = strdup(map->cmap_name)) == NULL) {
547*53548f91SRobert Mustacchi 		warn("failed to duplicate manual name for %s", map->cmap_name);
548*53548f91SRobert Mustacchi 		return (B_FALSE);
549*53548f91SRobert Mustacchi 	}
550*53548f91SRobert Mustacchi 
551*53548f91SRobert Mustacchi 	for (i = 0; upper[i] != '\0'; i++) {
552*53548f91SRobert Mustacchi 		upper[i] = toupper(upper[i]);
553*53548f91SRobert Mustacchi 	}
554*53548f91SRobert Mustacchi 
555*53548f91SRobert Mustacchi 	if (fprintf(f, cpcgen_manual_header, map->cmap_path, upper,
556*53548f91SRobert Mustacchi 	    map->cmap_name) == -1) {
557*53548f91SRobert Mustacchi 		warn("failed to write out manual header for %s",
558*53548f91SRobert Mustacchi 		    map->cmap_name);
559*53548f91SRobert Mustacchi 		free(upper);
560*53548f91SRobert Mustacchi 		return (B_FALSE);
561*53548f91SRobert Mustacchi 	}
562*53548f91SRobert Mustacchi 
563*53548f91SRobert Mustacchi 	for (proc = map->cmap_procs; proc != NULL; proc = proc->cproc_next) {
564*53548f91SRobert Mustacchi 		if (fprintf(f, ".It\n.Sy Family 0x%x, Model 0x%x\n",
565*53548f91SRobert Mustacchi 		    proc->cproc_family, proc->cproc_model) == -1) {
566*53548f91SRobert Mustacchi 			warn("failed to write out model information for %s",
567*53548f91SRobert Mustacchi 			    map->cmap_name);
568*53548f91SRobert Mustacchi 			free(upper);
569*53548f91SRobert Mustacchi 			return (B_FALSE);
570*53548f91SRobert Mustacchi 		}
571*53548f91SRobert Mustacchi 	}
572*53548f91SRobert Mustacchi 
573*53548f91SRobert Mustacchi 	if (fprintf(f, cpcgen_manual_data, map->cmap_path, upper,
574*53548f91SRobert Mustacchi 	    map->cmap_name) == -1) {
575*53548f91SRobert Mustacchi 		warn("failed to write out manual header for %s",
576*53548f91SRobert Mustacchi 		    map->cmap_name);
577*53548f91SRobert Mustacchi 		free(upper);
578*53548f91SRobert Mustacchi 		return (B_FALSE);
579*53548f91SRobert Mustacchi 	}
580*53548f91SRobert Mustacchi 
581*53548f91SRobert Mustacchi 	free(upper);
582*53548f91SRobert Mustacchi 	return (B_TRUE);
583*53548f91SRobert Mustacchi }
584*53548f91SRobert Mustacchi 
585*53548f91SRobert Mustacchi static boolean_t
586*53548f91SRobert Mustacchi cpcgen_manual_file_after(FILE *f, cpc_map_t *map)
587*53548f91SRobert Mustacchi {
588*53548f91SRobert Mustacchi 	if (fprintf(f, cpcgen_manual_trailer) == -1) {
589*53548f91SRobert Mustacchi 		warn("failed to write out manual header for %s",
590*53548f91SRobert Mustacchi 		    map->cmap_name);
591*53548f91SRobert Mustacchi 		return (B_FALSE);
592*53548f91SRobert Mustacchi 	}
593*53548f91SRobert Mustacchi 
594*53548f91SRobert Mustacchi 	return (B_TRUE);
595*53548f91SRobert Mustacchi }
596*53548f91SRobert Mustacchi 
597*53548f91SRobert Mustacchi static boolean_t
598*53548f91SRobert Mustacchi cpcgen_manual_event(FILE *f, nvlist_t *nvl, const char *path, uint32_t ent)
599*53548f91SRobert Mustacchi {
600*53548f91SRobert Mustacchi 	char *event, *lname, *brief = NULL, *public = NULL, *errata = NULL;
601*53548f91SRobert Mustacchi 	size_t i;
602*53548f91SRobert Mustacchi 
603*53548f91SRobert Mustacchi 	if (nvlist_lookup_string(nvl, "EventName", &event) != 0) {
604*53548f91SRobert Mustacchi 		warnx("Found event without 'EventName' property "
605*53548f91SRobert Mustacchi 		    "in %s, entry %u", path, ent);
606*53548f91SRobert Mustacchi 		return (B_FALSE);
607*53548f91SRobert Mustacchi 	}
608*53548f91SRobert Mustacchi 
609*53548f91SRobert Mustacchi 	/*
610*53548f91SRobert Mustacchi 	 * Intel uses capital names. CPC historically uses lower case names.
611*53548f91SRobert Mustacchi 	 */
612*53548f91SRobert Mustacchi 	if ((lname = strdup(event)) == NULL) {
613*53548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to duplicate event name %s", event);
614*53548f91SRobert Mustacchi 	}
615*53548f91SRobert Mustacchi 	for (i = 0; lname[i] != '\0'; i++) {
616*53548f91SRobert Mustacchi 		lname[i] = tolower(event[i]);
617*53548f91SRobert Mustacchi 	}
618*53548f91SRobert Mustacchi 
619*53548f91SRobert Mustacchi 	/*
620*53548f91SRobert Mustacchi 	 * Try to get the other event fields, but if they're not there, don't
621*53548f91SRobert Mustacchi 	 * worry about it.
622*53548f91SRobert Mustacchi 	 */
623*53548f91SRobert Mustacchi 	(void) nvlist_lookup_string(nvl, "BriefDescription", &brief);
624*53548f91SRobert Mustacchi 	(void) nvlist_lookup_string(nvl, "PublicDescription", &public);
625*53548f91SRobert Mustacchi 	(void) nvlist_lookup_string(nvl, "Errata", &errata);
626*53548f91SRobert Mustacchi 	if (errata != NULL && (strcmp(errata, "0") == 0 ||
627*53548f91SRobert Mustacchi 	    strcmp(errata, "null") == 0)) {
628*53548f91SRobert Mustacchi 		errata = NULL;
629*53548f91SRobert Mustacchi 	}
630*53548f91SRobert Mustacchi 
631*53548f91SRobert Mustacchi 	if (fprintf(f, ".It Sy %s\n", lname) == -1) {
632*53548f91SRobert Mustacchi 		warn("failed to write out probe entry %s", event);
633*53548f91SRobert Mustacchi 		free(lname);
634*53548f91SRobert Mustacchi 		return (B_FALSE);
635*53548f91SRobert Mustacchi 	}
636*53548f91SRobert Mustacchi 
637*53548f91SRobert Mustacchi 	if (public != NULL) {
638*53548f91SRobert Mustacchi 		if (fprintf(f, "%s\n", public) == -1) {
639*53548f91SRobert Mustacchi 			warn("failed to write out probe entry %s", event);
640*53548f91SRobert Mustacchi 			free(lname);
641*53548f91SRobert Mustacchi 			return (B_FALSE);
642*53548f91SRobert Mustacchi 		}
643*53548f91SRobert Mustacchi 	} else if (brief != NULL) {
644*53548f91SRobert Mustacchi 		if (fprintf(f, "%s\n", brief) == -1) {
645*53548f91SRobert Mustacchi 			warn("failed to write out probe entry %s", event);
646*53548f91SRobert Mustacchi 			free(lname);
647*53548f91SRobert Mustacchi 			return (B_FALSE);
648*53548f91SRobert Mustacchi 		}
649*53548f91SRobert Mustacchi 	}
650*53548f91SRobert Mustacchi 
651*53548f91SRobert Mustacchi 	if (errata != NULL) {
652*53548f91SRobert Mustacchi 		if (fprintf(f, ".Pp\nThe following errata may apply to this: "
653*53548f91SRobert Mustacchi 		    "%s\n", errata) == -1) {
654*53548f91SRobert Mustacchi 
655*53548f91SRobert Mustacchi 			warn("failed to write out probe entry %s", event);
656*53548f91SRobert Mustacchi 			free(lname);
657*53548f91SRobert Mustacchi 			return (B_FALSE);
658*53548f91SRobert Mustacchi 		}
659*53548f91SRobert Mustacchi 	}
660*53548f91SRobert Mustacchi 
661*53548f91SRobert Mustacchi 	free(lname);
662*53548f91SRobert Mustacchi 	return (B_TRUE);
663*53548f91SRobert Mustacchi }
664*53548f91SRobert Mustacchi 
665*53548f91SRobert Mustacchi static char *
666*53548f91SRobert Mustacchi cpcgen_cfile_name(cpc_map_t *map)
667*53548f91SRobert Mustacchi {
668*53548f91SRobert Mustacchi 	char *name;
669*53548f91SRobert Mustacchi 
670*53548f91SRobert Mustacchi 	if (asprintf(&name, "core_pcbe_%s.c", map->cmap_name) == -1) {
671*53548f91SRobert Mustacchi 		warn("failed to assemble file name for %s", map->cmap_path);
672*53548f91SRobert Mustacchi 		return (NULL);
673*53548f91SRobert Mustacchi 	}
674*53548f91SRobert Mustacchi 
675*53548f91SRobert Mustacchi 	return (name);
676*53548f91SRobert Mustacchi }
677*53548f91SRobert Mustacchi 
678*53548f91SRobert Mustacchi static boolean_t
679*53548f91SRobert Mustacchi cpcgen_cfile_file_before(FILE *f, cpc_map_t *map)
680*53548f91SRobert Mustacchi {
681*53548f91SRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_header, map->cmap_path) == -1) {
682*53548f91SRobert Mustacchi 		warn("failed to write header to temporary file for %s",
683*53548f91SRobert Mustacchi 		    map->cmap_path);
684*53548f91SRobert Mustacchi 		return (B_FALSE);
685*53548f91SRobert Mustacchi 	}
686*53548f91SRobert Mustacchi 
687*53548f91SRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_table_start, map->cmap_name) == -1) {
688*53548f91SRobert Mustacchi 		warn("failed to write header to temporary file for %s",
689*53548f91SRobert Mustacchi 		    map->cmap_path);
690*53548f91SRobert Mustacchi 		return (B_FALSE);
691*53548f91SRobert Mustacchi 	}
692*53548f91SRobert Mustacchi 
693*53548f91SRobert Mustacchi 	return (B_TRUE);
694*53548f91SRobert Mustacchi }
695*53548f91SRobert Mustacchi 
696*53548f91SRobert Mustacchi static boolean_t
697*53548f91SRobert Mustacchi cpcgen_cfile_file_after(FILE *f, cpc_map_t *map)
698*53548f91SRobert Mustacchi {
699*53548f91SRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_table_end) == -1) {
700*53548f91SRobert Mustacchi 		warn("failed to write footer to temporary file for %s",
701*53548f91SRobert Mustacchi 		    map->cmap_path);
702*53548f91SRobert Mustacchi 		return (B_FALSE);
703*53548f91SRobert Mustacchi 	}
704*53548f91SRobert Mustacchi 
705*53548f91SRobert Mustacchi 	return (B_TRUE);
706*53548f91SRobert Mustacchi }
707*53548f91SRobert Mustacchi 
708*53548f91SRobert Mustacchi static boolean_t
709*53548f91SRobert Mustacchi cpcgen_cfile_event(FILE *f, nvlist_t *nvl, const char *path, uint_t ent)
710*53548f91SRobert Mustacchi {
711*53548f91SRobert Mustacchi 	char *ecode, *umask, *name, *counter, *lname, *cmask;
712*53548f91SRobert Mustacchi 	size_t i;
713*53548f91SRobert Mustacchi 
714*53548f91SRobert Mustacchi 	if (nvlist_lookup_string(nvl, "EventName", &name) != 0) {
715*53548f91SRobert Mustacchi 		warnx("Found event without 'EventName' property "
716*53548f91SRobert Mustacchi 		    "in %s, entry %u", path, ent);
717*53548f91SRobert Mustacchi 		return (B_FALSE);
718*53548f91SRobert Mustacchi 	}
719*53548f91SRobert Mustacchi 
720*53548f91SRobert Mustacchi 	if (nvlist_lookup_string(nvl, "EventCode", &ecode) != 0 ||
721*53548f91SRobert Mustacchi 	    nvlist_lookup_string(nvl, "UMask", &umask) != 0 ||
722*53548f91SRobert Mustacchi 	    nvlist_lookup_string(nvl, "Counter", &counter) != 0) {
723*53548f91SRobert Mustacchi 		warnx("event %s (index %u) from %s, missing "
724*53548f91SRobert Mustacchi 		    "required properties for C file translation",
725*53548f91SRobert Mustacchi 		    name, ent, path);
726*53548f91SRobert Mustacchi 		return (B_FALSE);
727*53548f91SRobert Mustacchi 	}
728*53548f91SRobert Mustacchi 
729*53548f91SRobert Mustacchi 	/*
730*53548f91SRobert Mustacchi 	 * While we could try and parse the counters manually, just do this the
731*53548f91SRobert Mustacchi 	 * max power way for now based on all possible values.
732*53548f91SRobert Mustacchi 	 */
733*53548f91SRobert Mustacchi 	if (strcmp(counter, "0") == 0 || strcmp(counter, "0,") == 0) {
734*53548f91SRobert Mustacchi 		cmask = "C0";
735*53548f91SRobert Mustacchi 	} else if (strcmp(counter, "1") == 0) {
736*53548f91SRobert Mustacchi 		cmask = "C1";
737*53548f91SRobert Mustacchi 	} else if (strcmp(counter, "2") == 0) {
738*53548f91SRobert Mustacchi 		cmask = "C2";
739*53548f91SRobert Mustacchi 	} else if (strcmp(counter, "3") == 0) {
740*53548f91SRobert Mustacchi 		cmask = "C3";
741*53548f91SRobert Mustacchi 	} else if (strcmp(counter, "0,1") == 0) {
742*53548f91SRobert Mustacchi 		cmask = "C0|C1";
743*53548f91SRobert Mustacchi 	} else if (strcmp(counter, "0,1,2") == 0) {
744*53548f91SRobert Mustacchi 		cmask = "C0|C1|C2";
745*53548f91SRobert Mustacchi 	} else if (strcmp(counter, "0,1,2,3") == 0) {
746*53548f91SRobert Mustacchi 		cmask = "C0|C1|C2|C3";
747*53548f91SRobert Mustacchi 	} else if (strcmp(counter, "0,2,3") == 0) {
748*53548f91SRobert Mustacchi 		cmask = "C0|C2|C3";
749*53548f91SRobert Mustacchi 	} else if (strcmp(counter, "1,2,3") == 0) {
750*53548f91SRobert Mustacchi 		cmask = "C1|C2|C3";
751*53548f91SRobert Mustacchi 	} else if (strcmp(counter, "2,3") == 0) {
752*53548f91SRobert Mustacchi 		cmask = "C2|C3";
753*53548f91SRobert Mustacchi 	} else {
754*53548f91SRobert Mustacchi 		warnx("event %s (index %u) from %s, has unknown "
755*53548f91SRobert Mustacchi 		    "counter value \"%s\"", name, ent, path, counter);
756*53548f91SRobert Mustacchi 		return (B_FALSE);
757*53548f91SRobert Mustacchi 	}
758*53548f91SRobert Mustacchi 
759*53548f91SRobert Mustacchi 
760*53548f91SRobert Mustacchi 	/*
761*53548f91SRobert Mustacchi 	 * Intel uses capital names. CPC historically uses lower case names.
762*53548f91SRobert Mustacchi 	 */
763*53548f91SRobert Mustacchi 	if ((lname = strdup(name)) == NULL) {
764*53548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to duplicate event name %s", name);
765*53548f91SRobert Mustacchi 	}
766*53548f91SRobert Mustacchi 	for (i = 0; lname[i] != '\0'; i++) {
767*53548f91SRobert Mustacchi 		lname[i] = tolower(name[i]);
768*53548f91SRobert Mustacchi 	}
769*53548f91SRobert Mustacchi 
770*53548f91SRobert Mustacchi 	if (fprintf(f, "\t{ %s, %s, %s, \"%s\" },\n", ecode, umask, cmask,
771*53548f91SRobert Mustacchi 	    lname) == -1) {
772*53548f91SRobert Mustacchi 		warn("failed to write out entry %s from %s", name, path);
773*53548f91SRobert Mustacchi 		free(lname);
774*53548f91SRobert Mustacchi 		return (B_FALSE);
775*53548f91SRobert Mustacchi 	}
776*53548f91SRobert Mustacchi 
777*53548f91SRobert Mustacchi 	free(lname);
778*53548f91SRobert Mustacchi 
779*53548f91SRobert Mustacchi 	/*
780*53548f91SRobert Mustacchi 	 * Check if we have any PAPI aliases.
781*53548f91SRobert Mustacchi 	 */
782*53548f91SRobert Mustacchi 	for (i = 0; cpcgen_papi_map[i].cpapi_intc != NULL; i++) {
783*53548f91SRobert Mustacchi 		if (strcmp(name, cpcgen_papi_map[i].cpapi_intc) != 0)
784*53548f91SRobert Mustacchi 			continue;
785*53548f91SRobert Mustacchi 
786*53548f91SRobert Mustacchi 		if (fprintf(f, "\t{ %s, %s, %s, \"%s\" },\n", ecode, umask,
787*53548f91SRobert Mustacchi 		    cmask, cpcgen_papi_map[i].cpapi_papi) == -1) {
788*53548f91SRobert Mustacchi 			warn("failed to write out entry %s from %s", name,
789*53548f91SRobert Mustacchi 			    path);
790*53548f91SRobert Mustacchi 			return (B_FALSE);
791*53548f91SRobert Mustacchi 		}
792*53548f91SRobert Mustacchi 	}
793*53548f91SRobert Mustacchi 
794*53548f91SRobert Mustacchi 	return (B_TRUE);
795*53548f91SRobert Mustacchi }
796*53548f91SRobert Mustacchi 
797*53548f91SRobert Mustacchi /*
798*53548f91SRobert Mustacchi  * Generate a header file that declares all of these arrays and provide a map
799*53548f91SRobert Mustacchi  * for models to the corresponding table to use.
800*53548f91SRobert Mustacchi  */
801*53548f91SRobert Mustacchi static void
802*53548f91SRobert Mustacchi cpcgen_common_files(int dirfd)
803*53548f91SRobert Mustacchi {
804*53548f91SRobert Mustacchi 	const char *fname = "core_pcbe_cpcgen.h";
805*53548f91SRobert Mustacchi 	char *tmpname;
806*53548f91SRobert Mustacchi 	int fd;
807*53548f91SRobert Mustacchi 	FILE *f;
808*53548f91SRobert Mustacchi 	cpc_map_t *map;
809*53548f91SRobert Mustacchi 
810*53548f91SRobert Mustacchi 	if (asprintf(&tmpname, ".%s.%d", fname, getpid()) == -1) {
811*53548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct temporary file name");
812*53548f91SRobert Mustacchi 	}
813*53548f91SRobert Mustacchi 
814*53548f91SRobert Mustacchi 	if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0644)) < 0) {
815*53548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to create temporary file %s",
816*53548f91SRobert Mustacchi 		    tmpname);
817*53548f91SRobert Mustacchi 	}
818*53548f91SRobert Mustacchi 
819*53548f91SRobert Mustacchi 	if ((f = fdopen(fd, "w")) == NULL) {
820*53548f91SRobert Mustacchi 		int e = errno;
821*53548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
822*53548f91SRobert Mustacchi 		errno = e;
823*53548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to fdopen temporary file");
824*53548f91SRobert Mustacchi 	}
825*53548f91SRobert Mustacchi 
826*53548f91SRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_header, cpcgen_mapfile) == -1) {
827*53548f91SRobert Mustacchi 		int e = errno;
828*53548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
829*53548f91SRobert Mustacchi 		errno = e;
830*53548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to temporary file "
831*53548f91SRobert Mustacchi 		    "for %s", fname);
832*53548f91SRobert Mustacchi 	}
833*53548f91SRobert Mustacchi 
834*53548f91SRobert Mustacchi 	if (fprintf(f, "#ifndef _CORE_PCBE_CPCGEN_H\n"
835*53548f91SRobert Mustacchi 	    "#define\t_CORE_PCBE_CPCGEN_H\n"
836*53548f91SRobert Mustacchi 	    "\n"
837*53548f91SRobert Mustacchi 	    "#ifdef __cplusplus\n"
838*53548f91SRobert Mustacchi 	    "extern \"C\" {\n"
839*53548f91SRobert Mustacchi 	    "#endif\n"
840*53548f91SRobert Mustacchi 	    "\n"
841*53548f91SRobert Mustacchi 	    "extern const struct events_table_t *core_cpcgen_table(uint_t);\n"
842*53548f91SRobert Mustacchi 	    "\n") == -1) {
843*53548f91SRobert Mustacchi 		int e = errno;
844*53548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
845*53548f91SRobert Mustacchi 		errno = e;
846*53548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to "
847*53548f91SRobert Mustacchi 		    "temporary file for %s", fname);
848*53548f91SRobert Mustacchi 	}
849*53548f91SRobert Mustacchi 
850*53548f91SRobert Mustacchi 	for (map = cpcgen_maps; map != NULL; map = map->cmap_next) {
851*53548f91SRobert Mustacchi 		if (fprintf(f, "extern const struct events_table_t "
852*53548f91SRobert Mustacchi 		    "pcbe_core_events_%s[];\n", map->cmap_name) == -1) {
853*53548f91SRobert Mustacchi 			int e = errno;
854*53548f91SRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
855*53548f91SRobert Mustacchi 			errno = e;
856*53548f91SRobert Mustacchi 			errx(EXIT_FAILURE, "failed to write entry to "
857*53548f91SRobert Mustacchi 			    "temporary file for %s", fname);
858*53548f91SRobert Mustacchi 		}
859*53548f91SRobert Mustacchi 	}
860*53548f91SRobert Mustacchi 
861*53548f91SRobert Mustacchi 	if (fprintf(f, "\n"
862*53548f91SRobert Mustacchi 	    "#ifdef __cplusplus\n"
863*53548f91SRobert Mustacchi 	    "}\n"
864*53548f91SRobert Mustacchi 	    "#endif\n"
865*53548f91SRobert Mustacchi 	    "\n"
866*53548f91SRobert Mustacchi 	    "#endif /* _CORE_PCBE_CPCGEN_H */\n") == -1) {
867*53548f91SRobert Mustacchi 		int e = errno;
868*53548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
869*53548f91SRobert Mustacchi 		errno = e;
870*53548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to "
871*53548f91SRobert Mustacchi 		    "temporary file for %s", fname);
872*53548f91SRobert Mustacchi 	}
873*53548f91SRobert Mustacchi 
874*53548f91SRobert Mustacchi 	if (fflush(f) != 0 || fclose(f) != 0) {
875*53548f91SRobert Mustacchi 		int e = errno;
876*53548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
877*53548f91SRobert Mustacchi 		errno = e;
878*53548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to flush and close temporary file");
879*53548f91SRobert Mustacchi 	}
880*53548f91SRobert Mustacchi 
881*53548f91SRobert Mustacchi 	if (renameat(dirfd, tmpname, dirfd, fname) != 0) {
882*53548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to rename temporary file %s",
883*53548f91SRobert Mustacchi 		    tmpname);
884*53548f91SRobert Mustacchi 	}
885*53548f91SRobert Mustacchi 
886*53548f91SRobert Mustacchi 	free(tmpname);
887*53548f91SRobert Mustacchi 
888*53548f91SRobert Mustacchi 	/* Now again for the .c file. */
889*53548f91SRobert Mustacchi 	fname = "core_pcbe_cpcgen.c";
890*53548f91SRobert Mustacchi 	if (asprintf(&tmpname, ".%s.%d", fname, getpid()) == -1) {
891*53548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct temporary file name");
892*53548f91SRobert Mustacchi 	}
893*53548f91SRobert Mustacchi 
894*53548f91SRobert Mustacchi 	if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0644)) < 0) {
895*53548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to create temporary file %s",
896*53548f91SRobert Mustacchi 		    tmpname);
897*53548f91SRobert Mustacchi 	}
898*53548f91SRobert Mustacchi 
899*53548f91SRobert Mustacchi 	if ((f = fdopen(fd, "w")) == NULL) {
900*53548f91SRobert Mustacchi 		int e = errno;
901*53548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
902*53548f91SRobert Mustacchi 		errno = e;
903*53548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to fdopen temporary file");
904*53548f91SRobert Mustacchi 	}
905*53548f91SRobert Mustacchi 
906*53548f91SRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_header, cpcgen_mapfile) == -1) {
907*53548f91SRobert Mustacchi 		int e = errno;
908*53548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
909*53548f91SRobert Mustacchi 		errno = e;
910*53548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to temporary file "
911*53548f91SRobert Mustacchi 		    "for %s", fname);
912*53548f91SRobert Mustacchi 	}
913*53548f91SRobert Mustacchi 
914*53548f91SRobert Mustacchi 	if (fprintf(f, "#include <core_pcbe_table.h>\n"
915*53548f91SRobert Mustacchi 	    "#include <sys/null.h>\n"
916*53548f91SRobert Mustacchi 	    "#include \"core_pcbe_cpcgen.h\"\n"
917*53548f91SRobert Mustacchi 	    "\n"
918*53548f91SRobert Mustacchi 	    "const struct events_table_t *\n"
919*53548f91SRobert Mustacchi 	    "core_cpcgen_table(uint_t model)\n"
920*53548f91SRobert Mustacchi 	    "{\n"
921*53548f91SRobert Mustacchi 	    "\tswitch (model) {\n") == -1) {
922*53548f91SRobert Mustacchi 		int e = errno;
923*53548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
924*53548f91SRobert Mustacchi 		errno = e;
925*53548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to "
926*53548f91SRobert Mustacchi 		    "temporary file for %s", fname);
927*53548f91SRobert Mustacchi 	}
928*53548f91SRobert Mustacchi 
929*53548f91SRobert Mustacchi 	for (map = cpcgen_maps; map != NULL; map = map->cmap_next) {
930*53548f91SRobert Mustacchi 		cpc_proc_t *p;
931*53548f91SRobert Mustacchi 		for (p = map->cmap_procs; p != NULL; p = p->cproc_next) {
932*53548f91SRobert Mustacchi 			assert(p->cproc_family == 6);
933*53548f91SRobert Mustacchi 			if (fprintf(f, "\t\tcase 0x%x:\n", p->cproc_model) ==
934*53548f91SRobert Mustacchi 			    -1) {
935*53548f91SRobert Mustacchi 				int e = errno;
936*53548f91SRobert Mustacchi 				(void) unlinkat(dirfd, tmpname, 0);
937*53548f91SRobert Mustacchi 				errno = e;
938*53548f91SRobert Mustacchi 				errx(EXIT_FAILURE, "failed to write header to "
939*53548f91SRobert Mustacchi 				    "temporary file for %s", fname);
940*53548f91SRobert Mustacchi 			}
941*53548f91SRobert Mustacchi 		}
942*53548f91SRobert Mustacchi 		if (fprintf(f, "\t\t\treturn (pcbe_core_events_%s);\n",
943*53548f91SRobert Mustacchi 		    map->cmap_name) == -1) {
944*53548f91SRobert Mustacchi 			int e = errno;
945*53548f91SRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
946*53548f91SRobert Mustacchi 			errno = e;
947*53548f91SRobert Mustacchi 			errx(EXIT_FAILURE, "failed to write entry to "
948*53548f91SRobert Mustacchi 			    "temporary file for %s", fname);
949*53548f91SRobert Mustacchi 		}
950*53548f91SRobert Mustacchi 	}
951*53548f91SRobert Mustacchi 
952*53548f91SRobert Mustacchi 	if (fprintf(f, "\t\tdefault:\n"
953*53548f91SRobert Mustacchi 	    "\t\t\treturn (NULL);\n"
954*53548f91SRobert Mustacchi 	    "\t}\n"
955*53548f91SRobert Mustacchi 	    "}\n") == -1) {
956*53548f91SRobert Mustacchi 		int e = errno;
957*53548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
958*53548f91SRobert Mustacchi 		errno = e;
959*53548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to "
960*53548f91SRobert Mustacchi 		    "temporary file for %s", fname);
961*53548f91SRobert Mustacchi 	}
962*53548f91SRobert Mustacchi 
963*53548f91SRobert Mustacchi 	if (fflush(f) != 0 || fclose(f) != 0) {
964*53548f91SRobert Mustacchi 		int e = errno;
965*53548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
966*53548f91SRobert Mustacchi 		errno = e;
967*53548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to flush and close temporary file");
968*53548f91SRobert Mustacchi 	}
969*53548f91SRobert Mustacchi 
970*53548f91SRobert Mustacchi 	if (renameat(dirfd, tmpname, dirfd, fname) != 0) {
971*53548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to rename temporary file %s",
972*53548f91SRobert Mustacchi 		    tmpname);
973*53548f91SRobert Mustacchi 	}
974*53548f91SRobert Mustacchi 
975*53548f91SRobert Mustacchi 	free(tmpname);
976*53548f91SRobert Mustacchi }
977*53548f91SRobert Mustacchi 
978*53548f91SRobert Mustacchi /*
979*53548f91SRobert Mustacchi  * Look at a rule to determine whether or not we should consider including it or
980*53548f91SRobert Mustacchi  * not. At this point we've already filtered things such that we only get core
981*53548f91SRobert Mustacchi  * events.
982*53548f91SRobert Mustacchi  *
983*53548f91SRobert Mustacchi  * To consider an entry, we currently apply the following criteria:
984*53548f91SRobert Mustacchi  *
985*53548f91SRobert Mustacchi  * - The MSRIndex and MSRValue are zero. Programming additional MSRs is no
986*53548f91SRobert Mustacchi  *   supported right now.
987*53548f91SRobert Mustacchi  * - TakenAlone is non-zero, which means that it cannot run at the same time as
988*53548f91SRobert Mustacchi  *   another field.
989*53548f91SRobert Mustacchi  * - Offcore is one, indicating that it is off the core and we need to figure
990*53548f91SRobert Mustacchi  *   out if we can support this.
991*53548f91SRobert Mustacchi  * - If the counter is fixed, don't use it for now.
992*53548f91SRobert Mustacchi  * - If more than one value is specified in the EventCode or UMask values
993*53548f91SRobert Mustacchi  */
994*53548f91SRobert Mustacchi static boolean_t
995*53548f91SRobert Mustacchi cpcgen_skip_entry(nvlist_t *nvl, const char *path, uint_t ent)
996*53548f91SRobert Mustacchi {
997*53548f91SRobert Mustacchi 	char *event, *msridx, *msrval, *taken, *offcore, *counter;
998*53548f91SRobert Mustacchi 	char *ecode, *umask;
999*53548f91SRobert Mustacchi 
1000*53548f91SRobert Mustacchi 	/*
1001*53548f91SRobert Mustacchi 	 * Require EventName, it's kind of useless without that.
1002*53548f91SRobert Mustacchi 	 */
1003*53548f91SRobert Mustacchi 	if (nvlist_lookup_string(nvl, "EventName", &event) != 0) {
1004*53548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "Found event without 'EventName' property "
1005*53548f91SRobert Mustacchi 		    "in %s, entry %u", path, ent);
1006*53548f91SRobert Mustacchi 	}
1007*53548f91SRobert Mustacchi 
1008*53548f91SRobert Mustacchi 	/*
1009*53548f91SRobert Mustacchi 	 * If we can't find an expected value, whine about it.
1010*53548f91SRobert Mustacchi 	 */
1011*53548f91SRobert Mustacchi 	if (nvlist_lookup_string(nvl, "MSRIndex", &msridx) != 0 ||
1012*53548f91SRobert Mustacchi 	    nvlist_lookup_string(nvl, "MSRValue", &msrval) != 0 ||
1013*53548f91SRobert Mustacchi 	    nvlist_lookup_string(nvl, "Counter", &counter) != 0 ||
1014*53548f91SRobert Mustacchi 	    nvlist_lookup_string(nvl, "EventCode", &ecode) != 0 ||
1015*53548f91SRobert Mustacchi 	    nvlist_lookup_string(nvl, "UMask", &umask) != 0 ||
1016*53548f91SRobert Mustacchi 	    nvlist_lookup_string(nvl, "Offcore", &offcore) != 0) {
1017*53548f91SRobert Mustacchi 		warnx("Skipping event %s (index %u) from %s, missing required "
1018*53548f91SRobert Mustacchi 		    "property", event, ent, path);
1019*53548f91SRobert Mustacchi 		return (B_TRUE);
1020*53548f91SRobert Mustacchi 	}
1021*53548f91SRobert Mustacchi 
1022*53548f91SRobert Mustacchi 	/*
1023*53548f91SRobert Mustacchi 	 * MSRIndex and MSRvalue comes as either "0" or "0x00".
1024*53548f91SRobert Mustacchi 	 */
1025*53548f91SRobert Mustacchi 	if ((strcmp(msridx, "0") != 0 && strcmp(msridx, "0x00") != 0) ||
1026*53548f91SRobert Mustacchi 	    (strcmp(msrval, "0") != 0 && strcmp(msridx, "0x00") != 0) ||
1027*53548f91SRobert Mustacchi 	    strcmp(offcore, "0") != 0 || strchr(ecode, ',') != NULL ||
1028*53548f91SRobert Mustacchi 	    strchr(umask, ',') != NULL) {
1029*53548f91SRobert Mustacchi 		return (B_TRUE);
1030*53548f91SRobert Mustacchi 	}
1031*53548f91SRobert Mustacchi 
1032*53548f91SRobert Mustacchi 	/*
1033*53548f91SRobert Mustacchi 	 * Unfortunately, not everything actually has "TakenAlone". If it
1034*53548f91SRobert Mustacchi 	 * doesn't, we assume that it doesn't have to be.
1035*53548f91SRobert Mustacchi 	 */
1036*53548f91SRobert Mustacchi 	if (nvlist_lookup_string(nvl, "TakenAlone", &taken) == 0 &&
1037*53548f91SRobert Mustacchi 	    strcmp(taken, "0") != 0) {
1038*53548f91SRobert Mustacchi 		return (B_TRUE);
1039*53548f91SRobert Mustacchi 	}
1040*53548f91SRobert Mustacchi 
1041*53548f91SRobert Mustacchi 
1042*53548f91SRobert Mustacchi 	if (strncasecmp(counter, "fixed", strlen("fixed")) == 0)
1043*53548f91SRobert Mustacchi 		return (B_TRUE);
1044*53548f91SRobert Mustacchi 
1045*53548f91SRobert Mustacchi 	return (B_FALSE);
1046*53548f91SRobert Mustacchi }
1047*53548f91SRobert Mustacchi 
1048*53548f91SRobert Mustacchi /*
1049*53548f91SRobert Mustacchi  * For each processor family, generate a data file that contains all of the
1050*53548f91SRobert Mustacchi  * events that we support. Also generate a header that can be included that
1051*53548f91SRobert Mustacchi  * declares all of the tables.
1052*53548f91SRobert Mustacchi  */
1053*53548f91SRobert Mustacchi static void
1054*53548f91SRobert Mustacchi cpcgen_gen(int dirfd)
1055*53548f91SRobert Mustacchi {
1056*53548f91SRobert Mustacchi 	cpc_map_t *map = cpcgen_maps;
1057*53548f91SRobert Mustacchi 
1058*53548f91SRobert Mustacchi 	if (map == NULL) {
1059*53548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "no platforms found or matched");
1060*53548f91SRobert Mustacchi 	}
1061*53548f91SRobert Mustacchi 
1062*53548f91SRobert Mustacchi 	for (map = cpcgen_maps; map != NULL; map = map->cmap_next) {
1063*53548f91SRobert Mustacchi 		int fd, ret;
1064*53548f91SRobert Mustacchi 		FILE *f;
1065*53548f91SRobert Mustacchi 		char *tmpname, *name;
1066*53548f91SRobert Mustacchi 		uint32_t length, i;
1067*53548f91SRobert Mustacchi 
1068*53548f91SRobert Mustacchi 		if ((name = cpcgen_ops.cgen_op_name(map)) == NULL) {
1069*53548f91SRobert Mustacchi 			exit(EXIT_FAILURE);
1070*53548f91SRobert Mustacchi 		}
1071*53548f91SRobert Mustacchi 
1072*53548f91SRobert Mustacchi 		if (asprintf(&tmpname, ".%s.%d", name, getpid()) == -1) {
1073*53548f91SRobert Mustacchi 			err(EXIT_FAILURE, "failed to construct temporary file "
1074*53548f91SRobert Mustacchi 			    "name");
1075*53548f91SRobert Mustacchi 		}
1076*53548f91SRobert Mustacchi 
1077*53548f91SRobert Mustacchi 		if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0444)) < 0) {
1078*53548f91SRobert Mustacchi 			err(EXIT_FAILURE, "failed to create temporary file %s",
1079*53548f91SRobert Mustacchi 			    tmpname);
1080*53548f91SRobert Mustacchi 		}
1081*53548f91SRobert Mustacchi 
1082*53548f91SRobert Mustacchi 		if ((f = fdopen(fd, "w")) == NULL) {
1083*53548f91SRobert Mustacchi 			int e = errno;
1084*53548f91SRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
1085*53548f91SRobert Mustacchi 			errno = e;
1086*53548f91SRobert Mustacchi 			err(EXIT_FAILURE, "failed to fdopen temporary file");
1087*53548f91SRobert Mustacchi 		}
1088*53548f91SRobert Mustacchi 
1089*53548f91SRobert Mustacchi 		if (!cpcgen_ops.cgen_op_file_before(f, map)) {
1090*53548f91SRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
1091*53548f91SRobert Mustacchi 			exit(EXIT_FAILURE);
1092*53548f91SRobert Mustacchi 		}
1093*53548f91SRobert Mustacchi 
1094*53548f91SRobert Mustacchi 		/*
1095*53548f91SRobert Mustacchi 		 * Iterate over array contents.
1096*53548f91SRobert Mustacchi 		 */
1097*53548f91SRobert Mustacchi 		if ((ret = nvlist_lookup_uint32(map->cmap_data, "length",
1098*53548f91SRobert Mustacchi 		    &length)) != 0) {
1099*53548f91SRobert Mustacchi 			errx(EXIT_FAILURE, "failed to look up length property "
1100*53548f91SRobert Mustacchi 			    "in parsed data for %s: %s", map->cmap_path,
1101*53548f91SRobert Mustacchi 			    strerror(ret));
1102*53548f91SRobert Mustacchi 		}
1103*53548f91SRobert Mustacchi 
1104*53548f91SRobert Mustacchi 		for (i = 0; i < length; i++) {
1105*53548f91SRobert Mustacchi 			nvlist_t *nvl;
1106*53548f91SRobert Mustacchi 			char num[64];
1107*53548f91SRobert Mustacchi 
1108*53548f91SRobert Mustacchi 			(void) snprintf(num, sizeof (num), "%u", i);
1109*53548f91SRobert Mustacchi 			if ((ret = nvlist_lookup_nvlist(map->cmap_data,
1110*53548f91SRobert Mustacchi 			    num, &nvl)) != 0) {
1111*53548f91SRobert Mustacchi 				errx(EXIT_FAILURE, "failed to look up array "
1112*53548f91SRobert Mustacchi 				    "entry %u in parsed data for %s: %s", i,
1113*53548f91SRobert Mustacchi 				    map->cmap_path, strerror(ret));
1114*53548f91SRobert Mustacchi 			}
1115*53548f91SRobert Mustacchi 
1116*53548f91SRobert Mustacchi 			if (cpcgen_skip_entry(nvl, map->cmap_path, i))
1117*53548f91SRobert Mustacchi 				continue;
1118*53548f91SRobert Mustacchi 
1119*53548f91SRobert Mustacchi 			if (!cpcgen_ops.cgen_op_event(f, nvl, map->cmap_path,
1120*53548f91SRobert Mustacchi 			    i)) {
1121*53548f91SRobert Mustacchi 				(void) unlinkat(dirfd, tmpname, 0);
1122*53548f91SRobert Mustacchi 				exit(EXIT_FAILURE);
1123*53548f91SRobert Mustacchi 			}
1124*53548f91SRobert Mustacchi 		}
1125*53548f91SRobert Mustacchi 
1126*53548f91SRobert Mustacchi 		if (!cpcgen_ops.cgen_op_file_after(f, map)) {
1127*53548f91SRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
1128*53548f91SRobert Mustacchi 			exit(EXIT_FAILURE);
1129*53548f91SRobert Mustacchi 		}
1130*53548f91SRobert Mustacchi 
1131*53548f91SRobert Mustacchi 		if (fflush(f) != 0 || fclose(f) != 0) {
1132*53548f91SRobert Mustacchi 			int e = errno;
1133*53548f91SRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
1134*53548f91SRobert Mustacchi 			errno = e;
1135*53548f91SRobert Mustacchi 			err(EXIT_FAILURE, "failed to flush and close "
1136*53548f91SRobert Mustacchi 			    "temporary file");
1137*53548f91SRobert Mustacchi 		}
1138*53548f91SRobert Mustacchi 
1139*53548f91SRobert Mustacchi 		if (renameat(dirfd, tmpname, dirfd, name) != 0) {
1140*53548f91SRobert Mustacchi 			err(EXIT_FAILURE, "failed to rename temporary file %s",
1141*53548f91SRobert Mustacchi 			    tmpname);
1142*53548f91SRobert Mustacchi 		}
1143*53548f91SRobert Mustacchi 
1144*53548f91SRobert Mustacchi 		free(name);
1145*53548f91SRobert Mustacchi 		free(tmpname);
1146*53548f91SRobert Mustacchi 	}
1147*53548f91SRobert Mustacchi }
1148*53548f91SRobert Mustacchi 
1149*53548f91SRobert Mustacchi static void
1150*53548f91SRobert Mustacchi cpcgen_usage(const char *fmt, ...)
1151*53548f91SRobert Mustacchi {
1152*53548f91SRobert Mustacchi 	if (fmt != NULL) {
1153*53548f91SRobert Mustacchi 		va_list ap;
1154*53548f91SRobert Mustacchi 
1155*53548f91SRobert Mustacchi 		(void) fprintf(stderr, "%s: ", cpcgen_progname);
1156*53548f91SRobert Mustacchi 		va_start(ap, fmt);
1157*53548f91SRobert Mustacchi 		(void) vfprintf(stderr, fmt, ap);
1158*53548f91SRobert Mustacchi 		va_end(ap);
1159*53548f91SRobert Mustacchi 	}
1160*53548f91SRobert Mustacchi 
1161*53548f91SRobert Mustacchi 	(void) fprintf(stderr, "Usage: %s -a|-p platform -c|-H|-m -d datadir "
1162*53548f91SRobert Mustacchi 	    "-o outdir\n"
1163*53548f91SRobert Mustacchi 	    "\n"
1164*53548f91SRobert Mustacchi 	    "\t-a  generate data for all platforms\n"
1165*53548f91SRobert Mustacchi 	    "\t-c  generate C file for CPC\n"
1166*53548f91SRobert Mustacchi 	    "\t-d  specify the directory containt perfmon data\n"
1167*53548f91SRobert Mustacchi 	    "\t-h  generate header file and common files\n"
1168*53548f91SRobert Mustacchi 	    "\t-m  generate manual pages for CPC data\n"
1169*53548f91SRobert Mustacchi 	    "\t-o  outut files in directory outdir\n"
1170*53548f91SRobert Mustacchi 	    "\t-p  generate data for a specified platform\n",
1171*53548f91SRobert Mustacchi 	    cpcgen_progname);
1172*53548f91SRobert Mustacchi }
1173*53548f91SRobert Mustacchi 
1174*53548f91SRobert Mustacchi int
1175*53548f91SRobert Mustacchi main(int argc, char *argv[])
1176*53548f91SRobert Mustacchi {
1177*53548f91SRobert Mustacchi 	int c, outdirfd;
1178*53548f91SRobert Mustacchi 	boolean_t do_mpage = B_FALSE, do_cfile = B_FALSE, do_header = B_FALSE,
1179*53548f91SRobert Mustacchi 	    do_all = B_FALSE;
1180*53548f91SRobert Mustacchi 	const char *datadir = NULL, *outdir = NULL, *platform = NULL;
1181*53548f91SRobert Mustacchi 	uint_t count = 0;
1182*53548f91SRobert Mustacchi 
1183*53548f91SRobert Mustacchi 	cpcgen_progname = basename(argv[0]);
1184*53548f91SRobert Mustacchi 
1185*53548f91SRobert Mustacchi 	while ((c = getopt(argc, argv, ":acd:hHmo:p:")) != -1) {
1186*53548f91SRobert Mustacchi 		switch (c) {
1187*53548f91SRobert Mustacchi 		case 'a':
1188*53548f91SRobert Mustacchi 			do_all = B_TRUE;
1189*53548f91SRobert Mustacchi 			break;
1190*53548f91SRobert Mustacchi 		case 'c':
1191*53548f91SRobert Mustacchi 			do_cfile = B_TRUE;
1192*53548f91SRobert Mustacchi 			break;
1193*53548f91SRobert Mustacchi 		case 'd':
1194*53548f91SRobert Mustacchi 			datadir = optarg;
1195*53548f91SRobert Mustacchi 			break;
1196*53548f91SRobert Mustacchi 		case 'm':
1197*53548f91SRobert Mustacchi 			do_mpage = B_TRUE;
1198*53548f91SRobert Mustacchi 			break;
1199*53548f91SRobert Mustacchi 		case 'H':
1200*53548f91SRobert Mustacchi 			do_header = B_TRUE;
1201*53548f91SRobert Mustacchi 			break;
1202*53548f91SRobert Mustacchi 		case 'o':
1203*53548f91SRobert Mustacchi 			outdir = optarg;
1204*53548f91SRobert Mustacchi 			break;
1205*53548f91SRobert Mustacchi 		case 'p':
1206*53548f91SRobert Mustacchi 			platform = optarg;
1207*53548f91SRobert Mustacchi 			break;
1208*53548f91SRobert Mustacchi 		case ':':
1209*53548f91SRobert Mustacchi 			cpcgen_usage("Option -%c requires an operand\n",
1210*53548f91SRobert Mustacchi 			    optopt);
1211*53548f91SRobert Mustacchi 			return (2);
1212*53548f91SRobert Mustacchi 		case '?':
1213*53548f91SRobert Mustacchi 			cpcgen_usage("Unknown option: -%c\n", optopt);
1214*53548f91SRobert Mustacchi 			return (2);
1215*53548f91SRobert Mustacchi 		case 'h':
1216*53548f91SRobert Mustacchi 		default:
1217*53548f91SRobert Mustacchi 			cpcgen_usage(NULL);
1218*53548f91SRobert Mustacchi 			return (2);
1219*53548f91SRobert Mustacchi 		}
1220*53548f91SRobert Mustacchi 	}
1221*53548f91SRobert Mustacchi 
1222*53548f91SRobert Mustacchi 	count = 0;
1223*53548f91SRobert Mustacchi 	if (do_mpage)
1224*53548f91SRobert Mustacchi 		count++;
1225*53548f91SRobert Mustacchi 	if (do_cfile)
1226*53548f91SRobert Mustacchi 		count++;
1227*53548f91SRobert Mustacchi 	if (do_header)
1228*53548f91SRobert Mustacchi 		count++;
1229*53548f91SRobert Mustacchi 	if (count > 1) {
1230*53548f91SRobert Mustacchi 		cpcgen_usage("Only one of -c, -h, and -m may be specified\n");
1231*53548f91SRobert Mustacchi 		return (2);
1232*53548f91SRobert Mustacchi 	} else if (count == 0) {
1233*53548f91SRobert Mustacchi 		cpcgen_usage("One of -c, -h, and -m is required\n");
1234*53548f91SRobert Mustacchi 		return (2);
1235*53548f91SRobert Mustacchi 	}
1236*53548f91SRobert Mustacchi 
1237*53548f91SRobert Mustacchi 	count = 0;
1238*53548f91SRobert Mustacchi 	if (do_all)
1239*53548f91SRobert Mustacchi 		count++;
1240*53548f91SRobert Mustacchi 	if (platform != NULL)
1241*53548f91SRobert Mustacchi 		count++;
1242*53548f91SRobert Mustacchi 	if (count > 1) {
1243*53548f91SRobert Mustacchi 		cpcgen_usage("Only one of -a and -p may be specified\n");
1244*53548f91SRobert Mustacchi 		return (2);
1245*53548f91SRobert Mustacchi 	} else if (count == 0) {
1246*53548f91SRobert Mustacchi 		cpcgen_usage("One of -a and -p is required\n");
1247*53548f91SRobert Mustacchi 		return (2);
1248*53548f91SRobert Mustacchi 	}
1249*53548f91SRobert Mustacchi 
1250*53548f91SRobert Mustacchi 
1251*53548f91SRobert Mustacchi 	if (outdir == NULL) {
1252*53548f91SRobert Mustacchi 		cpcgen_usage("Missing required output directory (-o)\n");
1253*53548f91SRobert Mustacchi 		return (2);
1254*53548f91SRobert Mustacchi 	}
1255*53548f91SRobert Mustacchi 
1256*53548f91SRobert Mustacchi 	if ((outdirfd = open(outdir, O_RDONLY)) < 0) {
1257*53548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to open output directory %s", outdir);
1258*53548f91SRobert Mustacchi 	}
1259*53548f91SRobert Mustacchi 
1260*53548f91SRobert Mustacchi 	if (datadir == NULL) {
1261*53548f91SRobert Mustacchi 		cpcgen_usage("Missing required data directory (-d)\n");
1262*53548f91SRobert Mustacchi 		return (2);
1263*53548f91SRobert Mustacchi 	}
1264*53548f91SRobert Mustacchi 
1265*53548f91SRobert Mustacchi 	cpcgen_read_mapfile(datadir, platform);
1266*53548f91SRobert Mustacchi 
1267*53548f91SRobert Mustacchi 	if (do_header) {
1268*53548f91SRobert Mustacchi 		cpcgen_common_files(outdirfd);
1269*53548f91SRobert Mustacchi 		return (0);
1270*53548f91SRobert Mustacchi 	}
1271*53548f91SRobert Mustacchi 
1272*53548f91SRobert Mustacchi 	if (do_mpage) {
1273*53548f91SRobert Mustacchi 		cpcgen_ops.cgen_op_name = cpcgen_manual_name;
1274*53548f91SRobert Mustacchi 		cpcgen_ops.cgen_op_file_before = cpcgen_manual_file_before;
1275*53548f91SRobert Mustacchi 		cpcgen_ops.cgen_op_file_after = cpcgen_manual_file_after;
1276*53548f91SRobert Mustacchi 		cpcgen_ops.cgen_op_event = cpcgen_manual_event;
1277*53548f91SRobert Mustacchi 	}
1278*53548f91SRobert Mustacchi 
1279*53548f91SRobert Mustacchi 	if (do_cfile) {
1280*53548f91SRobert Mustacchi 		cpcgen_ops.cgen_op_name = cpcgen_cfile_name;
1281*53548f91SRobert Mustacchi 		cpcgen_ops.cgen_op_file_before = cpcgen_cfile_file_before;
1282*53548f91SRobert Mustacchi 		cpcgen_ops.cgen_op_file_after = cpcgen_cfile_file_after;
1283*53548f91SRobert Mustacchi 		cpcgen_ops.cgen_op_event = cpcgen_cfile_event;
1284*53548f91SRobert Mustacchi 	}
1285*53548f91SRobert Mustacchi 
1286*53548f91SRobert Mustacchi 
1287*53548f91SRobert Mustacchi 	cpcgen_gen(outdirfd);
1288*53548f91SRobert Mustacchi 
1289*53548f91SRobert Mustacchi 	return (0);
1290*53548f91SRobert Mustacchi }
1291