xref: /illumos-gate/usr/src/tools/cpcgen/cpcgen.c (revision c18e9bc3)
17e3dbbacSRobert Mustacchi /*
27e3dbbacSRobert Mustacchi  * This file and its contents are supplied under the terms of the
37e3dbbacSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
47e3dbbacSRobert Mustacchi  * You may only use this file in accordance with the terms of version
57e3dbbacSRobert Mustacchi  * 1.0 of the CDDL.
67e3dbbacSRobert Mustacchi  *
77e3dbbacSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
87e3dbbacSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
97e3dbbacSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
107e3dbbacSRobert Mustacchi  */
117e3dbbacSRobert Mustacchi 
127e3dbbacSRobert Mustacchi /*
1308f1bbedSJohn Levon  * Copyright (c) 2019, Joyent, Inc.
147e3dbbacSRobert Mustacchi  */
157e3dbbacSRobert Mustacchi 
167e3dbbacSRobert Mustacchi /*
177e3dbbacSRobert Mustacchi  * This file transforms the perfmon data files into C files and manual pages.
187e3dbbacSRobert Mustacchi  */
197e3dbbacSRobert Mustacchi 
207e3dbbacSRobert Mustacchi #include <stdio.h>
217e3dbbacSRobert Mustacchi #include <stdarg.h>
227e3dbbacSRobert Mustacchi #include <unistd.h>
237e3dbbacSRobert Mustacchi #include <err.h>
247e3dbbacSRobert Mustacchi #include <libgen.h>
257e3dbbacSRobert Mustacchi #include <libnvpair.h>
267e3dbbacSRobert Mustacchi #include <strings.h>
277e3dbbacSRobert Mustacchi #include <errno.h>
287e3dbbacSRobert Mustacchi #include <limits.h>
297e3dbbacSRobert Mustacchi #include <sys/mman.h>
307e3dbbacSRobert Mustacchi #include <sys/param.h>
317e3dbbacSRobert Mustacchi #include <assert.h>
327e3dbbacSRobert Mustacchi #include <ctype.h>
337e3dbbacSRobert Mustacchi #include <sys/types.h>
347e3dbbacSRobert Mustacchi #include <sys/stat.h>
357e3dbbacSRobert Mustacchi #include <fcntl.h>
367e3dbbacSRobert Mustacchi 
377e3dbbacSRobert Mustacchi #include <json_nvlist.h>
387e3dbbacSRobert Mustacchi 
397e3dbbacSRobert Mustacchi #define	EXIT_USAGE	2
40*c18e9bc3SRobert Mustacchi #define	CPROC_MAX_STEPPINGS	16
417e3dbbacSRobert Mustacchi 
427e3dbbacSRobert Mustacchi typedef struct cpc_proc {
437e3dbbacSRobert Mustacchi 	struct cpc_proc *cproc_next;
447e3dbbacSRobert Mustacchi 	uint_t		cproc_family;
457e3dbbacSRobert Mustacchi 	uint_t		cproc_model;
46*c18e9bc3SRobert Mustacchi 	uint_t		cproc_nsteps;
47*c18e9bc3SRobert Mustacchi 	uint_t		cproc_steppings[CPROC_MAX_STEPPINGS];
487e3dbbacSRobert Mustacchi } cpc_proc_t;
497e3dbbacSRobert Mustacchi 
507e3dbbacSRobert Mustacchi typedef enum cpc_file_type {
517e3dbbacSRobert Mustacchi 	CPC_FILE_CORE		= 1 << 0,
527e3dbbacSRobert Mustacchi 	CPC_FILE_OFF_CORE	= 1 << 1,
537e3dbbacSRobert Mustacchi 	CPC_FILE_UNCORE		= 1 << 2,
547e3dbbacSRobert Mustacchi 	CPC_FILE_FP_MATH	= 1 << 3,
557e3dbbacSRobert Mustacchi 	CPC_FILE_UNCORE_EXP	= 1 << 4
567e3dbbacSRobert Mustacchi } cpc_type_t;
577e3dbbacSRobert Mustacchi 
587e3dbbacSRobert Mustacchi typedef struct cpc_map {
597e3dbbacSRobert Mustacchi 	struct cpc_map	*cmap_next;
607e3dbbacSRobert Mustacchi 	cpc_type_t	cmap_type;
617e3dbbacSRobert Mustacchi 	nvlist_t	*cmap_data;
627e3dbbacSRobert Mustacchi 	char		*cmap_path;
637e3dbbacSRobert Mustacchi 	const char	*cmap_name;
647e3dbbacSRobert Mustacchi 	cpc_proc_t	*cmap_procs;
657e3dbbacSRobert Mustacchi } cpc_map_t;
667e3dbbacSRobert Mustacchi 
677e3dbbacSRobert Mustacchi typedef struct cpc_whitelist {
687e3dbbacSRobert Mustacchi 	const char	*cwhite_short;
697e3dbbacSRobert Mustacchi 	const char	*cwhite_human;
707e3dbbacSRobert Mustacchi 	uint_t		cwhite_mask;
717e3dbbacSRobert Mustacchi } cpc_whitelist_t;
727e3dbbacSRobert Mustacchi 
737e3dbbacSRobert Mustacchi /*
747e3dbbacSRobert Mustacchi  * List of architectures that we support generating this data for. This is done
757e3dbbacSRobert Mustacchi  * so that processors that illumos doesn't support or run on aren't generated
767e3dbbacSRobert Mustacchi  * (generally the Xeon Phi).
777e3dbbacSRobert Mustacchi  */
787e3dbbacSRobert Mustacchi static cpc_whitelist_t cpcgen_whitelist[] = {
797e3dbbacSRobert Mustacchi 	/* Nehalem */
807e3dbbacSRobert Mustacchi 	{ "NHM-EP", "nhm_ep", CPC_FILE_CORE },
817e3dbbacSRobert Mustacchi 	{ "NHM-EX", "nhm_ex", CPC_FILE_CORE },
827e3dbbacSRobert Mustacchi 	/* Westmere */
837e3dbbacSRobert Mustacchi 	{ "WSM-EP-DP", "wsm_ep_dp", CPC_FILE_CORE },
847e3dbbacSRobert Mustacchi 	{ "WSM-EP-SP", "wsm_ep_sp", CPC_FILE_CORE },
857e3dbbacSRobert Mustacchi 	{ "WSM-EX", "wsm_ex", CPC_FILE_CORE },
867e3dbbacSRobert Mustacchi 	/* Sandy Bridge */
877e3dbbacSRobert Mustacchi 	{ "SNB", "snb", CPC_FILE_CORE },
887e3dbbacSRobert Mustacchi 	{ "JKT", "jkt", CPC_FILE_CORE },
897e3dbbacSRobert Mustacchi 	/* Ivy Bridge */
907e3dbbacSRobert Mustacchi 	{ "IVB", "ivb", CPC_FILE_CORE },
917e3dbbacSRobert Mustacchi 	{ "IVT", "ivt", CPC_FILE_CORE },
927e3dbbacSRobert Mustacchi 	/* Haswell */
937e3dbbacSRobert Mustacchi 	{ "HSW", "hsw", CPC_FILE_CORE },
947e3dbbacSRobert Mustacchi 	{ "HSX", "hsx", CPC_FILE_CORE },
957e3dbbacSRobert Mustacchi 	/* Broadwell */
967e3dbbacSRobert Mustacchi 	{ "BDW", "bdw", CPC_FILE_CORE },
977e3dbbacSRobert Mustacchi 	{ "BDW-DE", "bdw_de", CPC_FILE_CORE },
987e3dbbacSRobert Mustacchi 	{ "BDX", "bdx", CPC_FILE_CORE },
997e3dbbacSRobert Mustacchi 	/* Skylake */
1007e3dbbacSRobert Mustacchi 	{ "SKL", "skl", CPC_FILE_CORE },
1017e3dbbacSRobert Mustacchi 	{ "SKX", "skx", CPC_FILE_CORE },
102*c18e9bc3SRobert Mustacchi 	/* Cascade Lake */
103*c18e9bc3SRobert Mustacchi 	{ "CLX", "clx", CPC_FILE_CORE },
1047e3dbbacSRobert Mustacchi 	/* Atom */
1057e3dbbacSRobert Mustacchi 	{ "BNL", "bnl", CPC_FILE_CORE },
1067e3dbbacSRobert Mustacchi 	{ "SLM", "slm", CPC_FILE_CORE },
1077e3dbbacSRobert Mustacchi 	{ "GLM", "glm", CPC_FILE_CORE },
1087e3dbbacSRobert Mustacchi 	{ "GLP", "glp", CPC_FILE_CORE },
1097e3dbbacSRobert Mustacchi 	{ NULL }
1107e3dbbacSRobert Mustacchi };
1117e3dbbacSRobert Mustacchi 
1127e3dbbacSRobert Mustacchi typedef struct cpc_papi {
1137e3dbbacSRobert Mustacchi 	const char	*cpapi_intc;
1147e3dbbacSRobert Mustacchi 	const char	*cpapi_papi;
1157e3dbbacSRobert Mustacchi } cpc_papi_t;
1167e3dbbacSRobert Mustacchi 
1177e3dbbacSRobert Mustacchi /*
1187e3dbbacSRobert Mustacchi  * This table maps events with an Intel specific name to the corresponding PAPI
119*c18e9bc3SRobert Mustacchi  * name. There may be multiple Intel events which map to the same PAPI event.
1207e3dbbacSRobert Mustacchi  * This is usually because different processors have different names for an
1217e3dbbacSRobert Mustacchi  * event. We use the title as opposed to the event codes because those can
1227e3dbbacSRobert Mustacchi  * change somewhat arbitrarily between processor generations.
1237e3dbbacSRobert Mustacchi  */
1247e3dbbacSRobert Mustacchi static cpc_papi_t cpcgen_papi_map[] = {
1257e3dbbacSRobert Mustacchi 	{ "CPU_CLK_UNHALTED.THREAD_P", "PAPI_tot_cyc" },
1267e3dbbacSRobert Mustacchi 	{ "INST_RETIRED.ANY_P", "PAPI_tot_ins" },
1277e3dbbacSRobert Mustacchi 	{ "BR_INST_RETIRED.ALL_BRANCHES", "PAPI_br_ins" },
1287e3dbbacSRobert Mustacchi 	{ "BR_MISP_RETIRED.ALL_BRANCHES", "PAPI_br_msp" },
1297e3dbbacSRobert Mustacchi 	{ "BR_INST_RETIRED.CONDITIONAL", "PAPI_br_cn" },
1307e3dbbacSRobert Mustacchi 	{ "CYCLE_ACTIVITY.CYCLES_L1D_MISS", "PAPI_l1_dcm" },
1317e3dbbacSRobert Mustacchi 	{ "L1I.HITS", "PAPI_l1_ich" },
1327e3dbbacSRobert Mustacchi 	{ "ICACHE.HIT", "PAPI_l1_ich" },
1337e3dbbacSRobert Mustacchi 	{ "L1I.MISS", "PAPI_L1_icm" },
1347e3dbbacSRobert Mustacchi 	{ "ICACHE.MISSES", "PAPI_l1_icm" },
1357e3dbbacSRobert Mustacchi 	{ "L1I.READS", "PAPI_l1_ica" },
1367e3dbbacSRobert Mustacchi 	{ "ICACHE.ACCESSES", "PAPI_l1_ica" },
1377e3dbbacSRobert Mustacchi 	{ "L1I.READS", "PAPI_l1_icr" },
1387e3dbbacSRobert Mustacchi 	{ "ICACHE.ACCESSES", "PAPI_l1_icr" },
1397e3dbbacSRobert Mustacchi 	{ "L2_RQSTS.CODE_RD_MISS", "PAPI_l2_icm" },
1407e3dbbacSRobert Mustacchi 	{ "L2_RQSTS.MISS", "PAPI_l2_tcm" },
1417e3dbbacSRobert Mustacchi 	{ "ITLB_MISSES.MISS_CAUSES_A_WALK", "PAPI_tlb_im" },
1427e3dbbacSRobert Mustacchi 	{ "DTLB_LOAD_MISSES.MISS_CAUSES_A_WALK", "PAPI_tlb_dm" },
1437e3dbbacSRobert Mustacchi 	{ "PAGE_WALKS.D_SIDE_WALKS", "PAPI_tlb_dm" },
1447e3dbbacSRobert Mustacchi 	{ "PAGE_WALKS.I_SIDE_WALKS", "PAPI_tlb_im" },
1457e3dbbacSRobert Mustacchi 	{ "PAGE_WALKS.WALKS", "PAPI_tlb_tl" },
1467e3dbbacSRobert Mustacchi 	{ "INST_QUEUE_WRITES", "PAPI_tot_iis" },
1477e3dbbacSRobert Mustacchi 	{ "MEM_INST_RETIRED.STORES" "PAPI_sr_ins" },
1487e3dbbacSRobert Mustacchi 	{ "MEM_INST_RETIRED.LOADS" "PAPI_ld_ins" },
1497e3dbbacSRobert Mustacchi 	{ NULL, NULL }
1507e3dbbacSRobert Mustacchi };
1517e3dbbacSRobert Mustacchi 
1527e3dbbacSRobert Mustacchi typedef struct cpcgen_ops {
1537e3dbbacSRobert Mustacchi 	char *(*cgen_op_name)(cpc_map_t *);
1547e3dbbacSRobert Mustacchi 	boolean_t (*cgen_op_file_before)(FILE *, cpc_map_t *);
1557e3dbbacSRobert Mustacchi 	boolean_t (*cgen_op_file_after)(FILE *, cpc_map_t *);
1567e3dbbacSRobert Mustacchi 	boolean_t (*cgen_op_event)(FILE *, nvlist_t *, const char *, uint32_t);
1577e3dbbacSRobert Mustacchi } cpcgen_ops_t;
1587e3dbbacSRobert Mustacchi 
1597e3dbbacSRobert Mustacchi static cpcgen_ops_t cpcgen_ops;
1607e3dbbacSRobert Mustacchi static const char *cpcgen_mapfile = "/mapfile.csv";
1617e3dbbacSRobert Mustacchi static const char *cpcgen_progname;
1627e3dbbacSRobert Mustacchi static cpc_map_t *cpcgen_maps;
1637e3dbbacSRobert Mustacchi 
1647e3dbbacSRobert Mustacchi /*
1657e3dbbacSRobert Mustacchi  * Constants used for generating data.
1667e3dbbacSRobert Mustacchi  */
1677e3dbbacSRobert Mustacchi /* BEGIN CSTYLED */
1687e3dbbacSRobert Mustacchi static const char *cpcgen_cfile_header = ""
1697e3dbbacSRobert Mustacchi "/*\n"
1707e3dbbacSRobert Mustacchi " *  Copyright (c) 2018, Intel Corporation\n"
1717e3dbbacSRobert Mustacchi " *  Copyright (c) 2018, Joyent, Inc\n"
1727e3dbbacSRobert Mustacchi " *  All rights reserved.\n"
1737e3dbbacSRobert Mustacchi " *\n"
1747e3dbbacSRobert Mustacchi " *  Redistribution and use in source and binary forms, with or without\n"
1757e3dbbacSRobert Mustacchi " *  modification, are permitted provided that the following conditions are met:\n"
1767e3dbbacSRobert Mustacchi " * \n"
1777e3dbbacSRobert Mustacchi " *   1. Redistributions of source code must retain the above copyright notice,\n"
1787e3dbbacSRobert Mustacchi " *      this list of conditions and the following disclaimer.\n"
1797e3dbbacSRobert Mustacchi " * \n"
1807e3dbbacSRobert Mustacchi " *   2. Redistributions in binary form must reproduce the above copyright \n"
1817e3dbbacSRobert Mustacchi " *      notice, this list of conditions and the following disclaimer in the\n"
1827e3dbbacSRobert Mustacchi " *      documentation and/or other materials provided with the distribution.\n"
1837e3dbbacSRobert Mustacchi " * \n"
1847e3dbbacSRobert Mustacchi " *   3. Neither the name of the Intel Corporation nor the names of its \n"
1857e3dbbacSRobert Mustacchi " *      contributors may be used to endorse or promote products derived from\n"
1867e3dbbacSRobert Mustacchi " *      this software without specific prior written permission.\n"
1877e3dbbacSRobert Mustacchi " *\n"
1887e3dbbacSRobert Mustacchi " *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n"
1897e3dbbacSRobert Mustacchi " *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n"
1907e3dbbacSRobert Mustacchi " *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
1917e3dbbacSRobert Mustacchi " *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n"
1927e3dbbacSRobert Mustacchi " *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n"
1937e3dbbacSRobert Mustacchi " *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n"
1947e3dbbacSRobert Mustacchi " *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n"
1957e3dbbacSRobert Mustacchi " *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n"
1967e3dbbacSRobert Mustacchi " *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n"
1977e3dbbacSRobert Mustacchi " *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n"
1987e3dbbacSRobert Mustacchi " *  POSSIBILITY OF SUCH DAMAGE.\n"
1997e3dbbacSRobert Mustacchi " *\n"
2007e3dbbacSRobert Mustacchi " * This file was automatically generated by cpcgen from the data file\n"
2017e3dbbacSRobert Mustacchi " * data/perfmon%s\n"
2027e3dbbacSRobert Mustacchi " *\n"
2037e3dbbacSRobert Mustacchi " * Do not modify this file. Your changes will be lost!\n"
2047e3dbbacSRobert Mustacchi " */\n"
2057e3dbbacSRobert Mustacchi "\n";
2067e3dbbacSRobert Mustacchi /* END CSTYLED */
2077e3dbbacSRobert Mustacchi 
2087e3dbbacSRobert Mustacchi static const char *cpcgen_cfile_table_start = ""
2097e3dbbacSRobert Mustacchi "#include <core_pcbe_table.h>\n"
2107e3dbbacSRobert Mustacchi "\n"
2117e3dbbacSRobert Mustacchi "const struct events_table_t pcbe_core_events_%s[] = {\n";
2127e3dbbacSRobert Mustacchi 
2137e3dbbacSRobert Mustacchi static const char *cpcgen_cfile_table_end = ""
2147e3dbbacSRobert Mustacchi "\t{ NT_END, 0, 0, \"\" }\n"
2157e3dbbacSRobert Mustacchi "};\n";
2167e3dbbacSRobert Mustacchi 
2177e3dbbacSRobert Mustacchi /* BEGIN CSTYLED */
2187e3dbbacSRobert Mustacchi static const char *cpcgen_manual_header = ""
2197e3dbbacSRobert Mustacchi ".\\\" Copyright (c) 2018, Intel Corporation \n"
2207e3dbbacSRobert Mustacchi ".\\\" Copyright (c) 2018, Joyent, Inc.\n"
2217e3dbbacSRobert Mustacchi ".\\\" All rights reserved.\n"
2227e3dbbacSRobert Mustacchi ".\\\"\n"
2237e3dbbacSRobert Mustacchi ".\\\" Redistribution and use in source and binary forms, with or without \n"
2247e3dbbacSRobert Mustacchi ".\\\" modification, are permitted provided that the following conditions are met:\n"
2257e3dbbacSRobert Mustacchi ".\\\"\n"
2267e3dbbacSRobert Mustacchi ".\\\"  1. Redistributions of source code must retain the above copyright notice,\n"
2277e3dbbacSRobert Mustacchi ".\\\"     this list of conditions and the following disclaimer.\n"
2287e3dbbacSRobert Mustacchi ".\\\"\n"
2297e3dbbacSRobert Mustacchi ".\\\"  2. Redistributions in binary form must reproduce the above copyright\n"
2307e3dbbacSRobert Mustacchi ".\\\"     notice, this list of conditions and the following disclaimer in the\n"
2317e3dbbacSRobert Mustacchi ".\\\"     documentation and/or other materials provided with the distribution.\n"
2327e3dbbacSRobert Mustacchi ".\\\"\n"
2337e3dbbacSRobert Mustacchi ".\\\"  3. Neither the name of the Intel Corporation nor the names of its\n"
2347e3dbbacSRobert Mustacchi ".\\\"     contributors may be used to endorse or promote products derived from\n"
2357e3dbbacSRobert Mustacchi ".\\\"     this software without specific prior written permission.\n"
2367e3dbbacSRobert Mustacchi ".\\\"\n"
2377e3dbbacSRobert Mustacchi ".\\\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n"
2387e3dbbacSRobert Mustacchi ".\\\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n"
2397e3dbbacSRobert Mustacchi ".\\\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
2407e3dbbacSRobert Mustacchi ".\\\" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n"
2417e3dbbacSRobert Mustacchi ".\\\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n"
2427e3dbbacSRobert Mustacchi ".\\\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n"
2437e3dbbacSRobert Mustacchi ".\\\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n"
2447e3dbbacSRobert Mustacchi ".\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n"
2457e3dbbacSRobert Mustacchi ".\\\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n"
2467e3dbbacSRobert Mustacchi ".\\\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n"
2477e3dbbacSRobert Mustacchi ".\\\" POSSIBILITY OF SUCH DAMAGE.\n"
2487e3dbbacSRobert Mustacchi ".\\\"\n"
2497e3dbbacSRobert Mustacchi ".\\\" This file was automatically generated by cpcgen from the data file\n"
2507e3dbbacSRobert Mustacchi ".\\\" data/perfmon%s\n"
2517e3dbbacSRobert Mustacchi ".\\\"\n"
2527e3dbbacSRobert Mustacchi ".\\\" Do not modify this file. Your changes will be lost!\n"
2537e3dbbacSRobert Mustacchi ".\\\"\n"
2547e3dbbacSRobert Mustacchi ".\\\" We would like to thank Intel for providing the perfmon data for use in\n"
2557e3dbbacSRobert Mustacchi ".\\\" our manual pages.\n"
2567e3dbbacSRobert Mustacchi ".Dd June 18, 2018\n"
2577e3dbbacSRobert Mustacchi ".Dt %s_EVENTS 3CPC\n"
2587e3dbbacSRobert Mustacchi ".Os\n"
2597e3dbbacSRobert Mustacchi ".Sh NAME\n"
2607e3dbbacSRobert Mustacchi ".Nm %s_events\n"
2617e3dbbacSRobert Mustacchi ".Nd processor model specific performance counter events\n"
2627e3dbbacSRobert Mustacchi ".Sh DESCRIPTION\n"
2637e3dbbacSRobert Mustacchi "This manual page describes events specific to the following Intel CPU\n"
2647e3dbbacSRobert Mustacchi "models and is derived from Intel's perfmon data.\n"
2657e3dbbacSRobert Mustacchi "For more information, please consult the Intel Software Developer's Manual "
2667e3dbbacSRobert Mustacchi "or Intel's perfmon website.\n"
2677e3dbbacSRobert Mustacchi ".Pp\n"
2687e3dbbacSRobert Mustacchi "CPU models described by this document:\n"
2697e3dbbacSRobert Mustacchi ".Bl -bullet\n";
2707e3dbbacSRobert Mustacchi /* END CSTYLED */
2717e3dbbacSRobert Mustacchi 
2727e3dbbacSRobert Mustacchi static const char *cpcgen_manual_data = ""
2737e3dbbacSRobert Mustacchi ".El\n"
2747e3dbbacSRobert Mustacchi ".Pp\n"
2757e3dbbacSRobert Mustacchi "The following events are supported:\n"
2767e3dbbacSRobert Mustacchi ".Bl -tag -width Sy\n";
2777e3dbbacSRobert Mustacchi 
2787e3dbbacSRobert Mustacchi static const char *cpcgen_manual_trailer = ""
2797e3dbbacSRobert Mustacchi ".El\n"
2807e3dbbacSRobert Mustacchi ".Sh SEE ALSO\n"
2817e3dbbacSRobert Mustacchi ".Xr cpc 3CPC\n"
2827e3dbbacSRobert Mustacchi ".Pp\n"
2837e3dbbacSRobert Mustacchi ".Lk https://download.01.org/perfmon/index/";
2847e3dbbacSRobert Mustacchi 
2857e3dbbacSRobert Mustacchi static cpc_map_t *
2867e3dbbacSRobert Mustacchi cpcgen_map_lookup(const char *path)
2877e3dbbacSRobert Mustacchi {
2887e3dbbacSRobert Mustacchi 	cpc_map_t *m;
2897e3dbbacSRobert Mustacchi 
2907e3dbbacSRobert Mustacchi 	for (m = cpcgen_maps; m != NULL; m = m->cmap_next) {
2917e3dbbacSRobert Mustacchi 		if (strcmp(path, m->cmap_path) == 0) {
2927e3dbbacSRobert Mustacchi 			return (m);
2937e3dbbacSRobert Mustacchi 		}
2947e3dbbacSRobert Mustacchi 	}
2957e3dbbacSRobert Mustacchi 
2967e3dbbacSRobert Mustacchi 	return (NULL);
2977e3dbbacSRobert Mustacchi }
2987e3dbbacSRobert Mustacchi 
2997e3dbbacSRobert Mustacchi /*
3007e3dbbacSRobert Mustacchi  * Parse a string of the form 'GenuineIntel-6-2E' and get out the family and
3017e3dbbacSRobert Mustacchi  * model.
3027e3dbbacSRobert Mustacchi  */
3037e3dbbacSRobert Mustacchi static void
304*c18e9bc3SRobert Mustacchi cpcgen_parse_model(char *fsr, uint_t *family, uint_t *model, uint_t *nstepp,
305*c18e9bc3SRobert Mustacchi     uint_t *steppings)
3067e3dbbacSRobert Mustacchi {
3077e3dbbacSRobert Mustacchi 	const char *bstr = "GenuineIntel";
308*c18e9bc3SRobert Mustacchi 	const char *brand, *fam, *mod, *step;
3097e3dbbacSRobert Mustacchi 	char *last;
3107e3dbbacSRobert Mustacchi 	long l;
311*c18e9bc3SRobert Mustacchi 	uint_t nstep = 0;
3127e3dbbacSRobert Mustacchi 
313*c18e9bc3SRobert Mustacchi 	/*
314*c18e9bc3SRobert Mustacchi 	 * Tokeninze the string. There may be an optional stepping portion,
315*c18e9bc3SRobert Mustacchi 	 * which has a range of steppings enclosed by '[' and ']' characters.
316*c18e9bc3SRobert Mustacchi 	 * While the other parts are required, the stepping may be missing.
317*c18e9bc3SRobert Mustacchi 	 */
3187e3dbbacSRobert Mustacchi 	if ((brand = strtok_r(fsr, "-", &last)) == NULL ||
3197e3dbbacSRobert Mustacchi 	    (fam = strtok_r(NULL, "-", &last)) == NULL ||
3207e3dbbacSRobert Mustacchi 	    (mod = strtok_r(NULL, "-", &last)) == NULL) {
3217e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse processor id \"%s\"", fsr);
3227e3dbbacSRobert Mustacchi 	}
323*c18e9bc3SRobert Mustacchi 	step = strtok_r(NULL, "-", &last);
3247e3dbbacSRobert Mustacchi 
3257e3dbbacSRobert Mustacchi 	if (strcmp(bstr, brand) != 0) {
3267e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "brand string \"%s\" did not match \"%s\"",
3277e3dbbacSRobert Mustacchi 		    brand, bstr);
3287e3dbbacSRobert Mustacchi 	}
3297e3dbbacSRobert Mustacchi 
3307e3dbbacSRobert Mustacchi 	errno = 0;
3317e3dbbacSRobert Mustacchi 	l = strtol(fam, &last, 16);
332*c18e9bc3SRobert Mustacchi 	if (errno != 0 || l < 0 || l > UINT_MAX || *last != '\0') {
3337e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse family \"%s\"", fam);
3347e3dbbacSRobert Mustacchi 	}
3357e3dbbacSRobert Mustacchi 	*family = (uint_t)l;
3367e3dbbacSRobert Mustacchi 
3377e3dbbacSRobert Mustacchi 	l = strtol(mod, &last, 16);
338*c18e9bc3SRobert Mustacchi 	if (errno != 0 || l < 0 || l > UINT_MAX || *last != '\0') {
3397e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse model \"%s\"", mod);
3407e3dbbacSRobert Mustacchi 	}
3417e3dbbacSRobert Mustacchi 	*model = (uint_t)l;
342*c18e9bc3SRobert Mustacchi 
343*c18e9bc3SRobert Mustacchi 	if (step == NULL) {
344*c18e9bc3SRobert Mustacchi 		*nstepp = 0;
345*c18e9bc3SRobert Mustacchi 		return;
346*c18e9bc3SRobert Mustacchi 	}
347*c18e9bc3SRobert Mustacchi 
348*c18e9bc3SRobert Mustacchi 	if (*step != '[' || ((last = strrchr(step, ']')) == NULL)) {
349*c18e9bc3SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse stepping \"%s\": missing "
350*c18e9bc3SRobert Mustacchi 		    "stepping range brackets", step);
351*c18e9bc3SRobert Mustacchi 	}
352*c18e9bc3SRobert Mustacchi 	step++;
353*c18e9bc3SRobert Mustacchi 	*last = '\0';
354*c18e9bc3SRobert Mustacchi 	while (*step != '\0') {
355*c18e9bc3SRobert Mustacchi 		if (!isxdigit(*step)) {
356*c18e9bc3SRobert Mustacchi 			errx(EXIT_FAILURE, "failed to parse stepping: invalid "
357*c18e9bc3SRobert Mustacchi 			    "stepping identifier '0x%x'", *step);
358*c18e9bc3SRobert Mustacchi 		}
359*c18e9bc3SRobert Mustacchi 
360*c18e9bc3SRobert Mustacchi 		if (nstep >= CPROC_MAX_STEPPINGS) {
361*c18e9bc3SRobert Mustacchi 			errx(EXIT_FAILURE, "failed to parse stepping: "
362*c18e9bc3SRobert Mustacchi 			    "encountered too many steppings");
363*c18e9bc3SRobert Mustacchi 		}
364*c18e9bc3SRobert Mustacchi 
365*c18e9bc3SRobert Mustacchi 		switch (*step) {
366*c18e9bc3SRobert Mustacchi 		case '0':
367*c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0x0;
368*c18e9bc3SRobert Mustacchi 			break;
369*c18e9bc3SRobert Mustacchi 		case '1':
370*c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0x1;
371*c18e9bc3SRobert Mustacchi 			break;
372*c18e9bc3SRobert Mustacchi 		case '2':
373*c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0x2;
374*c18e9bc3SRobert Mustacchi 			break;
375*c18e9bc3SRobert Mustacchi 		case '3':
376*c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0x3;
377*c18e9bc3SRobert Mustacchi 			break;
378*c18e9bc3SRobert Mustacchi 		case '4':
379*c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0x4;
380*c18e9bc3SRobert Mustacchi 			break;
381*c18e9bc3SRobert Mustacchi 		case '5':
382*c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0x5;
383*c18e9bc3SRobert Mustacchi 			break;
384*c18e9bc3SRobert Mustacchi 		case '6':
385*c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0x6;
386*c18e9bc3SRobert Mustacchi 			break;
387*c18e9bc3SRobert Mustacchi 		case '7':
388*c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0x7;
389*c18e9bc3SRobert Mustacchi 			break;
390*c18e9bc3SRobert Mustacchi 		case '8':
391*c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0x8;
392*c18e9bc3SRobert Mustacchi 			break;
393*c18e9bc3SRobert Mustacchi 		case '9':
394*c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0x9;
395*c18e9bc3SRobert Mustacchi 			break;
396*c18e9bc3SRobert Mustacchi 		case 'a':
397*c18e9bc3SRobert Mustacchi 		case 'A':
398*c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0xa;
399*c18e9bc3SRobert Mustacchi 			break;
400*c18e9bc3SRobert Mustacchi 		case 'b':
401*c18e9bc3SRobert Mustacchi 		case 'B':
402*c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0xb;
403*c18e9bc3SRobert Mustacchi 			break;
404*c18e9bc3SRobert Mustacchi 		case 'c':
405*c18e9bc3SRobert Mustacchi 		case 'C':
406*c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0xc;
407*c18e9bc3SRobert Mustacchi 			break;
408*c18e9bc3SRobert Mustacchi 		case 'd':
409*c18e9bc3SRobert Mustacchi 		case 'D':
410*c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0xd;
411*c18e9bc3SRobert Mustacchi 			break;
412*c18e9bc3SRobert Mustacchi 		case 'e':
413*c18e9bc3SRobert Mustacchi 		case 'E':
414*c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0xe;
415*c18e9bc3SRobert Mustacchi 			break;
416*c18e9bc3SRobert Mustacchi 		case 'f':
417*c18e9bc3SRobert Mustacchi 		case 'F':
418*c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0xf;
419*c18e9bc3SRobert Mustacchi 			break;
420*c18e9bc3SRobert Mustacchi 		default:
421*c18e9bc3SRobert Mustacchi 			errx(EXIT_FAILURE, "encountered non-hex stepping "
422*c18e9bc3SRobert Mustacchi 			    "character: '%c'", *step);
423*c18e9bc3SRobert Mustacchi 		}
424*c18e9bc3SRobert Mustacchi 		nstep++;
425*c18e9bc3SRobert Mustacchi 		step++;
426*c18e9bc3SRobert Mustacchi 	}
427*c18e9bc3SRobert Mustacchi 
428*c18e9bc3SRobert Mustacchi 	*nstepp = nstep;
4297e3dbbacSRobert Mustacchi }
4307e3dbbacSRobert Mustacchi 
4317e3dbbacSRobert Mustacchi static nvlist_t *
4327e3dbbacSRobert Mustacchi cpcgen_read_datafile(const char *datadir, const char *file)
4337e3dbbacSRobert Mustacchi {
4347e3dbbacSRobert Mustacchi 	int fd;
4357e3dbbacSRobert Mustacchi 	char *path;
4367e3dbbacSRobert Mustacchi 	struct stat st;
4377e3dbbacSRobert Mustacchi 	void *map;
4387e3dbbacSRobert Mustacchi 	nvlist_t *nvl;
4397e3dbbacSRobert Mustacchi 	nvlist_parse_json_error_t jerr;
4407e3dbbacSRobert Mustacchi 
4417e3dbbacSRobert Mustacchi 	if (asprintf(&path, "%s/%s", datadir, file) == -1) {
4427e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct path to data file %s",
4437e3dbbacSRobert Mustacchi 		    file);
4447e3dbbacSRobert Mustacchi 	}
4457e3dbbacSRobert Mustacchi 
4467e3dbbacSRobert Mustacchi 	if ((fd = open(path, O_RDONLY)) < 0) {
4477e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to open data file %s", path);
4487e3dbbacSRobert Mustacchi 	}
4497e3dbbacSRobert Mustacchi 
4507e3dbbacSRobert Mustacchi 	if (fstat(fd, &st) != 0) {
4517e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to stat %s", path);
4527e3dbbacSRobert Mustacchi 	}
4537e3dbbacSRobert Mustacchi 
4547e3dbbacSRobert Mustacchi 	if ((map = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
4557e3dbbacSRobert Mustacchi 	    fd, 0)) == MAP_FAILED) {
4567e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to mmap %s", path);
4577e3dbbacSRobert Mustacchi 	}
4587e3dbbacSRobert Mustacchi 
4597e3dbbacSRobert Mustacchi 	if (nvlist_parse_json(map, st.st_size, &nvl, NVJSON_FORCE_INTEGER,
4607e3dbbacSRobert Mustacchi 	    &jerr) != 0) {
4617e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse file %s at pos %ld: %s",
4627e3dbbacSRobert Mustacchi 		    path, jerr.nje_pos, jerr.nje_message);
4637e3dbbacSRobert Mustacchi 	}
4647e3dbbacSRobert Mustacchi 
4657e3dbbacSRobert Mustacchi 	if (munmap(map, st.st_size) != 0) {
4667e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to munmap %s", path);
4677e3dbbacSRobert Mustacchi 	}
4687e3dbbacSRobert Mustacchi 
4697e3dbbacSRobert Mustacchi 	if (close(fd) != 0) {
4707e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to close data file %s", path);
4717e3dbbacSRobert Mustacchi 	}
4727e3dbbacSRobert Mustacchi 	free(path);
4737e3dbbacSRobert Mustacchi 
4747e3dbbacSRobert Mustacchi 	return (nvl);
4757e3dbbacSRobert Mustacchi }
4767e3dbbacSRobert Mustacchi 
4777e3dbbacSRobert Mustacchi /*
4787e3dbbacSRobert Mustacchi  * Check the whitelist to see if we should use this model.
4797e3dbbacSRobert Mustacchi  */
4807e3dbbacSRobert Mustacchi static const char *
4817e3dbbacSRobert Mustacchi cpcgen_use_arch(const char *path, cpc_type_t type, const char *platform)
4827e3dbbacSRobert Mustacchi {
4837e3dbbacSRobert Mustacchi 	const char *slash;
4847e3dbbacSRobert Mustacchi 	size_t len;
4857e3dbbacSRobert Mustacchi 	uint_t i;
4867e3dbbacSRobert Mustacchi 
4877e3dbbacSRobert Mustacchi 	if (*path != '/') {
4887e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "invalid path in mapfile: \"%s\": missing "
4897e3dbbacSRobert Mustacchi 		    "leading '/'", path);
4907e3dbbacSRobert Mustacchi 	}
4917e3dbbacSRobert Mustacchi 	if ((slash = strchr(path + 1, '/')) == NULL) {
4927e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "invalid path in mapfile: \"%s\": missing "
4937e3dbbacSRobert Mustacchi 		    "second '/'", path);
4947e3dbbacSRobert Mustacchi 	}
4957e3dbbacSRobert Mustacchi 	/* Account for the last '/' character. */
4967e3dbbacSRobert Mustacchi 	len = slash - path - 1;
4977e3dbbacSRobert Mustacchi 	assert(len > 0);
4987e3dbbacSRobert Mustacchi 
4997e3dbbacSRobert Mustacchi 	for (i = 0; cpcgen_whitelist[i].cwhite_short != NULL; i++) {
5007e3dbbacSRobert Mustacchi 		if (platform != NULL && strcasecmp(platform,
5017e3dbbacSRobert Mustacchi 		    cpcgen_whitelist[i].cwhite_short) != 0)
5027e3dbbacSRobert Mustacchi 			continue;
5037e3dbbacSRobert Mustacchi 		if (strncmp(path + 1, cpcgen_whitelist[i].cwhite_short,
5047e3dbbacSRobert Mustacchi 		    len) == 0 &&
5057e3dbbacSRobert Mustacchi 		    (cpcgen_whitelist[i].cwhite_mask & type) == type) {
5067e3dbbacSRobert Mustacchi 			return (cpcgen_whitelist[i].cwhite_human);
5077e3dbbacSRobert Mustacchi 		}
5087e3dbbacSRobert Mustacchi 	}
5097e3dbbacSRobert Mustacchi 
5107e3dbbacSRobert Mustacchi 	return (NULL);
5117e3dbbacSRobert Mustacchi }
5127e3dbbacSRobert Mustacchi 
5137e3dbbacSRobert Mustacchi /*
5147e3dbbacSRobert Mustacchi  * Read in the mapfile.csv that is used to map between processor families and
5157e3dbbacSRobert Mustacchi  * parse this. Each line has a comma separated value.
5167e3dbbacSRobert Mustacchi  */
5177e3dbbacSRobert Mustacchi static void
5187e3dbbacSRobert Mustacchi cpcgen_read_mapfile(const char *datadir, const char *platform)
5197e3dbbacSRobert Mustacchi {
5207e3dbbacSRobert Mustacchi 	FILE *map;
5217e3dbbacSRobert Mustacchi 	char *mappath, *last;
5227e3dbbacSRobert Mustacchi 	char *data = NULL;
5237e3dbbacSRobert Mustacchi 	size_t datalen = 0;
5247e3dbbacSRobert Mustacchi 	uint_t lineno;
5257e3dbbacSRobert Mustacchi 
5267e3dbbacSRobert Mustacchi 	if (asprintf(&mappath, "%s/%s", datadir, cpcgen_mapfile) == -1) {
5277e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct path to mapfile");
5287e3dbbacSRobert Mustacchi 	}
5297e3dbbacSRobert Mustacchi 
5307e3dbbacSRobert Mustacchi 	if ((map = fopen(mappath, "r")) == NULL) {
5317e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to open data mapfile %s", mappath);
5327e3dbbacSRobert Mustacchi 	}
5337e3dbbacSRobert Mustacchi 
5347e3dbbacSRobert Mustacchi 	lineno = 0;
5357e3dbbacSRobert Mustacchi 	while (getline(&data, &datalen, map) != -1) {
5367e3dbbacSRobert Mustacchi 		char *fstr, *path, *tstr;
5377e3dbbacSRobert Mustacchi 		const char *name;
538*c18e9bc3SRobert Mustacchi 		uint_t family, model, nsteps;
539*c18e9bc3SRobert Mustacchi 		uint_t steppings[CPROC_MAX_STEPPINGS];
540*c18e9bc3SRobert Mustacchi 
5417e3dbbacSRobert Mustacchi 		cpc_type_t type;
5427e3dbbacSRobert Mustacchi 		cpc_map_t *map;
5437e3dbbacSRobert Mustacchi 		cpc_proc_t *proc;
5447e3dbbacSRobert Mustacchi 
5457e3dbbacSRobert Mustacchi 		/*
5467e3dbbacSRobert Mustacchi 		 * The first line contains the header:
5477e3dbbacSRobert Mustacchi 		 * Family-model,Version,Filename,EventType
5487e3dbbacSRobert Mustacchi 		 */
5497e3dbbacSRobert Mustacchi 		lineno++;
5507e3dbbacSRobert Mustacchi 		if (lineno == 1) {
5517e3dbbacSRobert Mustacchi 			continue;
5527e3dbbacSRobert Mustacchi 		}
5537e3dbbacSRobert Mustacchi 
5547e3dbbacSRobert Mustacchi 		if ((fstr = strtok_r(data, ",", &last)) == NULL ||
5557e3dbbacSRobert Mustacchi 		    strtok_r(NULL, ",", &last) == NULL ||
5567e3dbbacSRobert Mustacchi 		    (path = strtok_r(NULL, ",", &last)) == NULL ||
5577e3dbbacSRobert Mustacchi 		    (tstr = strtok_r(NULL, "\n", &last)) == NULL) {
5587e3dbbacSRobert Mustacchi 			errx(EXIT_FAILURE, "failed to parse mapfile line "
5597e3dbbacSRobert Mustacchi 			    "%u in %s", lineno, mappath);
5607e3dbbacSRobert Mustacchi 		}
5617e3dbbacSRobert Mustacchi 
562*c18e9bc3SRobert Mustacchi 		cpcgen_parse_model(fstr, &family, &model, &nsteps, steppings);
5637e3dbbacSRobert Mustacchi 
5647e3dbbacSRobert Mustacchi 		if (strcmp(tstr, "core") == 0) {
5657e3dbbacSRobert Mustacchi 			type = CPC_FILE_CORE;
5667e3dbbacSRobert Mustacchi 		} else if (strcmp(tstr, "offcore") == 0) {
5677e3dbbacSRobert Mustacchi 			type = CPC_FILE_OFF_CORE;
5687e3dbbacSRobert Mustacchi 		} else if (strcmp(tstr, "uncore") == 0) {
5697e3dbbacSRobert Mustacchi 			type = CPC_FILE_UNCORE;
5707e3dbbacSRobert Mustacchi 		} else if (strcmp(tstr, "fp_arith_inst") == 0) {
5717e3dbbacSRobert Mustacchi 			type = CPC_FILE_FP_MATH;
5727e3dbbacSRobert Mustacchi 		} else if (strcmp(tstr, "uncore experimental") == 0) {
5737e3dbbacSRobert Mustacchi 			type = CPC_FILE_UNCORE_EXP;
5747e3dbbacSRobert Mustacchi 		} else {
5757e3dbbacSRobert Mustacchi 			errx(EXIT_FAILURE, "unknown file type \"%s\" on line "
5767e3dbbacSRobert Mustacchi 			    "%u", tstr, lineno);
5777e3dbbacSRobert Mustacchi 		}
5787e3dbbacSRobert Mustacchi 
5797e3dbbacSRobert Mustacchi 		if ((name = cpcgen_use_arch(path, type, platform)) == NULL)
5807e3dbbacSRobert Mustacchi 			continue;
5817e3dbbacSRobert Mustacchi 
5827e3dbbacSRobert Mustacchi 		if ((map = cpcgen_map_lookup(path)) == NULL) {
5837e3dbbacSRobert Mustacchi 			nvlist_t *parsed;
5847e3dbbacSRobert Mustacchi 
5857e3dbbacSRobert Mustacchi 			parsed = cpcgen_read_datafile(datadir, path);
5867e3dbbacSRobert Mustacchi 
5877e3dbbacSRobert Mustacchi 			if ((map = calloc(1, sizeof (cpc_map_t))) == NULL) {
5887e3dbbacSRobert Mustacchi 				err(EXIT_FAILURE, "failed to allocate space "
5897e3dbbacSRobert Mustacchi 				    "for cpc file");
5907e3dbbacSRobert Mustacchi 			}
5917e3dbbacSRobert Mustacchi 
5927e3dbbacSRobert Mustacchi 			if ((map->cmap_path = strdup(path)) == NULL) {
5937e3dbbacSRobert Mustacchi 				err(EXIT_FAILURE, "failed to duplicate path "
5947e3dbbacSRobert Mustacchi 				    "string");
5957e3dbbacSRobert Mustacchi 			}
5967e3dbbacSRobert Mustacchi 
5977e3dbbacSRobert Mustacchi 			map->cmap_type = type;
5987e3dbbacSRobert Mustacchi 			map->cmap_data = parsed;
5997e3dbbacSRobert Mustacchi 			map->cmap_next = cpcgen_maps;
6007e3dbbacSRobert Mustacchi 			map->cmap_name = name;
601*c18e9bc3SRobert Mustacchi 			map->cmap_procs = NULL;
6027e3dbbacSRobert Mustacchi 			cpcgen_maps = map;
6037e3dbbacSRobert Mustacchi 		}
6047e3dbbacSRobert Mustacchi 
605*c18e9bc3SRobert Mustacchi 		if ((proc = calloc(1, sizeof (cpc_proc_t))) == NULL) {
6067e3dbbacSRobert Mustacchi 			err(EXIT_FAILURE, "failed to allocate memory for "
6077e3dbbacSRobert Mustacchi 			    "family and model tracking");
6087e3dbbacSRobert Mustacchi 		}
6097e3dbbacSRobert Mustacchi 
6107e3dbbacSRobert Mustacchi 		proc->cproc_family = family;
6117e3dbbacSRobert Mustacchi 		proc->cproc_model = model;
612*c18e9bc3SRobert Mustacchi 		proc->cproc_nsteps = nsteps;
613*c18e9bc3SRobert Mustacchi 		if (nsteps > 0) {
614*c18e9bc3SRobert Mustacchi 			bcopy(steppings, proc->cproc_steppings,
615*c18e9bc3SRobert Mustacchi 			    sizeof (steppings));
616*c18e9bc3SRobert Mustacchi 		}
6177e3dbbacSRobert Mustacchi 		proc->cproc_next = map->cmap_procs;
6187e3dbbacSRobert Mustacchi 		map->cmap_procs = proc;
6197e3dbbacSRobert Mustacchi 	}
6207e3dbbacSRobert Mustacchi 
6217e3dbbacSRobert Mustacchi 	if (errno != 0 || ferror(map)) {
6227e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to read %s", mappath);
6237e3dbbacSRobert Mustacchi 	}
6247e3dbbacSRobert Mustacchi 
6257e3dbbacSRobert Mustacchi 	if (fclose(map) == EOF) {
6267e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to close %s", mappath);
6277e3dbbacSRobert Mustacchi 	}
6287e3dbbacSRobert Mustacchi 	free(data);
6297e3dbbacSRobert Mustacchi 	free(mappath);
6307e3dbbacSRobert Mustacchi }
6317e3dbbacSRobert Mustacchi 
6327e3dbbacSRobert Mustacchi static char *
6337e3dbbacSRobert Mustacchi cpcgen_manual_name(cpc_map_t *map)
6347e3dbbacSRobert Mustacchi {
6357e3dbbacSRobert Mustacchi 	char *name;
6367e3dbbacSRobert Mustacchi 
6377e3dbbacSRobert Mustacchi 	if (asprintf(&name, "%s_events.3cpc", map->cmap_name) == -1) {
6387e3dbbacSRobert Mustacchi 		warn("failed to assemble manual page name for %s",
6397e3dbbacSRobert Mustacchi 		    map->cmap_path);
6407e3dbbacSRobert Mustacchi 		return (NULL);
6417e3dbbacSRobert Mustacchi 	}
6427e3dbbacSRobert Mustacchi 
6437e3dbbacSRobert Mustacchi 	return (name);
6447e3dbbacSRobert Mustacchi }
6457e3dbbacSRobert Mustacchi 
6467e3dbbacSRobert Mustacchi static boolean_t
6477e3dbbacSRobert Mustacchi cpcgen_manual_file_before(FILE *f, cpc_map_t *map)
6487e3dbbacSRobert Mustacchi {
6497e3dbbacSRobert Mustacchi 	size_t i;
6507e3dbbacSRobert Mustacchi 	char *upper;
6517e3dbbacSRobert Mustacchi 	cpc_proc_t *proc;
6527e3dbbacSRobert Mustacchi 
6537e3dbbacSRobert Mustacchi 	if ((upper = strdup(map->cmap_name)) == NULL) {
6547e3dbbacSRobert Mustacchi 		warn("failed to duplicate manual name for %s", map->cmap_name);
6557e3dbbacSRobert Mustacchi 		return (B_FALSE);
6567e3dbbacSRobert Mustacchi 	}
6577e3dbbacSRobert Mustacchi 
6587e3dbbacSRobert Mustacchi 	for (i = 0; upper[i] != '\0'; i++) {
6597e3dbbacSRobert Mustacchi 		upper[i] = toupper(upper[i]);
6607e3dbbacSRobert Mustacchi 	}
6617e3dbbacSRobert Mustacchi 
6627e3dbbacSRobert Mustacchi 	if (fprintf(f, cpcgen_manual_header, map->cmap_path, upper,
6637e3dbbacSRobert Mustacchi 	    map->cmap_name) == -1) {
6647e3dbbacSRobert Mustacchi 		warn("failed to write out manual header for %s",
6657e3dbbacSRobert Mustacchi 		    map->cmap_name);
6667e3dbbacSRobert Mustacchi 		free(upper);
6677e3dbbacSRobert Mustacchi 		return (B_FALSE);
6687e3dbbacSRobert Mustacchi 	}
6697e3dbbacSRobert Mustacchi 
6707e3dbbacSRobert Mustacchi 	for (proc = map->cmap_procs; proc != NULL; proc = proc->cproc_next) {
671*c18e9bc3SRobert Mustacchi 		if (proc->cproc_nsteps > 0) {
672*c18e9bc3SRobert Mustacchi 			uint_t step;
673*c18e9bc3SRobert Mustacchi 
674*c18e9bc3SRobert Mustacchi 			for (step = 0; step < proc->cproc_nsteps; step++) {
675*c18e9bc3SRobert Mustacchi 				if (fprintf(f, ".It\n.Sy Family 0x%x, Model "
676*c18e9bc3SRobert Mustacchi 				    "0x%x, Stepping 0x%x\n",
677*c18e9bc3SRobert Mustacchi 				    proc->cproc_family, proc->cproc_model,
678*c18e9bc3SRobert Mustacchi 				    proc->cproc_steppings[step]) == -1) {
679*c18e9bc3SRobert Mustacchi 					warn("failed to write out model "
680*c18e9bc3SRobert Mustacchi 					    "information for %s",
681*c18e9bc3SRobert Mustacchi 					    map->cmap_name);
682*c18e9bc3SRobert Mustacchi 					free(upper);
683*c18e9bc3SRobert Mustacchi 					return (B_FALSE);
684*c18e9bc3SRobert Mustacchi 				}
685*c18e9bc3SRobert Mustacchi 			}
686*c18e9bc3SRobert Mustacchi 		} else {
687*c18e9bc3SRobert Mustacchi 			if (fprintf(f, ".It\n.Sy Family 0x%x, Model 0x%x\n",
688*c18e9bc3SRobert Mustacchi 			    proc->cproc_family, proc->cproc_model) == -1) {
689*c18e9bc3SRobert Mustacchi 				warn("failed to write out model information "
690*c18e9bc3SRobert Mustacchi 				    "for %s", map->cmap_name);
691*c18e9bc3SRobert Mustacchi 				free(upper);
692*c18e9bc3SRobert Mustacchi 				return (B_FALSE);
693*c18e9bc3SRobert Mustacchi 			}
6947e3dbbacSRobert Mustacchi 		}
6957e3dbbacSRobert Mustacchi 	}
6967e3dbbacSRobert Mustacchi 
6977e3dbbacSRobert Mustacchi 	if (fprintf(f, cpcgen_manual_data, map->cmap_path, upper,
6987e3dbbacSRobert Mustacchi 	    map->cmap_name) == -1) {
6997e3dbbacSRobert Mustacchi 		warn("failed to write out manual header for %s",
7007e3dbbacSRobert Mustacchi 		    map->cmap_name);
7017e3dbbacSRobert Mustacchi 		free(upper);
7027e3dbbacSRobert Mustacchi 		return (B_FALSE);
7037e3dbbacSRobert Mustacchi 	}
7047e3dbbacSRobert Mustacchi 
7057e3dbbacSRobert Mustacchi 	free(upper);
7067e3dbbacSRobert Mustacchi 	return (B_TRUE);
7077e3dbbacSRobert Mustacchi }
7087e3dbbacSRobert Mustacchi 
7097e3dbbacSRobert Mustacchi static boolean_t
7107e3dbbacSRobert Mustacchi cpcgen_manual_file_after(FILE *f, cpc_map_t *map)
7117e3dbbacSRobert Mustacchi {
7127e3dbbacSRobert Mustacchi 	if (fprintf(f, cpcgen_manual_trailer) == -1) {
7137e3dbbacSRobert Mustacchi 		warn("failed to write out manual header for %s",
7147e3dbbacSRobert Mustacchi 		    map->cmap_name);
7157e3dbbacSRobert Mustacchi 		return (B_FALSE);
7167e3dbbacSRobert Mustacchi 	}
7177e3dbbacSRobert Mustacchi 
7187e3dbbacSRobert Mustacchi 	return (B_TRUE);
7197e3dbbacSRobert Mustacchi }
7207e3dbbacSRobert Mustacchi 
7217e3dbbacSRobert Mustacchi static boolean_t
7227e3dbbacSRobert Mustacchi cpcgen_manual_event(FILE *f, nvlist_t *nvl, const char *path, uint32_t ent)
7237e3dbbacSRobert Mustacchi {
7247e3dbbacSRobert Mustacchi 	char *event, *lname, *brief = NULL, *public = NULL, *errata = NULL;
7257e3dbbacSRobert Mustacchi 	size_t i;
7267e3dbbacSRobert Mustacchi 
7277e3dbbacSRobert Mustacchi 	if (nvlist_lookup_string(nvl, "EventName", &event) != 0) {
7287e3dbbacSRobert Mustacchi 		warnx("Found event without 'EventName' property "
7297e3dbbacSRobert Mustacchi 		    "in %s, entry %u", path, ent);
7307e3dbbacSRobert Mustacchi 		return (B_FALSE);
7317e3dbbacSRobert Mustacchi 	}
7327e3dbbacSRobert Mustacchi 
7337e3dbbacSRobert Mustacchi 	/*
7347e3dbbacSRobert Mustacchi 	 * Intel uses capital names. CPC historically uses lower case names.
7357e3dbbacSRobert Mustacchi 	 */
7367e3dbbacSRobert Mustacchi 	if ((lname = strdup(event)) == NULL) {
7377e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to duplicate event name %s", event);
7387e3dbbacSRobert Mustacchi 	}
7397e3dbbacSRobert Mustacchi 	for (i = 0; lname[i] != '\0'; i++) {
7407e3dbbacSRobert Mustacchi 		lname[i] = tolower(event[i]);
7417e3dbbacSRobert Mustacchi 	}
7427e3dbbacSRobert Mustacchi 
7437e3dbbacSRobert Mustacchi 	/*
7447e3dbbacSRobert Mustacchi 	 * Try to get the other event fields, but if they're not there, don't
7457e3dbbacSRobert Mustacchi 	 * worry about it.
7467e3dbbacSRobert Mustacchi 	 */
7477e3dbbacSRobert Mustacchi 	(void) nvlist_lookup_string(nvl, "BriefDescription", &brief);
7487e3dbbacSRobert Mustacchi 	(void) nvlist_lookup_string(nvl, "PublicDescription", &public);
7497e3dbbacSRobert Mustacchi 	(void) nvlist_lookup_string(nvl, "Errata", &errata);
7507e3dbbacSRobert Mustacchi 	if (errata != NULL && (strcmp(errata, "0") == 0 ||
7517e3dbbacSRobert Mustacchi 	    strcmp(errata, "null") == 0)) {
7527e3dbbacSRobert Mustacchi 		errata = NULL;
7537e3dbbacSRobert Mustacchi 	}
7547e3dbbacSRobert Mustacchi 
7557e3dbbacSRobert Mustacchi 	if (fprintf(f, ".It Sy %s\n", lname) == -1) {
7567e3dbbacSRobert Mustacchi 		warn("failed to write out probe entry %s", event);
7577e3dbbacSRobert Mustacchi 		free(lname);
7587e3dbbacSRobert Mustacchi 		return (B_FALSE);
7597e3dbbacSRobert Mustacchi 	}
7607e3dbbacSRobert Mustacchi 
7617e3dbbacSRobert Mustacchi 	if (public != NULL) {
7627e3dbbacSRobert Mustacchi 		if (fprintf(f, "%s\n", public) == -1) {
7637e3dbbacSRobert Mustacchi 			warn("failed to write out probe entry %s", event);
7647e3dbbacSRobert Mustacchi 			free(lname);
7657e3dbbacSRobert Mustacchi 			return (B_FALSE);
7667e3dbbacSRobert Mustacchi 		}
7677e3dbbacSRobert Mustacchi 	} else if (brief != NULL) {
7687e3dbbacSRobert Mustacchi 		if (fprintf(f, "%s\n", brief) == -1) {
7697e3dbbacSRobert Mustacchi 			warn("failed to write out probe entry %s", event);
7707e3dbbacSRobert Mustacchi 			free(lname);
7717e3dbbacSRobert Mustacchi 			return (B_FALSE);
7727e3dbbacSRobert Mustacchi 		}
7737e3dbbacSRobert Mustacchi 	}
7747e3dbbacSRobert Mustacchi 
7757e3dbbacSRobert Mustacchi 	if (errata != NULL) {
7767e3dbbacSRobert Mustacchi 		if (fprintf(f, ".Pp\nThe following errata may apply to this: "
7777e3dbbacSRobert Mustacchi 		    "%s\n", errata) == -1) {
7787e3dbbacSRobert Mustacchi 
7797e3dbbacSRobert Mustacchi 			warn("failed to write out probe entry %s", event);
7807e3dbbacSRobert Mustacchi 			free(lname);
7817e3dbbacSRobert Mustacchi 			return (B_FALSE);
7827e3dbbacSRobert Mustacchi 		}
7837e3dbbacSRobert Mustacchi 	}
7847e3dbbacSRobert Mustacchi 
7857e3dbbacSRobert Mustacchi 	free(lname);
7867e3dbbacSRobert Mustacchi 	return (B_TRUE);
7877e3dbbacSRobert Mustacchi }
7887e3dbbacSRobert Mustacchi 
7897e3dbbacSRobert Mustacchi static char *
7907e3dbbacSRobert Mustacchi cpcgen_cfile_name(cpc_map_t *map)
7917e3dbbacSRobert Mustacchi {
7927e3dbbacSRobert Mustacchi 	char *name;
7937e3dbbacSRobert Mustacchi 
7947e3dbbacSRobert Mustacchi 	if (asprintf(&name, "core_pcbe_%s.c", map->cmap_name) == -1) {
7957e3dbbacSRobert Mustacchi 		warn("failed to assemble file name for %s", map->cmap_path);
7967e3dbbacSRobert Mustacchi 		return (NULL);
7977e3dbbacSRobert Mustacchi 	}
7987e3dbbacSRobert Mustacchi 
7997e3dbbacSRobert Mustacchi 	return (name);
8007e3dbbacSRobert Mustacchi }
8017e3dbbacSRobert Mustacchi 
8027e3dbbacSRobert Mustacchi static boolean_t
8037e3dbbacSRobert Mustacchi cpcgen_cfile_file_before(FILE *f, cpc_map_t *map)
8047e3dbbacSRobert Mustacchi {
8057e3dbbacSRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_header, map->cmap_path) == -1) {
8067e3dbbacSRobert Mustacchi 		warn("failed to write header to temporary file for %s",
8077e3dbbacSRobert Mustacchi 		    map->cmap_path);
8087e3dbbacSRobert Mustacchi 		return (B_FALSE);
8097e3dbbacSRobert Mustacchi 	}
8107e3dbbacSRobert Mustacchi 
8117e3dbbacSRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_table_start, map->cmap_name) == -1) {
8127e3dbbacSRobert Mustacchi 		warn("failed to write header to temporary file for %s",
8137e3dbbacSRobert Mustacchi 		    map->cmap_path);
8147e3dbbacSRobert Mustacchi 		return (B_FALSE);
8157e3dbbacSRobert Mustacchi 	}
8167e3dbbacSRobert Mustacchi 
8177e3dbbacSRobert Mustacchi 	return (B_TRUE);
8187e3dbbacSRobert Mustacchi }
8197e3dbbacSRobert Mustacchi 
8207e3dbbacSRobert Mustacchi static boolean_t
8217e3dbbacSRobert Mustacchi cpcgen_cfile_file_after(FILE *f, cpc_map_t *map)
8227e3dbbacSRobert Mustacchi {
8237e3dbbacSRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_table_end) == -1) {
8247e3dbbacSRobert Mustacchi 		warn("failed to write footer to temporary file for %s",
8257e3dbbacSRobert Mustacchi 		    map->cmap_path);
8267e3dbbacSRobert Mustacchi 		return (B_FALSE);
8277e3dbbacSRobert Mustacchi 	}
8287e3dbbacSRobert Mustacchi 
8297e3dbbacSRobert Mustacchi 	return (B_TRUE);
8307e3dbbacSRobert Mustacchi }
8317e3dbbacSRobert Mustacchi 
8327e3dbbacSRobert Mustacchi static boolean_t
8337e3dbbacSRobert Mustacchi cpcgen_cfile_event(FILE *f, nvlist_t *nvl, const char *path, uint_t ent)
8347e3dbbacSRobert Mustacchi {
8357e3dbbacSRobert Mustacchi 	char *ecode, *umask, *name, *counter, *lname, *cmask;
8367e3dbbacSRobert Mustacchi 	size_t i;
8377e3dbbacSRobert Mustacchi 
8387e3dbbacSRobert Mustacchi 	if (nvlist_lookup_string(nvl, "EventName", &name) != 0) {
8397e3dbbacSRobert Mustacchi 		warnx("Found event without 'EventName' property "
8407e3dbbacSRobert Mustacchi 		    "in %s, entry %u", path, ent);
8417e3dbbacSRobert Mustacchi 		return (B_FALSE);
8427e3dbbacSRobert Mustacchi 	}
8437e3dbbacSRobert Mustacchi 
8447e3dbbacSRobert Mustacchi 	if (nvlist_lookup_string(nvl, "EventCode", &ecode) != 0 ||
8457e3dbbacSRobert Mustacchi 	    nvlist_lookup_string(nvl, "UMask", &umask) != 0 ||
8467e3dbbacSRobert Mustacchi 	    nvlist_lookup_string(nvl, "Counter", &counter) != 0) {
8477e3dbbacSRobert Mustacchi 		warnx("event %s (index %u) from %s, missing "
8487e3dbbacSRobert Mustacchi 		    "required properties for C file translation",
8497e3dbbacSRobert Mustacchi 		    name, ent, path);
8507e3dbbacSRobert Mustacchi 		return (B_FALSE);
8517e3dbbacSRobert Mustacchi 	}
8527e3dbbacSRobert Mustacchi 
8537e3dbbacSRobert Mustacchi 	/*
8547e3dbbacSRobert Mustacchi 	 * While we could try and parse the counters manually, just do this the
8557e3dbbacSRobert Mustacchi 	 * max power way for now based on all possible values.
8567e3dbbacSRobert Mustacchi 	 */
8577e3dbbacSRobert Mustacchi 	if (strcmp(counter, "0") == 0 || strcmp(counter, "0,") == 0) {
8587e3dbbacSRobert Mustacchi 		cmask = "C0";
8597e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "1") == 0) {
8607e3dbbacSRobert Mustacchi 		cmask = "C1";
8617e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "2") == 0) {
8627e3dbbacSRobert Mustacchi 		cmask = "C2";
8637e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "3") == 0) {
8647e3dbbacSRobert Mustacchi 		cmask = "C3";
8657e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "0,1") == 0) {
8667e3dbbacSRobert Mustacchi 		cmask = "C0|C1";
8677e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "0,1,2") == 0) {
8687e3dbbacSRobert Mustacchi 		cmask = "C0|C1|C2";
8697e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "0,1,2,3") == 0) {
8707e3dbbacSRobert Mustacchi 		cmask = "C0|C1|C2|C3";
8717e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "0,2,3") == 0) {
8727e3dbbacSRobert Mustacchi 		cmask = "C0|C2|C3";
8737e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "1,2,3") == 0) {
8747e3dbbacSRobert Mustacchi 		cmask = "C1|C2|C3";
8757e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "2,3") == 0) {
8767e3dbbacSRobert Mustacchi 		cmask = "C2|C3";
8777e3dbbacSRobert Mustacchi 	} else {
8787e3dbbacSRobert Mustacchi 		warnx("event %s (index %u) from %s, has unknown "
8797e3dbbacSRobert Mustacchi 		    "counter value \"%s\"", name, ent, path, counter);
8807e3dbbacSRobert Mustacchi 		return (B_FALSE);
8817e3dbbacSRobert Mustacchi 	}
8827e3dbbacSRobert Mustacchi 
8837e3dbbacSRobert Mustacchi 
8847e3dbbacSRobert Mustacchi 	/*
8857e3dbbacSRobert Mustacchi 	 * Intel uses capital names. CPC historically uses lower case names.
8867e3dbbacSRobert Mustacchi 	 */
8877e3dbbacSRobert Mustacchi 	if ((lname = strdup(name)) == NULL) {
8887e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to duplicate event name %s", name);
8897e3dbbacSRobert Mustacchi 	}
8907e3dbbacSRobert Mustacchi 	for (i = 0; lname[i] != '\0'; i++) {
8917e3dbbacSRobert Mustacchi 		lname[i] = tolower(name[i]);
8927e3dbbacSRobert Mustacchi 	}
8937e3dbbacSRobert Mustacchi 
8947e3dbbacSRobert Mustacchi 	if (fprintf(f, "\t{ %s, %s, %s, \"%s\" },\n", ecode, umask, cmask,
8957e3dbbacSRobert Mustacchi 	    lname) == -1) {
8967e3dbbacSRobert Mustacchi 		warn("failed to write out entry %s from %s", name, path);
8977e3dbbacSRobert Mustacchi 		free(lname);
8987e3dbbacSRobert Mustacchi 		return (B_FALSE);
8997e3dbbacSRobert Mustacchi 	}
9007e3dbbacSRobert Mustacchi 
9017e3dbbacSRobert Mustacchi 	free(lname);
9027e3dbbacSRobert Mustacchi 
9037e3dbbacSRobert Mustacchi 	/*
9047e3dbbacSRobert Mustacchi 	 * Check if we have any PAPI aliases.
9057e3dbbacSRobert Mustacchi 	 */
9067e3dbbacSRobert Mustacchi 	for (i = 0; cpcgen_papi_map[i].cpapi_intc != NULL; i++) {
9077e3dbbacSRobert Mustacchi 		if (strcmp(name, cpcgen_papi_map[i].cpapi_intc) != 0)
9087e3dbbacSRobert Mustacchi 			continue;
9097e3dbbacSRobert Mustacchi 
9107e3dbbacSRobert Mustacchi 		if (fprintf(f, "\t{ %s, %s, %s, \"%s\" },\n", ecode, umask,
9117e3dbbacSRobert Mustacchi 		    cmask, cpcgen_papi_map[i].cpapi_papi) == -1) {
9127e3dbbacSRobert Mustacchi 			warn("failed to write out entry %s from %s", name,
9137e3dbbacSRobert Mustacchi 			    path);
9147e3dbbacSRobert Mustacchi 			return (B_FALSE);
9157e3dbbacSRobert Mustacchi 		}
9167e3dbbacSRobert Mustacchi 	}
9177e3dbbacSRobert Mustacchi 
9187e3dbbacSRobert Mustacchi 	return (B_TRUE);
9197e3dbbacSRobert Mustacchi }
9207e3dbbacSRobert Mustacchi 
921*c18e9bc3SRobert Mustacchi static boolean_t
922*c18e9bc3SRobert Mustacchi cpcgen_generate_map(FILE *f, cpc_map_t *map, boolean_t start)
923*c18e9bc3SRobert Mustacchi {
924*c18e9bc3SRobert Mustacchi 	cpc_proc_t *p;
925*c18e9bc3SRobert Mustacchi 
926*c18e9bc3SRobert Mustacchi 	if (fprintf(f, "\t%sif (", start ? "" : "} else ") == -1) {
927*c18e9bc3SRobert Mustacchi 		return (B_FALSE);
928*c18e9bc3SRobert Mustacchi 	}
929*c18e9bc3SRobert Mustacchi 
930*c18e9bc3SRobert Mustacchi 	for (p = map->cmap_procs; p != NULL; p = p->cproc_next) {
931*c18e9bc3SRobert Mustacchi 		/*
932*c18e9bc3SRobert Mustacchi 		 * Make sure the line is padded so the generated C code looks
933*c18e9bc3SRobert Mustacchi 		 * like reasonable C style.
934*c18e9bc3SRobert Mustacchi 		 */
935*c18e9bc3SRobert Mustacchi 		if (p != map->cmap_procs) {
936*c18e9bc3SRobert Mustacchi 			if (fputs("\t    ", f) == -1) {
937*c18e9bc3SRobert Mustacchi 				return (B_FALSE);
938*c18e9bc3SRobert Mustacchi 			}
939*c18e9bc3SRobert Mustacchi 		}
940*c18e9bc3SRobert Mustacchi 
941*c18e9bc3SRobert Mustacchi 		if (p->cproc_nsteps > 0) {
942*c18e9bc3SRobert Mustacchi 			uint_t i;
943*c18e9bc3SRobert Mustacchi 
944*c18e9bc3SRobert Mustacchi 			if (fprintf(f, "(model == 0x%x &&\n\t    (",
945*c18e9bc3SRobert Mustacchi 			    p->cproc_model) == -1) {
946*c18e9bc3SRobert Mustacchi 				return (B_FALSE);
947*c18e9bc3SRobert Mustacchi 			}
948*c18e9bc3SRobert Mustacchi 
949*c18e9bc3SRobert Mustacchi 			for (i = 0; i < p->cproc_nsteps; i++) {
950*c18e9bc3SRobert Mustacchi 				if (fprintf(f, "stepping == 0x%x%s",
951*c18e9bc3SRobert Mustacchi 				    p->cproc_steppings[i],
952*c18e9bc3SRobert Mustacchi 				    i + 1 != p->cproc_nsteps ?
953*c18e9bc3SRobert Mustacchi 				    " ||\n\t    " : "") == -1) {
954*c18e9bc3SRobert Mustacchi 					return (B_FALSE);
955*c18e9bc3SRobert Mustacchi 				}
956*c18e9bc3SRobert Mustacchi 			}
957*c18e9bc3SRobert Mustacchi 
958*c18e9bc3SRobert Mustacchi 			if (fputs("))", f) == -1) {
959*c18e9bc3SRobert Mustacchi 				return (B_FALSE);
960*c18e9bc3SRobert Mustacchi 			}
961*c18e9bc3SRobert Mustacchi 		} else if (fprintf(f, "model == 0x%x", p->cproc_model) == -1) {
962*c18e9bc3SRobert Mustacchi 			return (B_FALSE);
963*c18e9bc3SRobert Mustacchi 		}
964*c18e9bc3SRobert Mustacchi 
965*c18e9bc3SRobert Mustacchi 		if (fprintf(f, "%s\n",
966*c18e9bc3SRobert Mustacchi 		    p->cproc_next != NULL ? " ||" : ") {") == -1) {
967*c18e9bc3SRobert Mustacchi 			return (B_FALSE);
968*c18e9bc3SRobert Mustacchi 		}
969*c18e9bc3SRobert Mustacchi 	}
970*c18e9bc3SRobert Mustacchi 
971*c18e9bc3SRobert Mustacchi 	if (fprintf(f, "\t\t\treturn (pcbe_core_events_%s);\n",
972*c18e9bc3SRobert Mustacchi 	    map->cmap_name) == -1) {
973*c18e9bc3SRobert Mustacchi 		return (B_FALSE);
974*c18e9bc3SRobert Mustacchi 	}
975*c18e9bc3SRobert Mustacchi 
976*c18e9bc3SRobert Mustacchi 	return (B_TRUE);
977*c18e9bc3SRobert Mustacchi }
978*c18e9bc3SRobert Mustacchi 
9797e3dbbacSRobert Mustacchi /*
9807e3dbbacSRobert Mustacchi  * Generate a header file that declares all of these arrays and provide a map
9817e3dbbacSRobert Mustacchi  * for models to the corresponding table to use.
9827e3dbbacSRobert Mustacchi  */
9837e3dbbacSRobert Mustacchi static void
9847e3dbbacSRobert Mustacchi cpcgen_common_files(int dirfd)
9857e3dbbacSRobert Mustacchi {
9867e3dbbacSRobert Mustacchi 	const char *fname = "core_pcbe_cpcgen.h";
9877e3dbbacSRobert Mustacchi 	char *tmpname;
9887e3dbbacSRobert Mustacchi 	int fd;
9897e3dbbacSRobert Mustacchi 	FILE *f;
9907e3dbbacSRobert Mustacchi 	cpc_map_t *map;
9917e3dbbacSRobert Mustacchi 
9927e3dbbacSRobert Mustacchi 	if (asprintf(&tmpname, ".%s.%d", fname, getpid()) == -1) {
9937e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct temporary file name");
9947e3dbbacSRobert Mustacchi 	}
9957e3dbbacSRobert Mustacchi 
9967e3dbbacSRobert Mustacchi 	if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0644)) < 0) {
9977e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to create temporary file %s",
9987e3dbbacSRobert Mustacchi 		    tmpname);
9997e3dbbacSRobert Mustacchi 	}
10007e3dbbacSRobert Mustacchi 
10017e3dbbacSRobert Mustacchi 	if ((f = fdopen(fd, "w")) == NULL) {
10027e3dbbacSRobert Mustacchi 		int e = errno;
10037e3dbbacSRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
10047e3dbbacSRobert Mustacchi 		errno = e;
10057e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to fdopen temporary file");
10067e3dbbacSRobert Mustacchi 	}
10077e3dbbacSRobert Mustacchi 
10087e3dbbacSRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_header, cpcgen_mapfile) == -1) {
10097e3dbbacSRobert Mustacchi 		int e = errno;
10107e3dbbacSRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
10117e3dbbacSRobert Mustacchi 		errno = e;
10127e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to temporary file "
10137e3dbbacSRobert Mustacchi 		    "for %s", fname);
10147e3dbbacSRobert Mustacchi 	}
10157e3dbbacSRobert Mustacchi 
10167e3dbbacSRobert Mustacchi 	if (fprintf(f, "#ifndef _CORE_PCBE_CPCGEN_H\n"
10177e3dbbacSRobert Mustacchi 	    "#define\t_CORE_PCBE_CPCGEN_H\n"
10187e3dbbacSRobert Mustacchi 	    "\n"
10197e3dbbacSRobert Mustacchi 	    "#ifdef __cplusplus\n"
10207e3dbbacSRobert Mustacchi 	    "extern \"C\" {\n"
10217e3dbbacSRobert Mustacchi 	    "#endif\n"
10227e3dbbacSRobert Mustacchi 	    "\n"
1023*c18e9bc3SRobert Mustacchi 	    "extern const struct events_table_t *core_cpcgen_table(uint_t, "
1024*c18e9bc3SRobert Mustacchi 	    "uint_t);\n"
10257e3dbbacSRobert Mustacchi 	    "\n") == -1) {
10267e3dbbacSRobert Mustacchi 		int e = errno;
10277e3dbbacSRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
10287e3dbbacSRobert Mustacchi 		errno = e;
10297e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to "
10307e3dbbacSRobert Mustacchi 		    "temporary file for %s", fname);
10317e3dbbacSRobert Mustacchi 	}
10327e3dbbacSRobert Mustacchi 
10337e3dbbacSRobert Mustacchi 	for (map = cpcgen_maps; map != NULL; map = map->cmap_next) {
10347e3dbbacSRobert Mustacchi 		if (fprintf(f, "extern const struct events_table_t "
10357e3dbbacSRobert Mustacchi 		    "pcbe_core_events_%s[];\n", map->cmap_name) == -1) {
10367e3dbbacSRobert Mustacchi 			int e = errno;
10377e3dbbacSRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
10387e3dbbacSRobert Mustacchi 			errno = e;
10397e3dbbacSRobert Mustacchi 			errx(EXIT_FAILURE, "failed to write entry to "
10407e3dbbacSRobert Mustacchi 			    "temporary file for %s", fname);
10417e3dbbacSRobert Mustacchi 		}
10427e3dbbacSRobert Mustacchi 	}
10437e3dbbacSRobert Mustacchi 
10447e3dbbacSRobert Mustacchi 	if (fprintf(f, "\n"
10457e3dbbacSRobert Mustacchi 	    "#ifdef __cplusplus\n"
10467e3dbbacSRobert Mustacchi 	    "}\n"
10477e3dbbacSRobert Mustacchi 	    "#endif\n"
10487e3dbbacSRobert Mustacchi 	    "\n"
10497e3dbbacSRobert Mustacchi 	    "#endif /* _CORE_PCBE_CPCGEN_H */\n") == -1) {
10507e3dbbacSRobert Mustacchi 		int e = errno;
10517e3dbbacSRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
10527e3dbbacSRobert Mustacchi 		errno = e;
10537e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to "
10547e3dbbacSRobert Mustacchi 		    "temporary file for %s", fname);
10557e3dbbacSRobert Mustacchi 	}
10567e3dbbacSRobert Mustacchi 
10577e3dbbacSRobert Mustacchi 	if (fflush(f) != 0 || fclose(f) != 0) {
10587e3dbbacSRobert Mustacchi 		int e = errno;
10597e3dbbacSRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
10607e3dbbacSRobert Mustacchi 		errno = e;
10617e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to flush and close temporary file");
10627e3dbbacSRobert Mustacchi 	}
10637e3dbbacSRobert Mustacchi 
10647e3dbbacSRobert Mustacchi 	if (renameat(dirfd, tmpname, dirfd, fname) != 0) {
10657e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to rename temporary file %s",
10667e3dbbacSRobert Mustacchi 		    tmpname);
10677e3dbbacSRobert Mustacchi 	}
10687e3dbbacSRobert Mustacchi 
10697e3dbbacSRobert Mustacchi 	free(tmpname);
10707e3dbbacSRobert Mustacchi 
10717e3dbbacSRobert Mustacchi 	/* Now again for the .c file. */
10727e3dbbacSRobert Mustacchi 	fname = "core_pcbe_cpcgen.c";
10737e3dbbacSRobert Mustacchi 	if (asprintf(&tmpname, ".%s.%d", fname, getpid()) == -1) {
10747e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct temporary file name");
10757e3dbbacSRobert Mustacchi 	}
10767e3dbbacSRobert Mustacchi 
10777e3dbbacSRobert Mustacchi 	if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0644)) < 0) {
10787e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to create temporary file %s",
10797e3dbbacSRobert Mustacchi 		    tmpname);
10807e3dbbacSRobert Mustacchi 	}
10817e3dbbacSRobert Mustacchi 
10827e3dbbacSRobert Mustacchi 	if ((f = fdopen(fd, "w")) == NULL) {
10837e3dbbacSRobert Mustacchi 		int e = errno;
10847e3dbbacSRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
10857e3dbbacSRobert Mustacchi 		errno = e;
10867e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to fdopen temporary file");
10877e3dbbacSRobert Mustacchi 	}
10887e3dbbacSRobert Mustacchi 
10897e3dbbacSRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_header, cpcgen_mapfile) == -1) {
10907e3dbbacSRobert Mustacchi 		int e = errno;
10917e3dbbacSRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
10927e3dbbacSRobert Mustacchi 		errno = e;
10937e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to temporary file "
10947e3dbbacSRobert Mustacchi 		    "for %s", fname);
10957e3dbbacSRobert Mustacchi 	}
10967e3dbbacSRobert Mustacchi 
10977e3dbbacSRobert Mustacchi 	if (fprintf(f, "#include <core_pcbe_table.h>\n"
10987e3dbbacSRobert Mustacchi 	    "#include <sys/null.h>\n"
10997e3dbbacSRobert Mustacchi 	    "#include \"core_pcbe_cpcgen.h\"\n"
11007e3dbbacSRobert Mustacchi 	    "\n"
11017e3dbbacSRobert Mustacchi 	    "const struct events_table_t *\n"
1102*c18e9bc3SRobert Mustacchi 	    "core_cpcgen_table(uint_t model, uint_t stepping)\n"
1103*c18e9bc3SRobert Mustacchi 	    "{\n") == -1) {
11047e3dbbacSRobert Mustacchi 		int e = errno;
11057e3dbbacSRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
11067e3dbbacSRobert Mustacchi 		errno = e;
11077e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to "
11087e3dbbacSRobert Mustacchi 		    "temporary file for %s", fname);
11097e3dbbacSRobert Mustacchi 	}
11107e3dbbacSRobert Mustacchi 
11117e3dbbacSRobert Mustacchi 	for (map = cpcgen_maps; map != NULL; map = map->cmap_next) {
1112*c18e9bc3SRobert Mustacchi 		if (!cpcgen_generate_map(f, map, map == cpcgen_maps)) {
11137e3dbbacSRobert Mustacchi 			int e = errno;
11147e3dbbacSRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
11157e3dbbacSRobert Mustacchi 			errno = e;
1116*c18e9bc3SRobert Mustacchi 			errx(EXIT_FAILURE, "failed to write to temporary "
1117*c18e9bc3SRobert Mustacchi 			    "file for %s", fname);
11187e3dbbacSRobert Mustacchi 		}
11197e3dbbacSRobert Mustacchi 	}
11207e3dbbacSRobert Mustacchi 
1121*c18e9bc3SRobert Mustacchi 	if (fprintf(f, "\t} else {\n"
11227e3dbbacSRobert Mustacchi 	    "\t\t\treturn (NULL);\n"
11237e3dbbacSRobert Mustacchi 	    "\t}\n"
11247e3dbbacSRobert Mustacchi 	    "}\n") == -1) {
11257e3dbbacSRobert Mustacchi 		int e = errno;
11267e3dbbacSRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
11277e3dbbacSRobert Mustacchi 		errno = e;
11287e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to "
11297e3dbbacSRobert Mustacchi 		    "temporary file for %s", fname);
11307e3dbbacSRobert Mustacchi 	}
11317e3dbbacSRobert Mustacchi 
11327e3dbbacSRobert Mustacchi 	if (fflush(f) != 0 || fclose(f) != 0) {
11337e3dbbacSRobert Mustacchi 		int e = errno;
11347e3dbbacSRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
11357e3dbbacSRobert Mustacchi 		errno = e;
11367e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to flush and close temporary file");
11377e3dbbacSRobert Mustacchi 	}
11387e3dbbacSRobert Mustacchi 
11397e3dbbacSRobert Mustacchi 	if (renameat(dirfd, tmpname, dirfd, fname) != 0) {
11407e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to rename temporary file %s",
11417e3dbbacSRobert Mustacchi 		    tmpname);
11427e3dbbacSRobert Mustacchi 	}
11437e3dbbacSRobert Mustacchi 
11447e3dbbacSRobert Mustacchi 	free(tmpname);
11457e3dbbacSRobert Mustacchi }
11467e3dbbacSRobert Mustacchi 
11477e3dbbacSRobert Mustacchi /*
11487e3dbbacSRobert Mustacchi  * Look at a rule to determine whether or not we should consider including it or
11497e3dbbacSRobert Mustacchi  * not. At this point we've already filtered things such that we only get core
11507e3dbbacSRobert Mustacchi  * events.
11517e3dbbacSRobert Mustacchi  *
11527e3dbbacSRobert Mustacchi  * To consider an entry, we currently apply the following criteria:
11537e3dbbacSRobert Mustacchi  *
11547e3dbbacSRobert Mustacchi  * - The MSRIndex and MSRValue are zero. Programming additional MSRs is no
11557e3dbbacSRobert Mustacchi  *   supported right now.
11567e3dbbacSRobert Mustacchi  * - TakenAlone is non-zero, which means that it cannot run at the same time as
11577e3dbbacSRobert Mustacchi  *   another field.
11587e3dbbacSRobert Mustacchi  * - Offcore is one, indicating that it is off the core and we need to figure
11597e3dbbacSRobert Mustacchi  *   out if we can support this.
11607e3dbbacSRobert Mustacchi  * - If the counter is fixed, don't use it for now.
11617e3dbbacSRobert Mustacchi  * - If more than one value is specified in the EventCode or UMask values
11627e3dbbacSRobert Mustacchi  */
11637e3dbbacSRobert Mustacchi static boolean_t
11647e3dbbacSRobert Mustacchi cpcgen_skip_entry(nvlist_t *nvl, const char *path, uint_t ent)
11657e3dbbacSRobert Mustacchi {
11667e3dbbacSRobert Mustacchi 	char *event, *msridx, *msrval, *taken, *offcore, *counter;
11677e3dbbacSRobert Mustacchi 	char *ecode, *umask;
11687e3dbbacSRobert Mustacchi 
11697e3dbbacSRobert Mustacchi 	/*
11707e3dbbacSRobert Mustacchi 	 * Require EventName, it's kind of useless without that.
11717e3dbbacSRobert Mustacchi 	 */
11727e3dbbacSRobert Mustacchi 	if (nvlist_lookup_string(nvl, "EventName", &event) != 0) {
11737e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "Found event without 'EventName' property "
11747e3dbbacSRobert Mustacchi 		    "in %s, entry %u", path, ent);
11757e3dbbacSRobert Mustacchi 	}
11767e3dbbacSRobert Mustacchi 
11777e3dbbacSRobert Mustacchi 	/*
11787e3dbbacSRobert Mustacchi 	 * If we can't find an expected value, whine about it.
11797e3dbbacSRobert Mustacchi 	 */
11807e3dbbacSRobert Mustacchi 	if (nvlist_lookup_string(nvl, "MSRIndex", &msridx) != 0 ||
11817e3dbbacSRobert Mustacchi 	    nvlist_lookup_string(nvl, "MSRValue", &msrval) != 0 ||
11827e3dbbacSRobert Mustacchi 	    nvlist_lookup_string(nvl, "Counter", &counter) != 0 ||
11837e3dbbacSRobert Mustacchi 	    nvlist_lookup_string(nvl, "EventCode", &ecode) != 0 ||
11847e3dbbacSRobert Mustacchi 	    nvlist_lookup_string(nvl, "UMask", &umask) != 0 ||
11857e3dbbacSRobert Mustacchi 	    nvlist_lookup_string(nvl, "Offcore", &offcore) != 0) {
11867e3dbbacSRobert Mustacchi 		warnx("Skipping event %s (index %u) from %s, missing required "
11877e3dbbacSRobert Mustacchi 		    "property", event, ent, path);
11887e3dbbacSRobert Mustacchi 		return (B_TRUE);
11897e3dbbacSRobert Mustacchi 	}
11907e3dbbacSRobert Mustacchi 
11917e3dbbacSRobert Mustacchi 	/*
11927e3dbbacSRobert Mustacchi 	 * MSRIndex and MSRvalue comes as either "0" or "0x00".
11937e3dbbacSRobert Mustacchi 	 */
11947e3dbbacSRobert Mustacchi 	if ((strcmp(msridx, "0") != 0 && strcmp(msridx, "0x00") != 0) ||
11957e3dbbacSRobert Mustacchi 	    (strcmp(msrval, "0") != 0 && strcmp(msridx, "0x00") != 0) ||
11967e3dbbacSRobert Mustacchi 	    strcmp(offcore, "0") != 0 || strchr(ecode, ',') != NULL ||
11977e3dbbacSRobert Mustacchi 	    strchr(umask, ',') != NULL) {
11987e3dbbacSRobert Mustacchi 		return (B_TRUE);
11997e3dbbacSRobert Mustacchi 	}
12007e3dbbacSRobert Mustacchi 
12017e3dbbacSRobert Mustacchi 	/*
12027e3dbbacSRobert Mustacchi 	 * Unfortunately, not everything actually has "TakenAlone". If it
12037e3dbbacSRobert Mustacchi 	 * doesn't, we assume that it doesn't have to be.
12047e3dbbacSRobert Mustacchi 	 */
12057e3dbbacSRobert Mustacchi 	if (nvlist_lookup_string(nvl, "TakenAlone", &taken) == 0 &&
12067e3dbbacSRobert Mustacchi 	    strcmp(taken, "0") != 0) {
12077e3dbbacSRobert Mustacchi 		return (B_TRUE);
12087e3dbbacSRobert Mustacchi 	}
12097e3dbbacSRobert Mustacchi 
12107e3dbbacSRobert Mustacchi 
12117e3dbbacSRobert Mustacchi 	if (strncasecmp(counter, "fixed", strlen("fixed")) == 0)
12127e3dbbacSRobert Mustacchi 		return (B_TRUE);
12137e3dbbacSRobert Mustacchi 
12147e3dbbacSRobert Mustacchi 	return (B_FALSE);
12157e3dbbacSRobert Mustacchi }
12167e3dbbacSRobert Mustacchi 
12177e3dbbacSRobert Mustacchi /*
12187e3dbbacSRobert Mustacchi  * For each processor family, generate a data file that contains all of the
12197e3dbbacSRobert Mustacchi  * events that we support. Also generate a header that can be included that
12207e3dbbacSRobert Mustacchi  * declares all of the tables.
12217e3dbbacSRobert Mustacchi  */
12227e3dbbacSRobert Mustacchi static void
12237e3dbbacSRobert Mustacchi cpcgen_gen(int dirfd)
12247e3dbbacSRobert Mustacchi {
12257e3dbbacSRobert Mustacchi 	cpc_map_t *map = cpcgen_maps;
12267e3dbbacSRobert Mustacchi 
12277e3dbbacSRobert Mustacchi 	if (map == NULL) {
12287e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "no platforms found or matched");
12297e3dbbacSRobert Mustacchi 	}
12307e3dbbacSRobert Mustacchi 
12317e3dbbacSRobert Mustacchi 	for (map = cpcgen_maps; map != NULL; map = map->cmap_next) {
12327e3dbbacSRobert Mustacchi 		int fd, ret;
12337e3dbbacSRobert Mustacchi 		FILE *f;
12347e3dbbacSRobert Mustacchi 		char *tmpname, *name;
12357e3dbbacSRobert Mustacchi 		uint32_t length, i;
12367e3dbbacSRobert Mustacchi 
12377e3dbbacSRobert Mustacchi 		if ((name = cpcgen_ops.cgen_op_name(map)) == NULL) {
12387e3dbbacSRobert Mustacchi 			exit(EXIT_FAILURE);
12397e3dbbacSRobert Mustacchi 		}
12407e3dbbacSRobert Mustacchi 
12417e3dbbacSRobert Mustacchi 		if (asprintf(&tmpname, ".%s.%d", name, getpid()) == -1) {
12427e3dbbacSRobert Mustacchi 			err(EXIT_FAILURE, "failed to construct temporary file "
12437e3dbbacSRobert Mustacchi 			    "name");
12447e3dbbacSRobert Mustacchi 		}
12457e3dbbacSRobert Mustacchi 
12467e3dbbacSRobert Mustacchi 		if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0444)) < 0) {
12477e3dbbacSRobert Mustacchi 			err(EXIT_FAILURE, "failed to create temporary file %s",
12487e3dbbacSRobert Mustacchi 			    tmpname);
12497e3dbbacSRobert Mustacchi 		}
12507e3dbbacSRobert Mustacchi 
12517e3dbbacSRobert Mustacchi 		if ((f = fdopen(fd, "w")) == NULL) {
12527e3dbbacSRobert Mustacchi 			int e = errno;
12537e3dbbacSRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
12547e3dbbacSRobert Mustacchi 			errno = e;
12557e3dbbacSRobert Mustacchi 			err(EXIT_FAILURE, "failed to fdopen temporary file");
12567e3dbbacSRobert Mustacchi 		}
12577e3dbbacSRobert Mustacchi 
12587e3dbbacSRobert Mustacchi 		if (!cpcgen_ops.cgen_op_file_before(f, map)) {
12597e3dbbacSRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
12607e3dbbacSRobert Mustacchi 			exit(EXIT_FAILURE);
12617e3dbbacSRobert Mustacchi 		}
12627e3dbbacSRobert Mustacchi 
12637e3dbbacSRobert Mustacchi 		/*
12647e3dbbacSRobert Mustacchi 		 * Iterate over array contents.
12657e3dbbacSRobert Mustacchi 		 */
12667e3dbbacSRobert Mustacchi 		if ((ret = nvlist_lookup_uint32(map->cmap_data, "length",
12677e3dbbacSRobert Mustacchi 		    &length)) != 0) {
12687e3dbbacSRobert Mustacchi 			errx(EXIT_FAILURE, "failed to look up length property "
12697e3dbbacSRobert Mustacchi 			    "in parsed data for %s: %s", map->cmap_path,
12707e3dbbacSRobert Mustacchi 			    strerror(ret));
12717e3dbbacSRobert Mustacchi 		}
12727e3dbbacSRobert Mustacchi 
12737e3dbbacSRobert Mustacchi 		for (i = 0; i < length; i++) {
12747e3dbbacSRobert Mustacchi 			nvlist_t *nvl;
12757e3dbbacSRobert Mustacchi 			char num[64];
12767e3dbbacSRobert Mustacchi 
12777e3dbbacSRobert Mustacchi 			(void) snprintf(num, sizeof (num), "%u", i);
12787e3dbbacSRobert Mustacchi 			if ((ret = nvlist_lookup_nvlist(map->cmap_data,
12797e3dbbacSRobert Mustacchi 			    num, &nvl)) != 0) {
12807e3dbbacSRobert Mustacchi 				errx(EXIT_FAILURE, "failed to look up array "
12817e3dbbacSRobert Mustacchi 				    "entry %u in parsed data for %s: %s", i,
12827e3dbbacSRobert Mustacchi 				    map->cmap_path, strerror(ret));
12837e3dbbacSRobert Mustacchi 			}
12847e3dbbacSRobert Mustacchi 
12857e3dbbacSRobert Mustacchi 			if (cpcgen_skip_entry(nvl, map->cmap_path, i))
12867e3dbbacSRobert Mustacchi 				continue;
12877e3dbbacSRobert Mustacchi 
12887e3dbbacSRobert Mustacchi 			if (!cpcgen_ops.cgen_op_event(f, nvl, map->cmap_path,
12897e3dbbacSRobert Mustacchi 			    i)) {
12907e3dbbacSRobert Mustacchi 				(void) unlinkat(dirfd, tmpname, 0);
12917e3dbbacSRobert Mustacchi 				exit(EXIT_FAILURE);
12927e3dbbacSRobert Mustacchi 			}
12937e3dbbacSRobert Mustacchi 		}
12947e3dbbacSRobert Mustacchi 
12957e3dbbacSRobert Mustacchi 		if (!cpcgen_ops.cgen_op_file_after(f, map)) {
12967e3dbbacSRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
12977e3dbbacSRobert Mustacchi 			exit(EXIT_FAILURE);
12987e3dbbacSRobert Mustacchi 		}
12997e3dbbacSRobert Mustacchi 
13007e3dbbacSRobert Mustacchi 		if (fflush(f) != 0 || fclose(f) != 0) {
13017e3dbbacSRobert Mustacchi 			int e = errno;
13027e3dbbacSRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
13037e3dbbacSRobert Mustacchi 			errno = e;
13047e3dbbacSRobert Mustacchi 			err(EXIT_FAILURE, "failed to flush and close "
13057e3dbbacSRobert Mustacchi 			    "temporary file");
13067e3dbbacSRobert Mustacchi 		}
13077e3dbbacSRobert Mustacchi 
13087e3dbbacSRobert Mustacchi 		if (renameat(dirfd, tmpname, dirfd, name) != 0) {
13097e3dbbacSRobert Mustacchi 			err(EXIT_FAILURE, "failed to rename temporary file %s",
13107e3dbbacSRobert Mustacchi 			    tmpname);
13117e3dbbacSRobert Mustacchi 		}
13127e3dbbacSRobert Mustacchi 
13137e3dbbacSRobert Mustacchi 		free(name);
13147e3dbbacSRobert Mustacchi 		free(tmpname);
13157e3dbbacSRobert Mustacchi 	}
13167e3dbbacSRobert Mustacchi }
13177e3dbbacSRobert Mustacchi 
13187e3dbbacSRobert Mustacchi static void
13197e3dbbacSRobert Mustacchi cpcgen_usage(const char *fmt, ...)
13207e3dbbacSRobert Mustacchi {
13217e3dbbacSRobert Mustacchi 	if (fmt != NULL) {
13227e3dbbacSRobert Mustacchi 		va_list ap;
13237e3dbbacSRobert Mustacchi 
13247e3dbbacSRobert Mustacchi 		(void) fprintf(stderr, "%s: ", cpcgen_progname);
13257e3dbbacSRobert Mustacchi 		va_start(ap, fmt);
13267e3dbbacSRobert Mustacchi 		(void) vfprintf(stderr, fmt, ap);
13277e3dbbacSRobert Mustacchi 		va_end(ap);
13287e3dbbacSRobert Mustacchi 	}
13297e3dbbacSRobert Mustacchi 
13307e3dbbacSRobert Mustacchi 	(void) fprintf(stderr, "Usage: %s -a|-p platform -c|-H|-m -d datadir "
13317e3dbbacSRobert Mustacchi 	    "-o outdir\n"
13327e3dbbacSRobert Mustacchi 	    "\n"
13337e3dbbacSRobert Mustacchi 	    "\t-a  generate data for all platforms\n"
13347e3dbbacSRobert Mustacchi 	    "\t-c  generate C file for CPC\n"
13357e3dbbacSRobert Mustacchi 	    "\t-d  specify the directory containt perfmon data\n"
13367e3dbbacSRobert Mustacchi 	    "\t-h  generate header file and common files\n"
13377e3dbbacSRobert Mustacchi 	    "\t-m  generate manual pages for CPC data\n"
13387e3dbbacSRobert Mustacchi 	    "\t-o  outut files in directory outdir\n"
13397e3dbbacSRobert Mustacchi 	    "\t-p  generate data for a specified platform\n",
13407e3dbbacSRobert Mustacchi 	    cpcgen_progname);
13417e3dbbacSRobert Mustacchi }
13427e3dbbacSRobert Mustacchi 
13437e3dbbacSRobert Mustacchi int
13447e3dbbacSRobert Mustacchi main(int argc, char *argv[])
13457e3dbbacSRobert Mustacchi {
13467e3dbbacSRobert Mustacchi 	int c, outdirfd;
13477e3dbbacSRobert Mustacchi 	boolean_t do_mpage = B_FALSE, do_cfile = B_FALSE, do_header = B_FALSE,
13487e3dbbacSRobert Mustacchi 	    do_all = B_FALSE;
13497e3dbbacSRobert Mustacchi 	const char *datadir = NULL, *outdir = NULL, *platform = NULL;
13507e3dbbacSRobert Mustacchi 	uint_t count = 0;
13517e3dbbacSRobert Mustacchi 
13527e3dbbacSRobert Mustacchi 	cpcgen_progname = basename(argv[0]);
13537e3dbbacSRobert Mustacchi 
13547e3dbbacSRobert Mustacchi 	while ((c = getopt(argc, argv, ":acd:hHmo:p:")) != -1) {
13557e3dbbacSRobert Mustacchi 		switch (c) {
13567e3dbbacSRobert Mustacchi 		case 'a':
13577e3dbbacSRobert Mustacchi 			do_all = B_TRUE;
13587e3dbbacSRobert Mustacchi 			break;
13597e3dbbacSRobert Mustacchi 		case 'c':
13607e3dbbacSRobert Mustacchi 			do_cfile = B_TRUE;
13617e3dbbacSRobert Mustacchi 			break;
13627e3dbbacSRobert Mustacchi 		case 'd':
13637e3dbbacSRobert Mustacchi 			datadir = optarg;
13647e3dbbacSRobert Mustacchi 			break;
13657e3dbbacSRobert Mustacchi 		case 'm':
13667e3dbbacSRobert Mustacchi 			do_mpage = B_TRUE;
13677e3dbbacSRobert Mustacchi 			break;
13687e3dbbacSRobert Mustacchi 		case 'H':
13697e3dbbacSRobert Mustacchi 			do_header = B_TRUE;
13707e3dbbacSRobert Mustacchi 			break;
13717e3dbbacSRobert Mustacchi 		case 'o':
13727e3dbbacSRobert Mustacchi 			outdir = optarg;
13737e3dbbacSRobert Mustacchi 			break;
13747e3dbbacSRobert Mustacchi 		case 'p':
13757e3dbbacSRobert Mustacchi 			platform = optarg;
13767e3dbbacSRobert Mustacchi 			break;
13777e3dbbacSRobert Mustacchi 		case ':':
13787e3dbbacSRobert Mustacchi 			cpcgen_usage("Option -%c requires an operand\n",
13797e3dbbacSRobert Mustacchi 			    optopt);
13807e3dbbacSRobert Mustacchi 			return (2);
13817e3dbbacSRobert Mustacchi 		case '?':
13827e3dbbacSRobert Mustacchi 			cpcgen_usage("Unknown option: -%c\n", optopt);
13837e3dbbacSRobert Mustacchi 			return (2);
13847e3dbbacSRobert Mustacchi 		case 'h':
13857e3dbbacSRobert Mustacchi 		default:
13867e3dbbacSRobert Mustacchi 			cpcgen_usage(NULL);
13877e3dbbacSRobert Mustacchi 			return (2);
13887e3dbbacSRobert Mustacchi 		}
13897e3dbbacSRobert Mustacchi 	}
13907e3dbbacSRobert Mustacchi 
13917e3dbbacSRobert Mustacchi 	count = 0;
13927e3dbbacSRobert Mustacchi 	if (do_mpage)
13937e3dbbacSRobert Mustacchi 		count++;
13947e3dbbacSRobert Mustacchi 	if (do_cfile)
13957e3dbbacSRobert Mustacchi 		count++;
13967e3dbbacSRobert Mustacchi 	if (do_header)
13977e3dbbacSRobert Mustacchi 		count++;
13987e3dbbacSRobert Mustacchi 	if (count > 1) {
13997e3dbbacSRobert Mustacchi 		cpcgen_usage("Only one of -c, -h, and -m may be specified\n");
14007e3dbbacSRobert Mustacchi 		return (2);
14017e3dbbacSRobert Mustacchi 	} else if (count == 0) {
14027e3dbbacSRobert Mustacchi 		cpcgen_usage("One of -c, -h, and -m is required\n");
14037e3dbbacSRobert Mustacchi 		return (2);
14047e3dbbacSRobert Mustacchi 	}
14057e3dbbacSRobert Mustacchi 
14067e3dbbacSRobert Mustacchi 	count = 0;
14077e3dbbacSRobert Mustacchi 	if (do_all)
14087e3dbbacSRobert Mustacchi 		count++;
14097e3dbbacSRobert Mustacchi 	if (platform != NULL)
14107e3dbbacSRobert Mustacchi 		count++;
14117e3dbbacSRobert Mustacchi 	if (count > 1) {
14127e3dbbacSRobert Mustacchi 		cpcgen_usage("Only one of -a and -p may be specified\n");
14137e3dbbacSRobert Mustacchi 		return (2);
14147e3dbbacSRobert Mustacchi 	} else if (count == 0) {
14157e3dbbacSRobert Mustacchi 		cpcgen_usage("One of -a and -p is required\n");
14167e3dbbacSRobert Mustacchi 		return (2);
14177e3dbbacSRobert Mustacchi 	}
14187e3dbbacSRobert Mustacchi 
14197e3dbbacSRobert Mustacchi 
14207e3dbbacSRobert Mustacchi 	if (outdir == NULL) {
14217e3dbbacSRobert Mustacchi 		cpcgen_usage("Missing required output directory (-o)\n");
14227e3dbbacSRobert Mustacchi 		return (2);
14237e3dbbacSRobert Mustacchi 	}
14247e3dbbacSRobert Mustacchi 
14257e3dbbacSRobert Mustacchi 	if ((outdirfd = open(outdir, O_RDONLY)) < 0) {
14267e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to open output directory %s", outdir);
14277e3dbbacSRobert Mustacchi 	}
14287e3dbbacSRobert Mustacchi 
14297e3dbbacSRobert Mustacchi 	if (datadir == NULL) {
14307e3dbbacSRobert Mustacchi 		cpcgen_usage("Missing required data directory (-d)\n");
14317e3dbbacSRobert Mustacchi 		return (2);
14327e3dbbacSRobert Mustacchi 	}
14337e3dbbacSRobert Mustacchi 
14347e3dbbacSRobert Mustacchi 	cpcgen_read_mapfile(datadir, platform);
14357e3dbbacSRobert Mustacchi 
14367e3dbbacSRobert Mustacchi 	if (do_header) {
14377e3dbbacSRobert Mustacchi 		cpcgen_common_files(outdirfd);
14387e3dbbacSRobert Mustacchi 		return (0);
14397e3dbbacSRobert Mustacchi 	}
14407e3dbbacSRobert Mustacchi 
14417e3dbbacSRobert Mustacchi 	if (do_mpage) {
14427e3dbbacSRobert Mustacchi 		cpcgen_ops.cgen_op_name = cpcgen_manual_name;
14437e3dbbacSRobert Mustacchi 		cpcgen_ops.cgen_op_file_before = cpcgen_manual_file_before;
14447e3dbbacSRobert Mustacchi 		cpcgen_ops.cgen_op_file_after = cpcgen_manual_file_after;
14457e3dbbacSRobert Mustacchi 		cpcgen_ops.cgen_op_event = cpcgen_manual_event;
14467e3dbbacSRobert Mustacchi 	}
14477e3dbbacSRobert Mustacchi 
14487e3dbbacSRobert Mustacchi 	if (do_cfile) {
14497e3dbbacSRobert Mustacchi 		cpcgen_ops.cgen_op_name = cpcgen_cfile_name;
14507e3dbbacSRobert Mustacchi 		cpcgen_ops.cgen_op_file_before = cpcgen_cfile_file_before;
14517e3dbbacSRobert Mustacchi 		cpcgen_ops.cgen_op_file_after = cpcgen_cfile_file_after;
14527e3dbbacSRobert Mustacchi 		cpcgen_ops.cgen_op_event = cpcgen_cfile_event;
14537e3dbbacSRobert Mustacchi 	}
14547e3dbbacSRobert Mustacchi 
14557e3dbbacSRobert Mustacchi 
14567e3dbbacSRobert Mustacchi 	cpcgen_gen(outdirfd);
14577e3dbbacSRobert Mustacchi 
14587e3dbbacSRobert Mustacchi 	return (0);
14597e3dbbacSRobert Mustacchi }
1460