153548f91SRobert Mustacchi /* 253548f91SRobert Mustacchi * This file and its contents are supplied under the terms of the 353548f91SRobert Mustacchi * Common Development and Distribution License ("CDDL"), version 1.0. 453548f91SRobert Mustacchi * You may only use this file in accordance with the terms of version 553548f91SRobert Mustacchi * 1.0 of the CDDL. 653548f91SRobert Mustacchi * 753548f91SRobert Mustacchi * A full copy of the text of the CDDL should have accompanied this 853548f91SRobert Mustacchi * source. A copy of the CDDL is also available via the Internet at 953548f91SRobert Mustacchi * http://www.illumos.org/license/CDDL. 1053548f91SRobert Mustacchi */ 1153548f91SRobert Mustacchi 1253548f91SRobert Mustacchi /* 13*1ad658abSJohn Levon * Copyright (c) 2019, Joyent, Inc. 1453548f91SRobert Mustacchi */ 1553548f91SRobert Mustacchi 1653548f91SRobert Mustacchi /* 1753548f91SRobert Mustacchi * This file transforms the perfmon data files into C files and manual pages. 1853548f91SRobert Mustacchi */ 1953548f91SRobert Mustacchi 2053548f91SRobert Mustacchi #include <stdio.h> 2153548f91SRobert Mustacchi #include <stdarg.h> 2253548f91SRobert Mustacchi #include <unistd.h> 2353548f91SRobert Mustacchi #include <err.h> 2453548f91SRobert Mustacchi #include <libgen.h> 2553548f91SRobert Mustacchi #include <libnvpair.h> 2653548f91SRobert Mustacchi #include <strings.h> 2753548f91SRobert Mustacchi #include <errno.h> 2853548f91SRobert Mustacchi #include <limits.h> 2953548f91SRobert Mustacchi #include <sys/mman.h> 3053548f91SRobert Mustacchi #include <sys/param.h> 3153548f91SRobert Mustacchi #include <assert.h> 3253548f91SRobert Mustacchi #include <ctype.h> 3353548f91SRobert Mustacchi #include <sys/types.h> 3453548f91SRobert Mustacchi #include <sys/stat.h> 3553548f91SRobert Mustacchi #include <fcntl.h> 3653548f91SRobert Mustacchi 3753548f91SRobert Mustacchi #include <json_nvlist.h> 3853548f91SRobert Mustacchi 3953548f91SRobert Mustacchi #define EXIT_USAGE 2 4053548f91SRobert Mustacchi 4153548f91SRobert Mustacchi 4253548f91SRobert Mustacchi typedef struct cpc_proc { 4353548f91SRobert Mustacchi struct cpc_proc *cproc_next; 4453548f91SRobert Mustacchi uint_t cproc_family; 4553548f91SRobert Mustacchi uint_t cproc_model; 4653548f91SRobert Mustacchi } cpc_proc_t; 4753548f91SRobert Mustacchi 4853548f91SRobert Mustacchi typedef enum cpc_file_type { 4953548f91SRobert Mustacchi CPC_FILE_CORE = 1 << 0, 5053548f91SRobert Mustacchi CPC_FILE_OFF_CORE = 1 << 1, 5153548f91SRobert Mustacchi CPC_FILE_UNCORE = 1 << 2, 5253548f91SRobert Mustacchi CPC_FILE_FP_MATH = 1 << 3, 5353548f91SRobert Mustacchi CPC_FILE_UNCORE_EXP = 1 << 4 5453548f91SRobert Mustacchi } cpc_type_t; 5553548f91SRobert Mustacchi 5653548f91SRobert Mustacchi typedef struct cpc_map { 5753548f91SRobert Mustacchi struct cpc_map *cmap_next; 5853548f91SRobert Mustacchi cpc_type_t cmap_type; 5953548f91SRobert Mustacchi nvlist_t *cmap_data; 6053548f91SRobert Mustacchi char *cmap_path; 6153548f91SRobert Mustacchi const char *cmap_name; 6253548f91SRobert Mustacchi cpc_proc_t *cmap_procs; 6353548f91SRobert Mustacchi } cpc_map_t; 6453548f91SRobert Mustacchi 6553548f91SRobert Mustacchi typedef struct cpc_whitelist { 6653548f91SRobert Mustacchi const char *cwhite_short; 6753548f91SRobert Mustacchi const char *cwhite_human; 6853548f91SRobert Mustacchi uint_t cwhite_mask; 6953548f91SRobert Mustacchi } cpc_whitelist_t; 7053548f91SRobert Mustacchi 7153548f91SRobert Mustacchi /* 7253548f91SRobert Mustacchi * List of architectures that we support generating this data for. This is done 7353548f91SRobert Mustacchi * so that processors that illumos doesn't support or run on aren't generated 7453548f91SRobert Mustacchi * (generally the Xeon Phi). 7553548f91SRobert Mustacchi */ 7653548f91SRobert Mustacchi static cpc_whitelist_t cpcgen_whitelist[] = { 7753548f91SRobert Mustacchi /* Nehalem */ 7853548f91SRobert Mustacchi { "NHM-EP", "nhm_ep", CPC_FILE_CORE }, 7953548f91SRobert Mustacchi { "NHM-EX", "nhm_ex", CPC_FILE_CORE }, 8053548f91SRobert Mustacchi /* Westmere */ 8153548f91SRobert Mustacchi { "WSM-EP-DP", "wsm_ep_dp", CPC_FILE_CORE }, 8253548f91SRobert Mustacchi { "WSM-EP-SP", "wsm_ep_sp", CPC_FILE_CORE }, 8353548f91SRobert Mustacchi { "WSM-EX", "wsm_ex", CPC_FILE_CORE }, 8453548f91SRobert Mustacchi /* Sandy Bridge */ 8553548f91SRobert Mustacchi { "SNB", "snb", CPC_FILE_CORE }, 8653548f91SRobert Mustacchi { "JKT", "jkt", CPC_FILE_CORE }, 8753548f91SRobert Mustacchi /* Ivy Bridge */ 8853548f91SRobert Mustacchi { "IVB", "ivb", CPC_FILE_CORE }, 8953548f91SRobert Mustacchi { "IVT", "ivt", CPC_FILE_CORE }, 9053548f91SRobert Mustacchi /* Haswell */ 9153548f91SRobert Mustacchi { "HSW", "hsw", CPC_FILE_CORE }, 9253548f91SRobert Mustacchi { "HSX", "hsx", CPC_FILE_CORE }, 9353548f91SRobert Mustacchi /* Broadwell */ 9453548f91SRobert Mustacchi { "BDW", "bdw", CPC_FILE_CORE }, 9553548f91SRobert Mustacchi { "BDW-DE", "bdw_de", CPC_FILE_CORE }, 9653548f91SRobert Mustacchi { "BDX", "bdx", CPC_FILE_CORE }, 9753548f91SRobert Mustacchi /* Skylake */ 9853548f91SRobert Mustacchi { "SKL", "skl", CPC_FILE_CORE }, 9953548f91SRobert Mustacchi { "SKX", "skx", CPC_FILE_CORE }, 10053548f91SRobert Mustacchi /* Atom */ 10153548f91SRobert Mustacchi { "BNL", "bnl", CPC_FILE_CORE }, 10253548f91SRobert Mustacchi { "SLM", "slm", CPC_FILE_CORE }, 10353548f91SRobert Mustacchi { "GLM", "glm", CPC_FILE_CORE }, 10453548f91SRobert Mustacchi { "GLP", "glp", CPC_FILE_CORE }, 10553548f91SRobert Mustacchi { NULL } 10653548f91SRobert Mustacchi }; 10753548f91SRobert Mustacchi 10853548f91SRobert Mustacchi typedef struct cpc_papi { 10953548f91SRobert Mustacchi const char *cpapi_intc; 11053548f91SRobert Mustacchi const char *cpapi_papi; 11153548f91SRobert Mustacchi } cpc_papi_t; 11253548f91SRobert Mustacchi 11353548f91SRobert Mustacchi /* 11453548f91SRobert Mustacchi * This table maps events with an Intel specific name to the corresponding PAPI 11553548f91SRobert Mustacchi * name. There may be multiple INtel events which map to the same PAPI event. 11653548f91SRobert Mustacchi * This is usually because different processors have different names for an 11753548f91SRobert Mustacchi * event. We use the title as opposed to the event codes because those can 11853548f91SRobert Mustacchi * change somewhat arbitrarily between processor generations. 11953548f91SRobert Mustacchi */ 12053548f91SRobert Mustacchi static cpc_papi_t cpcgen_papi_map[] = { 12153548f91SRobert Mustacchi { "CPU_CLK_UNHALTED.THREAD_P", "PAPI_tot_cyc" }, 12253548f91SRobert Mustacchi { "INST_RETIRED.ANY_P", "PAPI_tot_ins" }, 12353548f91SRobert Mustacchi { "BR_INST_RETIRED.ALL_BRANCHES", "PAPI_br_ins" }, 12453548f91SRobert Mustacchi { "BR_MISP_RETIRED.ALL_BRANCHES", "PAPI_br_msp" }, 12553548f91SRobert Mustacchi { "BR_INST_RETIRED.CONDITIONAL", "PAPI_br_cn" }, 12653548f91SRobert Mustacchi { "CYCLE_ACTIVITY.CYCLES_L1D_MISS", "PAPI_l1_dcm" }, 12753548f91SRobert Mustacchi { "L1I.HITS", "PAPI_l1_ich" }, 12853548f91SRobert Mustacchi { "ICACHE.HIT", "PAPI_l1_ich" }, 12953548f91SRobert Mustacchi { "L1I.MISS", "PAPI_L1_icm" }, 13053548f91SRobert Mustacchi { "ICACHE.MISSES", "PAPI_l1_icm" }, 13153548f91SRobert Mustacchi { "L1I.READS", "PAPI_l1_ica" }, 13253548f91SRobert Mustacchi { "ICACHE.ACCESSES", "PAPI_l1_ica" }, 13353548f91SRobert Mustacchi { "L1I.READS", "PAPI_l1_icr" }, 13453548f91SRobert Mustacchi { "ICACHE.ACCESSES", "PAPI_l1_icr" }, 13553548f91SRobert Mustacchi { "L2_RQSTS.CODE_RD_MISS", "PAPI_l2_icm" }, 13653548f91SRobert Mustacchi { "L2_RQSTS.MISS", "PAPI_l2_tcm" }, 13753548f91SRobert Mustacchi { "ITLB_MISSES.MISS_CAUSES_A_WALK", "PAPI_tlb_im" }, 13853548f91SRobert Mustacchi { "DTLB_LOAD_MISSES.MISS_CAUSES_A_WALK", "PAPI_tlb_dm" }, 13953548f91SRobert Mustacchi { "PAGE_WALKS.D_SIDE_WALKS", "PAPI_tlb_dm" }, 14053548f91SRobert Mustacchi { "PAGE_WALKS.I_SIDE_WALKS", "PAPI_tlb_im" }, 14153548f91SRobert Mustacchi { "PAGE_WALKS.WALKS", "PAPI_tlb_tl" }, 14253548f91SRobert Mustacchi { "INST_QUEUE_WRITES", "PAPI_tot_iis" }, 14353548f91SRobert Mustacchi { "MEM_INST_RETIRED.STORES" "PAPI_sr_ins" }, 14453548f91SRobert Mustacchi { "MEM_INST_RETIRED.LOADS" "PAPI_ld_ins" }, 14553548f91SRobert Mustacchi { NULL, NULL } 14653548f91SRobert Mustacchi }; 14753548f91SRobert Mustacchi 14853548f91SRobert Mustacchi typedef struct cpcgen_ops { 14953548f91SRobert Mustacchi char *(*cgen_op_name)(cpc_map_t *); 15053548f91SRobert Mustacchi boolean_t (*cgen_op_file_before)(FILE *, cpc_map_t *); 15153548f91SRobert Mustacchi boolean_t (*cgen_op_file_after)(FILE *, cpc_map_t *); 15253548f91SRobert Mustacchi boolean_t (*cgen_op_event)(FILE *, nvlist_t *, const char *, uint32_t); 15353548f91SRobert Mustacchi } cpcgen_ops_t; 15453548f91SRobert Mustacchi 15553548f91SRobert Mustacchi static cpcgen_ops_t cpcgen_ops; 15653548f91SRobert Mustacchi static const char *cpcgen_mapfile = "/mapfile.csv"; 15753548f91SRobert Mustacchi static const char *cpcgen_progname; 15853548f91SRobert Mustacchi static cpc_map_t *cpcgen_maps; 15953548f91SRobert Mustacchi 16053548f91SRobert Mustacchi /* 16153548f91SRobert Mustacchi * Constants used for generating data. 16253548f91SRobert Mustacchi */ 16353548f91SRobert Mustacchi /* BEGIN CSTYLED */ 16453548f91SRobert Mustacchi static const char *cpcgen_cfile_header = "" 16553548f91SRobert Mustacchi "/*\n" 16653548f91SRobert Mustacchi " * Copyright (c) 2018, Intel Corporation\n" 16753548f91SRobert Mustacchi " * Copyright (c) 2018, Joyent, Inc\n" 16853548f91SRobert Mustacchi " * All rights reserved.\n" 16953548f91SRobert Mustacchi " *\n" 17053548f91SRobert Mustacchi " * Redistribution and use in source and binary forms, with or without\n" 17153548f91SRobert Mustacchi " * modification, are permitted provided that the following conditions are met:\n" 17253548f91SRobert Mustacchi " * \n" 17353548f91SRobert Mustacchi " * 1. Redistributions of source code must retain the above copyright notice,\n" 17453548f91SRobert Mustacchi " * this list of conditions and the following disclaimer.\n" 17553548f91SRobert Mustacchi " * \n" 17653548f91SRobert Mustacchi " * 2. Redistributions in binary form must reproduce the above copyright \n" 17753548f91SRobert Mustacchi " * notice, this list of conditions and the following disclaimer in the\n" 17853548f91SRobert Mustacchi " * documentation and/or other materials provided with the distribution.\n" 17953548f91SRobert Mustacchi " * \n" 18053548f91SRobert Mustacchi " * 3. Neither the name of the Intel Corporation nor the names of its \n" 18153548f91SRobert Mustacchi " * contributors may be used to endorse or promote products derived from\n" 18253548f91SRobert Mustacchi " * this software without specific prior written permission.\n" 18353548f91SRobert Mustacchi " *\n" 18453548f91SRobert Mustacchi " * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n" 18553548f91SRobert Mustacchi " * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n" 18653548f91SRobert Mustacchi " * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n" 18753548f91SRobert Mustacchi " * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n" 18853548f91SRobert Mustacchi " * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n" 18953548f91SRobert Mustacchi " * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n" 19053548f91SRobert Mustacchi " * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n" 19153548f91SRobert Mustacchi " * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n" 19253548f91SRobert Mustacchi " * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n" 19353548f91SRobert Mustacchi " * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n" 19453548f91SRobert Mustacchi " * POSSIBILITY OF SUCH DAMAGE.\n" 19553548f91SRobert Mustacchi " *\n" 19653548f91SRobert Mustacchi " * This file was automatically generated by cpcgen from the data file\n" 19753548f91SRobert Mustacchi " * data/perfmon%s\n" 19853548f91SRobert Mustacchi " *\n" 19953548f91SRobert Mustacchi " * Do not modify this file. Your changes will be lost!\n" 20053548f91SRobert Mustacchi " */\n" 20153548f91SRobert Mustacchi "\n"; 20253548f91SRobert Mustacchi /* END CSTYLED */ 20353548f91SRobert Mustacchi 20453548f91SRobert Mustacchi static const char *cpcgen_cfile_table_start = "" 20553548f91SRobert Mustacchi "#include <core_pcbe_table.h>\n" 20653548f91SRobert Mustacchi "\n" 20753548f91SRobert Mustacchi "const struct events_table_t pcbe_core_events_%s[] = {\n"; 20853548f91SRobert Mustacchi 20953548f91SRobert Mustacchi static const char *cpcgen_cfile_table_end = "" 21053548f91SRobert Mustacchi "\t{ NT_END, 0, 0, \"\" }\n" 21153548f91SRobert Mustacchi "};\n"; 21253548f91SRobert Mustacchi 21353548f91SRobert Mustacchi /* BEGIN CSTYLED */ 21453548f91SRobert Mustacchi static const char *cpcgen_manual_header = "" 21553548f91SRobert Mustacchi ".\\\" Copyright (c) 2018, Intel Corporation \n" 21653548f91SRobert Mustacchi ".\\\" Copyright (c) 2018, Joyent, Inc.\n" 21753548f91SRobert Mustacchi ".\\\" All rights reserved.\n" 21853548f91SRobert Mustacchi ".\\\"\n" 21953548f91SRobert Mustacchi ".\\\" Redistribution and use in source and binary forms, with or without \n" 22053548f91SRobert Mustacchi ".\\\" modification, are permitted provided that the following conditions are met:\n" 22153548f91SRobert Mustacchi ".\\\"\n" 22253548f91SRobert Mustacchi ".\\\" 1. Redistributions of source code must retain the above copyright notice,\n" 22353548f91SRobert Mustacchi ".\\\" this list of conditions and the following disclaimer.\n" 22453548f91SRobert Mustacchi ".\\\"\n" 22553548f91SRobert Mustacchi ".\\\" 2. Redistributions in binary form must reproduce the above copyright\n" 22653548f91SRobert Mustacchi ".\\\" notice, this list of conditions and the following disclaimer in the\n" 22753548f91SRobert Mustacchi ".\\\" documentation and/or other materials provided with the distribution.\n" 22853548f91SRobert Mustacchi ".\\\"\n" 22953548f91SRobert Mustacchi ".\\\" 3. Neither the name of the Intel Corporation nor the names of its\n" 23053548f91SRobert Mustacchi ".\\\" contributors may be used to endorse or promote products derived from\n" 23153548f91SRobert Mustacchi ".\\\" this software without specific prior written permission.\n" 23253548f91SRobert Mustacchi ".\\\"\n" 23353548f91SRobert Mustacchi ".\\\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n" 23453548f91SRobert Mustacchi ".\\\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n" 23553548f91SRobert Mustacchi ".\\\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n" 23653548f91SRobert Mustacchi ".\\\" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n" 23753548f91SRobert Mustacchi ".\\\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n" 23853548f91SRobert Mustacchi ".\\\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n" 23953548f91SRobert Mustacchi ".\\\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n" 24053548f91SRobert Mustacchi ".\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n" 24153548f91SRobert Mustacchi ".\\\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n" 24253548f91SRobert Mustacchi ".\\\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n" 24353548f91SRobert Mustacchi ".\\\" POSSIBILITY OF SUCH DAMAGE.\n" 24453548f91SRobert Mustacchi ".\\\"\n" 24553548f91SRobert Mustacchi ".\\\" This file was automatically generated by cpcgen from the data file\n" 24653548f91SRobert Mustacchi ".\\\" data/perfmon%s\n" 24753548f91SRobert Mustacchi ".\\\"\n" 24853548f91SRobert Mustacchi ".\\\" Do not modify this file. Your changes will be lost!\n" 24953548f91SRobert Mustacchi ".\\\"\n" 25053548f91SRobert Mustacchi ".\\\" We would like to thank Intel for providing the perfmon data for use in\n" 25153548f91SRobert Mustacchi ".\\\" our manual pages.\n" 25253548f91SRobert Mustacchi ".Dd June 18, 2018\n" 25353548f91SRobert Mustacchi ".Dt %s_EVENTS 3CPC\n" 25453548f91SRobert Mustacchi ".Os\n" 25553548f91SRobert Mustacchi ".Sh NAME\n" 25653548f91SRobert Mustacchi ".Nm %s_events\n" 25753548f91SRobert Mustacchi ".Nd processor model specific performance counter events\n" 25853548f91SRobert Mustacchi ".Sh DESCRIPTION\n" 25953548f91SRobert Mustacchi "This manual page describes events specific to the following Intel CPU\n" 26053548f91SRobert Mustacchi "models and is derived from Intel's perfmon data.\n" 26153548f91SRobert Mustacchi "For more information, please consult the Intel Software Developer's Manual " 26253548f91SRobert Mustacchi "or Intel's perfmon website.\n" 26353548f91SRobert Mustacchi ".Pp\n" 26453548f91SRobert Mustacchi "CPU models described by this document:\n" 26553548f91SRobert Mustacchi ".Bl -bullet\n"; 26653548f91SRobert Mustacchi /* END CSTYLED */ 26753548f91SRobert Mustacchi 26853548f91SRobert Mustacchi static const char *cpcgen_manual_data = "" 26953548f91SRobert Mustacchi ".El\n" 27053548f91SRobert Mustacchi ".Pp\n" 27153548f91SRobert Mustacchi "The following events are supported:\n" 27253548f91SRobert Mustacchi ".Bl -tag -width Sy\n"; 27353548f91SRobert Mustacchi 27453548f91SRobert Mustacchi static const char *cpcgen_manual_trailer = "" 27553548f91SRobert Mustacchi ".El\n" 27653548f91SRobert Mustacchi ".Sh SEE ALSO\n" 27753548f91SRobert Mustacchi ".Xr cpc 3CPC\n" 27853548f91SRobert Mustacchi ".Pp\n" 27953548f91SRobert Mustacchi ".Lk https://download.01.org/perfmon/index/"; 28053548f91SRobert Mustacchi 28153548f91SRobert Mustacchi static cpc_map_t * 28253548f91SRobert Mustacchi cpcgen_map_lookup(const char *path) 28353548f91SRobert Mustacchi { 28453548f91SRobert Mustacchi cpc_map_t *m; 28553548f91SRobert Mustacchi 28653548f91SRobert Mustacchi for (m = cpcgen_maps; m != NULL; m = m->cmap_next) { 28753548f91SRobert Mustacchi if (strcmp(path, m->cmap_path) == 0) { 28853548f91SRobert Mustacchi return (m); 28953548f91SRobert Mustacchi } 29053548f91SRobert Mustacchi } 29153548f91SRobert Mustacchi 29253548f91SRobert Mustacchi return (NULL); 29353548f91SRobert Mustacchi } 29453548f91SRobert Mustacchi 29553548f91SRobert Mustacchi /* 29653548f91SRobert Mustacchi * Parse a string of the form 'GenuineIntel-6-2E' and get out the family and 29753548f91SRobert Mustacchi * model. 29853548f91SRobert Mustacchi */ 29953548f91SRobert Mustacchi static void 30053548f91SRobert Mustacchi cpcgen_parse_model(char *fsr, uint_t *family, uint_t *model) 30153548f91SRobert Mustacchi { 30253548f91SRobert Mustacchi const char *bstr = "GenuineIntel"; 30353548f91SRobert Mustacchi const char *brand, *fam, *mod; 30453548f91SRobert Mustacchi char *last; 30553548f91SRobert Mustacchi long l; 30653548f91SRobert Mustacchi 30753548f91SRobert Mustacchi if ((brand = strtok_r(fsr, "-", &last)) == NULL || 30853548f91SRobert Mustacchi (fam = strtok_r(NULL, "-", &last)) == NULL || 30953548f91SRobert Mustacchi (mod = strtok_r(NULL, "-", &last)) == NULL) { 31053548f91SRobert Mustacchi errx(EXIT_FAILURE, "failed to parse processor id \"%s\"", fsr); 31153548f91SRobert Mustacchi } 31253548f91SRobert Mustacchi 31353548f91SRobert Mustacchi if (strcmp(bstr, brand) != 0) { 31453548f91SRobert Mustacchi errx(EXIT_FAILURE, "brand string \"%s\" did not match \"%s\"", 31553548f91SRobert Mustacchi brand, bstr); 31653548f91SRobert Mustacchi } 31753548f91SRobert Mustacchi 31853548f91SRobert Mustacchi errno = 0; 31953548f91SRobert Mustacchi l = strtol(fam, &last, 16); 320*1ad658abSJohn Levon if (errno != 0 || l < 0 || l >= INT_MAX || *last != '\0') { 32153548f91SRobert Mustacchi errx(EXIT_FAILURE, "failed to parse family \"%s\"", fam); 32253548f91SRobert Mustacchi } 32353548f91SRobert Mustacchi *family = (uint_t)l; 32453548f91SRobert Mustacchi 32553548f91SRobert Mustacchi l = strtol(mod, &last, 16); 326*1ad658abSJohn Levon if (errno != 0 || l < 0 || l >= INT_MAX || *last != '\0') { 32753548f91SRobert Mustacchi errx(EXIT_FAILURE, "failed to parse model \"%s\"", mod); 32853548f91SRobert Mustacchi } 32953548f91SRobert Mustacchi *model = (uint_t)l; 33053548f91SRobert Mustacchi } 33153548f91SRobert Mustacchi 33253548f91SRobert Mustacchi static nvlist_t * 33353548f91SRobert Mustacchi cpcgen_read_datafile(const char *datadir, const char *file) 33453548f91SRobert Mustacchi { 33553548f91SRobert Mustacchi int fd; 33653548f91SRobert Mustacchi char *path; 33753548f91SRobert Mustacchi struct stat st; 33853548f91SRobert Mustacchi void *map; 33953548f91SRobert Mustacchi nvlist_t *nvl; 34053548f91SRobert Mustacchi nvlist_parse_json_error_t jerr; 34153548f91SRobert Mustacchi 34253548f91SRobert Mustacchi if (asprintf(&path, "%s/%s", datadir, file) == -1) { 34353548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to construct path to data file %s", 34453548f91SRobert Mustacchi file); 34553548f91SRobert Mustacchi } 34653548f91SRobert Mustacchi 34753548f91SRobert Mustacchi if ((fd = open(path, O_RDONLY)) < 0) { 34853548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to open data file %s", path); 34953548f91SRobert Mustacchi } 35053548f91SRobert Mustacchi 35153548f91SRobert Mustacchi if (fstat(fd, &st) != 0) { 35253548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to stat %s", path); 35353548f91SRobert Mustacchi } 35453548f91SRobert Mustacchi 35553548f91SRobert Mustacchi if ((map = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, 35653548f91SRobert Mustacchi fd, 0)) == MAP_FAILED) { 35753548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to mmap %s", path); 35853548f91SRobert Mustacchi } 35953548f91SRobert Mustacchi 36053548f91SRobert Mustacchi if (nvlist_parse_json(map, st.st_size, &nvl, NVJSON_FORCE_INTEGER, 36153548f91SRobert Mustacchi &jerr) != 0) { 36253548f91SRobert Mustacchi errx(EXIT_FAILURE, "failed to parse file %s at pos %ld: %s", 36353548f91SRobert Mustacchi path, jerr.nje_pos, jerr.nje_message); 36453548f91SRobert Mustacchi } 36553548f91SRobert Mustacchi 36653548f91SRobert Mustacchi if (munmap(map, st.st_size) != 0) { 36753548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to munmap %s", path); 36853548f91SRobert Mustacchi } 36953548f91SRobert Mustacchi 37053548f91SRobert Mustacchi if (close(fd) != 0) { 37153548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to close data file %s", path); 37253548f91SRobert Mustacchi } 37353548f91SRobert Mustacchi free(path); 37453548f91SRobert Mustacchi 37553548f91SRobert Mustacchi return (nvl); 37653548f91SRobert Mustacchi } 37753548f91SRobert Mustacchi 37853548f91SRobert Mustacchi /* 37953548f91SRobert Mustacchi * Check the whitelist to see if we should use this model. 38053548f91SRobert Mustacchi */ 38153548f91SRobert Mustacchi static const char * 38253548f91SRobert Mustacchi cpcgen_use_arch(const char *path, cpc_type_t type, const char *platform) 38353548f91SRobert Mustacchi { 38453548f91SRobert Mustacchi const char *slash; 38553548f91SRobert Mustacchi size_t len; 38653548f91SRobert Mustacchi uint_t i; 38753548f91SRobert Mustacchi 38853548f91SRobert Mustacchi if (*path != '/') { 38953548f91SRobert Mustacchi errx(EXIT_FAILURE, "invalid path in mapfile: \"%s\": missing " 39053548f91SRobert Mustacchi "leading '/'", path); 39153548f91SRobert Mustacchi } 39253548f91SRobert Mustacchi if ((slash = strchr(path + 1, '/')) == NULL) { 39353548f91SRobert Mustacchi errx(EXIT_FAILURE, "invalid path in mapfile: \"%s\": missing " 39453548f91SRobert Mustacchi "second '/'", path); 39553548f91SRobert Mustacchi } 39653548f91SRobert Mustacchi /* Account for the last '/' character. */ 39753548f91SRobert Mustacchi len = slash - path - 1; 39853548f91SRobert Mustacchi assert(len > 0); 39953548f91SRobert Mustacchi 40053548f91SRobert Mustacchi for (i = 0; cpcgen_whitelist[i].cwhite_short != NULL; i++) { 40153548f91SRobert Mustacchi if (platform != NULL && strcasecmp(platform, 40253548f91SRobert Mustacchi cpcgen_whitelist[i].cwhite_short) != 0) 40353548f91SRobert Mustacchi continue; 40453548f91SRobert Mustacchi if (strncmp(path + 1, cpcgen_whitelist[i].cwhite_short, 40553548f91SRobert Mustacchi len) == 0 && 40653548f91SRobert Mustacchi (cpcgen_whitelist[i].cwhite_mask & type) == type) { 40753548f91SRobert Mustacchi return (cpcgen_whitelist[i].cwhite_human); 40853548f91SRobert Mustacchi } 40953548f91SRobert Mustacchi } 41053548f91SRobert Mustacchi 41153548f91SRobert Mustacchi return (NULL); 41253548f91SRobert Mustacchi } 41353548f91SRobert Mustacchi 41453548f91SRobert Mustacchi /* 41553548f91SRobert Mustacchi * Read in the mapfile.csv that is used to map between processor families and 41653548f91SRobert Mustacchi * parse this. Each line has a comma separated value. 41753548f91SRobert Mustacchi */ 41853548f91SRobert Mustacchi static void 41953548f91SRobert Mustacchi cpcgen_read_mapfile(const char *datadir, const char *platform) 42053548f91SRobert Mustacchi { 42153548f91SRobert Mustacchi FILE *map; 42253548f91SRobert Mustacchi char *mappath, *last; 42353548f91SRobert Mustacchi char *data = NULL; 42453548f91SRobert Mustacchi size_t datalen = 0; 42553548f91SRobert Mustacchi uint_t lineno; 42653548f91SRobert Mustacchi 42753548f91SRobert Mustacchi if (asprintf(&mappath, "%s/%s", datadir, cpcgen_mapfile) == -1) { 42853548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to construct path to mapfile"); 42953548f91SRobert Mustacchi } 43053548f91SRobert Mustacchi 43153548f91SRobert Mustacchi if ((map = fopen(mappath, "r")) == NULL) { 43253548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to open data mapfile %s", mappath); 43353548f91SRobert Mustacchi } 43453548f91SRobert Mustacchi 43553548f91SRobert Mustacchi lineno = 0; 43653548f91SRobert Mustacchi while (getline(&data, &datalen, map) != -1) { 43753548f91SRobert Mustacchi char *fstr, *path, *tstr; 43853548f91SRobert Mustacchi const char *name; 43953548f91SRobert Mustacchi uint_t family, model; 44053548f91SRobert Mustacchi cpc_type_t type; 44153548f91SRobert Mustacchi cpc_map_t *map; 44253548f91SRobert Mustacchi cpc_proc_t *proc; 44353548f91SRobert Mustacchi 44453548f91SRobert Mustacchi /* 44553548f91SRobert Mustacchi * The first line contains the header: 44653548f91SRobert Mustacchi * Family-model,Version,Filename,EventType 44753548f91SRobert Mustacchi */ 44853548f91SRobert Mustacchi lineno++; 44953548f91SRobert Mustacchi if (lineno == 1) { 45053548f91SRobert Mustacchi continue; 45153548f91SRobert Mustacchi } 45253548f91SRobert Mustacchi 45353548f91SRobert Mustacchi if ((fstr = strtok_r(data, ",", &last)) == NULL || 45453548f91SRobert Mustacchi strtok_r(NULL, ",", &last) == NULL || 45553548f91SRobert Mustacchi (path = strtok_r(NULL, ",", &last)) == NULL || 45653548f91SRobert Mustacchi (tstr = strtok_r(NULL, "\n", &last)) == NULL) { 45753548f91SRobert Mustacchi errx(EXIT_FAILURE, "failed to parse mapfile line " 45853548f91SRobert Mustacchi "%u in %s", lineno, mappath); 45953548f91SRobert Mustacchi } 46053548f91SRobert Mustacchi 46153548f91SRobert Mustacchi cpcgen_parse_model(fstr, &family, &model); 46253548f91SRobert Mustacchi 46353548f91SRobert Mustacchi if (strcmp(tstr, "core") == 0) { 46453548f91SRobert Mustacchi type = CPC_FILE_CORE; 46553548f91SRobert Mustacchi } else if (strcmp(tstr, "offcore") == 0) { 46653548f91SRobert Mustacchi type = CPC_FILE_OFF_CORE; 46753548f91SRobert Mustacchi } else if (strcmp(tstr, "uncore") == 0) { 46853548f91SRobert Mustacchi type = CPC_FILE_UNCORE; 46953548f91SRobert Mustacchi } else if (strcmp(tstr, "fp_arith_inst") == 0) { 47053548f91SRobert Mustacchi type = CPC_FILE_FP_MATH; 47153548f91SRobert Mustacchi } else if (strcmp(tstr, "uncore experimental") == 0) { 47253548f91SRobert Mustacchi type = CPC_FILE_UNCORE_EXP; 47353548f91SRobert Mustacchi } else { 47453548f91SRobert Mustacchi errx(EXIT_FAILURE, "unknown file type \"%s\" on line " 47553548f91SRobert Mustacchi "%u", tstr, lineno); 47653548f91SRobert Mustacchi } 47753548f91SRobert Mustacchi 47853548f91SRobert Mustacchi if ((name = cpcgen_use_arch(path, type, platform)) == NULL) 47953548f91SRobert Mustacchi continue; 48053548f91SRobert Mustacchi 48153548f91SRobert Mustacchi if ((map = cpcgen_map_lookup(path)) == NULL) { 48253548f91SRobert Mustacchi nvlist_t *parsed; 48353548f91SRobert Mustacchi 48453548f91SRobert Mustacchi parsed = cpcgen_read_datafile(datadir, path); 48553548f91SRobert Mustacchi 48653548f91SRobert Mustacchi if ((map = calloc(1, sizeof (cpc_map_t))) == NULL) { 48753548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to allocate space " 48853548f91SRobert Mustacchi "for cpc file"); 48953548f91SRobert Mustacchi } 49053548f91SRobert Mustacchi 49153548f91SRobert Mustacchi if ((map->cmap_path = strdup(path)) == NULL) { 49253548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to duplicate path " 49353548f91SRobert Mustacchi "string"); 49453548f91SRobert Mustacchi } 49553548f91SRobert Mustacchi 49653548f91SRobert Mustacchi map->cmap_type = type; 49753548f91SRobert Mustacchi map->cmap_data = parsed; 49853548f91SRobert Mustacchi map->cmap_next = cpcgen_maps; 49953548f91SRobert Mustacchi map->cmap_name = name; 50053548f91SRobert Mustacchi cpcgen_maps = map; 50153548f91SRobert Mustacchi } 50253548f91SRobert Mustacchi 50353548f91SRobert Mustacchi if ((proc = malloc(sizeof (cpc_proc_t))) == NULL) { 50453548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to allocate memory for " 50553548f91SRobert Mustacchi "family and model tracking"); 50653548f91SRobert Mustacchi } 50753548f91SRobert Mustacchi 50853548f91SRobert Mustacchi proc->cproc_family = family; 50953548f91SRobert Mustacchi proc->cproc_model = model; 51053548f91SRobert Mustacchi proc->cproc_next = map->cmap_procs; 51153548f91SRobert Mustacchi map->cmap_procs = proc; 51253548f91SRobert Mustacchi } 51353548f91SRobert Mustacchi 51453548f91SRobert Mustacchi if (errno != 0 || ferror(map)) { 51553548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to read %s", mappath); 51653548f91SRobert Mustacchi } 51753548f91SRobert Mustacchi 51853548f91SRobert Mustacchi if (fclose(map) == EOF) { 51953548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to close %s", mappath); 52053548f91SRobert Mustacchi } 52153548f91SRobert Mustacchi free(data); 52253548f91SRobert Mustacchi free(mappath); 52353548f91SRobert Mustacchi } 52453548f91SRobert Mustacchi 52553548f91SRobert Mustacchi static char * 52653548f91SRobert Mustacchi cpcgen_manual_name(cpc_map_t *map) 52753548f91SRobert Mustacchi { 52853548f91SRobert Mustacchi char *name; 52953548f91SRobert Mustacchi 53053548f91SRobert Mustacchi if (asprintf(&name, "%s_events.3cpc", map->cmap_name) == -1) { 53153548f91SRobert Mustacchi warn("failed to assemble manual page name for %s", 53253548f91SRobert Mustacchi map->cmap_path); 53353548f91SRobert Mustacchi return (NULL); 53453548f91SRobert Mustacchi } 53553548f91SRobert Mustacchi 53653548f91SRobert Mustacchi return (name); 53753548f91SRobert Mustacchi } 53853548f91SRobert Mustacchi 53953548f91SRobert Mustacchi static boolean_t 54053548f91SRobert Mustacchi cpcgen_manual_file_before(FILE *f, cpc_map_t *map) 54153548f91SRobert Mustacchi { 54253548f91SRobert Mustacchi size_t i; 54353548f91SRobert Mustacchi char *upper; 54453548f91SRobert Mustacchi cpc_proc_t *proc; 54553548f91SRobert Mustacchi 54653548f91SRobert Mustacchi if ((upper = strdup(map->cmap_name)) == NULL) { 54753548f91SRobert Mustacchi warn("failed to duplicate manual name for %s", map->cmap_name); 54853548f91SRobert Mustacchi return (B_FALSE); 54953548f91SRobert Mustacchi } 55053548f91SRobert Mustacchi 55153548f91SRobert Mustacchi for (i = 0; upper[i] != '\0'; i++) { 55253548f91SRobert Mustacchi upper[i] = toupper(upper[i]); 55353548f91SRobert Mustacchi } 55453548f91SRobert Mustacchi 55553548f91SRobert Mustacchi if (fprintf(f, cpcgen_manual_header, map->cmap_path, upper, 55653548f91SRobert Mustacchi map->cmap_name) == -1) { 55753548f91SRobert Mustacchi warn("failed to write out manual header for %s", 55853548f91SRobert Mustacchi map->cmap_name); 55953548f91SRobert Mustacchi free(upper); 56053548f91SRobert Mustacchi return (B_FALSE); 56153548f91SRobert Mustacchi } 56253548f91SRobert Mustacchi 56353548f91SRobert Mustacchi for (proc = map->cmap_procs; proc != NULL; proc = proc->cproc_next) { 56453548f91SRobert Mustacchi if (fprintf(f, ".It\n.Sy Family 0x%x, Model 0x%x\n", 56553548f91SRobert Mustacchi proc->cproc_family, proc->cproc_model) == -1) { 56653548f91SRobert Mustacchi warn("failed to write out model information for %s", 56753548f91SRobert Mustacchi map->cmap_name); 56853548f91SRobert Mustacchi free(upper); 56953548f91SRobert Mustacchi return (B_FALSE); 57053548f91SRobert Mustacchi } 57153548f91SRobert Mustacchi } 57253548f91SRobert Mustacchi 57353548f91SRobert Mustacchi if (fprintf(f, cpcgen_manual_data, map->cmap_path, upper, 57453548f91SRobert Mustacchi map->cmap_name) == -1) { 57553548f91SRobert Mustacchi warn("failed to write out manual header for %s", 57653548f91SRobert Mustacchi map->cmap_name); 57753548f91SRobert Mustacchi free(upper); 57853548f91SRobert Mustacchi return (B_FALSE); 57953548f91SRobert Mustacchi } 58053548f91SRobert Mustacchi 58153548f91SRobert Mustacchi free(upper); 58253548f91SRobert Mustacchi return (B_TRUE); 58353548f91SRobert Mustacchi } 58453548f91SRobert Mustacchi 58553548f91SRobert Mustacchi static boolean_t 58653548f91SRobert Mustacchi cpcgen_manual_file_after(FILE *f, cpc_map_t *map) 58753548f91SRobert Mustacchi { 58853548f91SRobert Mustacchi if (fprintf(f, cpcgen_manual_trailer) == -1) { 58953548f91SRobert Mustacchi warn("failed to write out manual header for %s", 59053548f91SRobert Mustacchi map->cmap_name); 59153548f91SRobert Mustacchi return (B_FALSE); 59253548f91SRobert Mustacchi } 59353548f91SRobert Mustacchi 59453548f91SRobert Mustacchi return (B_TRUE); 59553548f91SRobert Mustacchi } 59653548f91SRobert Mustacchi 59753548f91SRobert Mustacchi static boolean_t 59853548f91SRobert Mustacchi cpcgen_manual_event(FILE *f, nvlist_t *nvl, const char *path, uint32_t ent) 59953548f91SRobert Mustacchi { 60053548f91SRobert Mustacchi char *event, *lname, *brief = NULL, *public = NULL, *errata = NULL; 60153548f91SRobert Mustacchi size_t i; 60253548f91SRobert Mustacchi 60353548f91SRobert Mustacchi if (nvlist_lookup_string(nvl, "EventName", &event) != 0) { 60453548f91SRobert Mustacchi warnx("Found event without 'EventName' property " 60553548f91SRobert Mustacchi "in %s, entry %u", path, ent); 60653548f91SRobert Mustacchi return (B_FALSE); 60753548f91SRobert Mustacchi } 60853548f91SRobert Mustacchi 60953548f91SRobert Mustacchi /* 61053548f91SRobert Mustacchi * Intel uses capital names. CPC historically uses lower case names. 61153548f91SRobert Mustacchi */ 61253548f91SRobert Mustacchi if ((lname = strdup(event)) == NULL) { 61353548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to duplicate event name %s", event); 61453548f91SRobert Mustacchi } 61553548f91SRobert Mustacchi for (i = 0; lname[i] != '\0'; i++) { 61653548f91SRobert Mustacchi lname[i] = tolower(event[i]); 61753548f91SRobert Mustacchi } 61853548f91SRobert Mustacchi 61953548f91SRobert Mustacchi /* 62053548f91SRobert Mustacchi * Try to get the other event fields, but if they're not there, don't 62153548f91SRobert Mustacchi * worry about it. 62253548f91SRobert Mustacchi */ 62353548f91SRobert Mustacchi (void) nvlist_lookup_string(nvl, "BriefDescription", &brief); 62453548f91SRobert Mustacchi (void) nvlist_lookup_string(nvl, "PublicDescription", &public); 62553548f91SRobert Mustacchi (void) nvlist_lookup_string(nvl, "Errata", &errata); 62653548f91SRobert Mustacchi if (errata != NULL && (strcmp(errata, "0") == 0 || 62753548f91SRobert Mustacchi strcmp(errata, "null") == 0)) { 62853548f91SRobert Mustacchi errata = NULL; 62953548f91SRobert Mustacchi } 63053548f91SRobert Mustacchi 63153548f91SRobert Mustacchi if (fprintf(f, ".It Sy %s\n", lname) == -1) { 63253548f91SRobert Mustacchi warn("failed to write out probe entry %s", event); 63353548f91SRobert Mustacchi free(lname); 63453548f91SRobert Mustacchi return (B_FALSE); 63553548f91SRobert Mustacchi } 63653548f91SRobert Mustacchi 63753548f91SRobert Mustacchi if (public != NULL) { 63853548f91SRobert Mustacchi if (fprintf(f, "%s\n", public) == -1) { 63953548f91SRobert Mustacchi warn("failed to write out probe entry %s", event); 64053548f91SRobert Mustacchi free(lname); 64153548f91SRobert Mustacchi return (B_FALSE); 64253548f91SRobert Mustacchi } 64353548f91SRobert Mustacchi } else if (brief != NULL) { 64453548f91SRobert Mustacchi if (fprintf(f, "%s\n", brief) == -1) { 64553548f91SRobert Mustacchi warn("failed to write out probe entry %s", event); 64653548f91SRobert Mustacchi free(lname); 64753548f91SRobert Mustacchi return (B_FALSE); 64853548f91SRobert Mustacchi } 64953548f91SRobert Mustacchi } 65053548f91SRobert Mustacchi 65153548f91SRobert Mustacchi if (errata != NULL) { 65253548f91SRobert Mustacchi if (fprintf(f, ".Pp\nThe following errata may apply to this: " 65353548f91SRobert Mustacchi "%s\n", errata) == -1) { 65453548f91SRobert Mustacchi 65553548f91SRobert Mustacchi warn("failed to write out probe entry %s", event); 65653548f91SRobert Mustacchi free(lname); 65753548f91SRobert Mustacchi return (B_FALSE); 65853548f91SRobert Mustacchi } 65953548f91SRobert Mustacchi } 66053548f91SRobert Mustacchi 66153548f91SRobert Mustacchi free(lname); 66253548f91SRobert Mustacchi return (B_TRUE); 66353548f91SRobert Mustacchi } 66453548f91SRobert Mustacchi 66553548f91SRobert Mustacchi static char * 66653548f91SRobert Mustacchi cpcgen_cfile_name(cpc_map_t *map) 66753548f91SRobert Mustacchi { 66853548f91SRobert Mustacchi char *name; 66953548f91SRobert Mustacchi 67053548f91SRobert Mustacchi if (asprintf(&name, "core_pcbe_%s.c", map->cmap_name) == -1) { 67153548f91SRobert Mustacchi warn("failed to assemble file name for %s", map->cmap_path); 67253548f91SRobert Mustacchi return (NULL); 67353548f91SRobert Mustacchi } 67453548f91SRobert Mustacchi 67553548f91SRobert Mustacchi return (name); 67653548f91SRobert Mustacchi } 67753548f91SRobert Mustacchi 67853548f91SRobert Mustacchi static boolean_t 67953548f91SRobert Mustacchi cpcgen_cfile_file_before(FILE *f, cpc_map_t *map) 68053548f91SRobert Mustacchi { 68153548f91SRobert Mustacchi if (fprintf(f, cpcgen_cfile_header, map->cmap_path) == -1) { 68253548f91SRobert Mustacchi warn("failed to write header to temporary file for %s", 68353548f91SRobert Mustacchi map->cmap_path); 68453548f91SRobert Mustacchi return (B_FALSE); 68553548f91SRobert Mustacchi } 68653548f91SRobert Mustacchi 68753548f91SRobert Mustacchi if (fprintf(f, cpcgen_cfile_table_start, map->cmap_name) == -1) { 68853548f91SRobert Mustacchi warn("failed to write header to temporary file for %s", 68953548f91SRobert Mustacchi map->cmap_path); 69053548f91SRobert Mustacchi return (B_FALSE); 69153548f91SRobert Mustacchi } 69253548f91SRobert Mustacchi 69353548f91SRobert Mustacchi return (B_TRUE); 69453548f91SRobert Mustacchi } 69553548f91SRobert Mustacchi 69653548f91SRobert Mustacchi static boolean_t 69753548f91SRobert Mustacchi cpcgen_cfile_file_after(FILE *f, cpc_map_t *map) 69853548f91SRobert Mustacchi { 69953548f91SRobert Mustacchi if (fprintf(f, cpcgen_cfile_table_end) == -1) { 70053548f91SRobert Mustacchi warn("failed to write footer to temporary file for %s", 70153548f91SRobert Mustacchi map->cmap_path); 70253548f91SRobert Mustacchi return (B_FALSE); 70353548f91SRobert Mustacchi } 70453548f91SRobert Mustacchi 70553548f91SRobert Mustacchi return (B_TRUE); 70653548f91SRobert Mustacchi } 70753548f91SRobert Mustacchi 70853548f91SRobert Mustacchi static boolean_t 70953548f91SRobert Mustacchi cpcgen_cfile_event(FILE *f, nvlist_t *nvl, const char *path, uint_t ent) 71053548f91SRobert Mustacchi { 71153548f91SRobert Mustacchi char *ecode, *umask, *name, *counter, *lname, *cmask; 71253548f91SRobert Mustacchi size_t i; 71353548f91SRobert Mustacchi 71453548f91SRobert Mustacchi if (nvlist_lookup_string(nvl, "EventName", &name) != 0) { 71553548f91SRobert Mustacchi warnx("Found event without 'EventName' property " 71653548f91SRobert Mustacchi "in %s, entry %u", path, ent); 71753548f91SRobert Mustacchi return (B_FALSE); 71853548f91SRobert Mustacchi } 71953548f91SRobert Mustacchi 72053548f91SRobert Mustacchi if (nvlist_lookup_string(nvl, "EventCode", &ecode) != 0 || 72153548f91SRobert Mustacchi nvlist_lookup_string(nvl, "UMask", &umask) != 0 || 72253548f91SRobert Mustacchi nvlist_lookup_string(nvl, "Counter", &counter) != 0) { 72353548f91SRobert Mustacchi warnx("event %s (index %u) from %s, missing " 72453548f91SRobert Mustacchi "required properties for C file translation", 72553548f91SRobert Mustacchi name, ent, path); 72653548f91SRobert Mustacchi return (B_FALSE); 72753548f91SRobert Mustacchi } 72853548f91SRobert Mustacchi 72953548f91SRobert Mustacchi /* 73053548f91SRobert Mustacchi * While we could try and parse the counters manually, just do this the 73153548f91SRobert Mustacchi * max power way for now based on all possible values. 73253548f91SRobert Mustacchi */ 73353548f91SRobert Mustacchi if (strcmp(counter, "0") == 0 || strcmp(counter, "0,") == 0) { 73453548f91SRobert Mustacchi cmask = "C0"; 73553548f91SRobert Mustacchi } else if (strcmp(counter, "1") == 0) { 73653548f91SRobert Mustacchi cmask = "C1"; 73753548f91SRobert Mustacchi } else if (strcmp(counter, "2") == 0) { 73853548f91SRobert Mustacchi cmask = "C2"; 73953548f91SRobert Mustacchi } else if (strcmp(counter, "3") == 0) { 74053548f91SRobert Mustacchi cmask = "C3"; 74153548f91SRobert Mustacchi } else if (strcmp(counter, "0,1") == 0) { 74253548f91SRobert Mustacchi cmask = "C0|C1"; 74353548f91SRobert Mustacchi } else if (strcmp(counter, "0,1,2") == 0) { 74453548f91SRobert Mustacchi cmask = "C0|C1|C2"; 74553548f91SRobert Mustacchi } else if (strcmp(counter, "0,1,2,3") == 0) { 74653548f91SRobert Mustacchi cmask = "C0|C1|C2|C3"; 74753548f91SRobert Mustacchi } else if (strcmp(counter, "0,2,3") == 0) { 74853548f91SRobert Mustacchi cmask = "C0|C2|C3"; 74953548f91SRobert Mustacchi } else if (strcmp(counter, "1,2,3") == 0) { 75053548f91SRobert Mustacchi cmask = "C1|C2|C3"; 75153548f91SRobert Mustacchi } else if (strcmp(counter, "2,3") == 0) { 75253548f91SRobert Mustacchi cmask = "C2|C3"; 75353548f91SRobert Mustacchi } else { 75453548f91SRobert Mustacchi warnx("event %s (index %u) from %s, has unknown " 75553548f91SRobert Mustacchi "counter value \"%s\"", name, ent, path, counter); 75653548f91SRobert Mustacchi return (B_FALSE); 75753548f91SRobert Mustacchi } 75853548f91SRobert Mustacchi 75953548f91SRobert Mustacchi 76053548f91SRobert Mustacchi /* 76153548f91SRobert Mustacchi * Intel uses capital names. CPC historically uses lower case names. 76253548f91SRobert Mustacchi */ 76353548f91SRobert Mustacchi if ((lname = strdup(name)) == NULL) { 76453548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to duplicate event name %s", name); 76553548f91SRobert Mustacchi } 76653548f91SRobert Mustacchi for (i = 0; lname[i] != '\0'; i++) { 76753548f91SRobert Mustacchi lname[i] = tolower(name[i]); 76853548f91SRobert Mustacchi } 76953548f91SRobert Mustacchi 77053548f91SRobert Mustacchi if (fprintf(f, "\t{ %s, %s, %s, \"%s\" },\n", ecode, umask, cmask, 77153548f91SRobert Mustacchi lname) == -1) { 77253548f91SRobert Mustacchi warn("failed to write out entry %s from %s", name, path); 77353548f91SRobert Mustacchi free(lname); 77453548f91SRobert Mustacchi return (B_FALSE); 77553548f91SRobert Mustacchi } 77653548f91SRobert Mustacchi 77753548f91SRobert Mustacchi free(lname); 77853548f91SRobert Mustacchi 77953548f91SRobert Mustacchi /* 78053548f91SRobert Mustacchi * Check if we have any PAPI aliases. 78153548f91SRobert Mustacchi */ 78253548f91SRobert Mustacchi for (i = 0; cpcgen_papi_map[i].cpapi_intc != NULL; i++) { 78353548f91SRobert Mustacchi if (strcmp(name, cpcgen_papi_map[i].cpapi_intc) != 0) 78453548f91SRobert Mustacchi continue; 78553548f91SRobert Mustacchi 78653548f91SRobert Mustacchi if (fprintf(f, "\t{ %s, %s, %s, \"%s\" },\n", ecode, umask, 78753548f91SRobert Mustacchi cmask, cpcgen_papi_map[i].cpapi_papi) == -1) { 78853548f91SRobert Mustacchi warn("failed to write out entry %s from %s", name, 78953548f91SRobert Mustacchi path); 79053548f91SRobert Mustacchi return (B_FALSE); 79153548f91SRobert Mustacchi } 79253548f91SRobert Mustacchi } 79353548f91SRobert Mustacchi 79453548f91SRobert Mustacchi return (B_TRUE); 79553548f91SRobert Mustacchi } 79653548f91SRobert Mustacchi 79753548f91SRobert Mustacchi /* 79853548f91SRobert Mustacchi * Generate a header file that declares all of these arrays and provide a map 79953548f91SRobert Mustacchi * for models to the corresponding table to use. 80053548f91SRobert Mustacchi */ 80153548f91SRobert Mustacchi static void 80253548f91SRobert Mustacchi cpcgen_common_files(int dirfd) 80353548f91SRobert Mustacchi { 80453548f91SRobert Mustacchi const char *fname = "core_pcbe_cpcgen.h"; 80553548f91SRobert Mustacchi char *tmpname; 80653548f91SRobert Mustacchi int fd; 80753548f91SRobert Mustacchi FILE *f; 80853548f91SRobert Mustacchi cpc_map_t *map; 80953548f91SRobert Mustacchi 81053548f91SRobert Mustacchi if (asprintf(&tmpname, ".%s.%d", fname, getpid()) == -1) { 81153548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to construct temporary file name"); 81253548f91SRobert Mustacchi } 81353548f91SRobert Mustacchi 81453548f91SRobert Mustacchi if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0644)) < 0) { 81553548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to create temporary file %s", 81653548f91SRobert Mustacchi tmpname); 81753548f91SRobert Mustacchi } 81853548f91SRobert Mustacchi 81953548f91SRobert Mustacchi if ((f = fdopen(fd, "w")) == NULL) { 82053548f91SRobert Mustacchi int e = errno; 82153548f91SRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 82253548f91SRobert Mustacchi errno = e; 82353548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to fdopen temporary file"); 82453548f91SRobert Mustacchi } 82553548f91SRobert Mustacchi 82653548f91SRobert Mustacchi if (fprintf(f, cpcgen_cfile_header, cpcgen_mapfile) == -1) { 82753548f91SRobert Mustacchi int e = errno; 82853548f91SRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 82953548f91SRobert Mustacchi errno = e; 83053548f91SRobert Mustacchi errx(EXIT_FAILURE, "failed to write header to temporary file " 83153548f91SRobert Mustacchi "for %s", fname); 83253548f91SRobert Mustacchi } 83353548f91SRobert Mustacchi 83453548f91SRobert Mustacchi if (fprintf(f, "#ifndef _CORE_PCBE_CPCGEN_H\n" 83553548f91SRobert Mustacchi "#define\t_CORE_PCBE_CPCGEN_H\n" 83653548f91SRobert Mustacchi "\n" 83753548f91SRobert Mustacchi "#ifdef __cplusplus\n" 83853548f91SRobert Mustacchi "extern \"C\" {\n" 83953548f91SRobert Mustacchi "#endif\n" 84053548f91SRobert Mustacchi "\n" 84153548f91SRobert Mustacchi "extern const struct events_table_t *core_cpcgen_table(uint_t);\n" 84253548f91SRobert Mustacchi "\n") == -1) { 84353548f91SRobert Mustacchi int e = errno; 84453548f91SRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 84553548f91SRobert Mustacchi errno = e; 84653548f91SRobert Mustacchi errx(EXIT_FAILURE, "failed to write header to " 84753548f91SRobert Mustacchi "temporary file for %s", fname); 84853548f91SRobert Mustacchi } 84953548f91SRobert Mustacchi 85053548f91SRobert Mustacchi for (map = cpcgen_maps; map != NULL; map = map->cmap_next) { 85153548f91SRobert Mustacchi if (fprintf(f, "extern const struct events_table_t " 85253548f91SRobert Mustacchi "pcbe_core_events_%s[];\n", map->cmap_name) == -1) { 85353548f91SRobert Mustacchi int e = errno; 85453548f91SRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 85553548f91SRobert Mustacchi errno = e; 85653548f91SRobert Mustacchi errx(EXIT_FAILURE, "failed to write entry to " 85753548f91SRobert Mustacchi "temporary file for %s", fname); 85853548f91SRobert Mustacchi } 85953548f91SRobert Mustacchi } 86053548f91SRobert Mustacchi 86153548f91SRobert Mustacchi if (fprintf(f, "\n" 86253548f91SRobert Mustacchi "#ifdef __cplusplus\n" 86353548f91SRobert Mustacchi "}\n" 86453548f91SRobert Mustacchi "#endif\n" 86553548f91SRobert Mustacchi "\n" 86653548f91SRobert Mustacchi "#endif /* _CORE_PCBE_CPCGEN_H */\n") == -1) { 86753548f91SRobert Mustacchi int e = errno; 86853548f91SRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 86953548f91SRobert Mustacchi errno = e; 87053548f91SRobert Mustacchi errx(EXIT_FAILURE, "failed to write header to " 87153548f91SRobert Mustacchi "temporary file for %s", fname); 87253548f91SRobert Mustacchi } 87353548f91SRobert Mustacchi 87453548f91SRobert Mustacchi if (fflush(f) != 0 || fclose(f) != 0) { 87553548f91SRobert Mustacchi int e = errno; 87653548f91SRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 87753548f91SRobert Mustacchi errno = e; 87853548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to flush and close temporary file"); 87953548f91SRobert Mustacchi } 88053548f91SRobert Mustacchi 88153548f91SRobert Mustacchi if (renameat(dirfd, tmpname, dirfd, fname) != 0) { 88253548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to rename temporary file %s", 88353548f91SRobert Mustacchi tmpname); 88453548f91SRobert Mustacchi } 88553548f91SRobert Mustacchi 88653548f91SRobert Mustacchi free(tmpname); 88753548f91SRobert Mustacchi 88853548f91SRobert Mustacchi /* Now again for the .c file. */ 88953548f91SRobert Mustacchi fname = "core_pcbe_cpcgen.c"; 89053548f91SRobert Mustacchi if (asprintf(&tmpname, ".%s.%d", fname, getpid()) == -1) { 89153548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to construct temporary file name"); 89253548f91SRobert Mustacchi } 89353548f91SRobert Mustacchi 89453548f91SRobert Mustacchi if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0644)) < 0) { 89553548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to create temporary file %s", 89653548f91SRobert Mustacchi tmpname); 89753548f91SRobert Mustacchi } 89853548f91SRobert Mustacchi 89953548f91SRobert Mustacchi if ((f = fdopen(fd, "w")) == NULL) { 90053548f91SRobert Mustacchi int e = errno; 90153548f91SRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 90253548f91SRobert Mustacchi errno = e; 90353548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to fdopen temporary file"); 90453548f91SRobert Mustacchi } 90553548f91SRobert Mustacchi 90653548f91SRobert Mustacchi if (fprintf(f, cpcgen_cfile_header, cpcgen_mapfile) == -1) { 90753548f91SRobert Mustacchi int e = errno; 90853548f91SRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 90953548f91SRobert Mustacchi errno = e; 91053548f91SRobert Mustacchi errx(EXIT_FAILURE, "failed to write header to temporary file " 91153548f91SRobert Mustacchi "for %s", fname); 91253548f91SRobert Mustacchi } 91353548f91SRobert Mustacchi 91453548f91SRobert Mustacchi if (fprintf(f, "#include <core_pcbe_table.h>\n" 91553548f91SRobert Mustacchi "#include <sys/null.h>\n" 91653548f91SRobert Mustacchi "#include \"core_pcbe_cpcgen.h\"\n" 91753548f91SRobert Mustacchi "\n" 91853548f91SRobert Mustacchi "const struct events_table_t *\n" 91953548f91SRobert Mustacchi "core_cpcgen_table(uint_t model)\n" 92053548f91SRobert Mustacchi "{\n" 92153548f91SRobert Mustacchi "\tswitch (model) {\n") == -1) { 92253548f91SRobert Mustacchi int e = errno; 92353548f91SRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 92453548f91SRobert Mustacchi errno = e; 92553548f91SRobert Mustacchi errx(EXIT_FAILURE, "failed to write header to " 92653548f91SRobert Mustacchi "temporary file for %s", fname); 92753548f91SRobert Mustacchi } 92853548f91SRobert Mustacchi 92953548f91SRobert Mustacchi for (map = cpcgen_maps; map != NULL; map = map->cmap_next) { 93053548f91SRobert Mustacchi cpc_proc_t *p; 93153548f91SRobert Mustacchi for (p = map->cmap_procs; p != NULL; p = p->cproc_next) { 93253548f91SRobert Mustacchi assert(p->cproc_family == 6); 93353548f91SRobert Mustacchi if (fprintf(f, "\t\tcase 0x%x:\n", p->cproc_model) == 93453548f91SRobert Mustacchi -1) { 93553548f91SRobert Mustacchi int e = errno; 93653548f91SRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 93753548f91SRobert Mustacchi errno = e; 93853548f91SRobert Mustacchi errx(EXIT_FAILURE, "failed to write header to " 93953548f91SRobert Mustacchi "temporary file for %s", fname); 94053548f91SRobert Mustacchi } 94153548f91SRobert Mustacchi } 94253548f91SRobert Mustacchi if (fprintf(f, "\t\t\treturn (pcbe_core_events_%s);\n", 94353548f91SRobert Mustacchi map->cmap_name) == -1) { 94453548f91SRobert Mustacchi int e = errno; 94553548f91SRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 94653548f91SRobert Mustacchi errno = e; 94753548f91SRobert Mustacchi errx(EXIT_FAILURE, "failed to write entry to " 94853548f91SRobert Mustacchi "temporary file for %s", fname); 94953548f91SRobert Mustacchi } 95053548f91SRobert Mustacchi } 95153548f91SRobert Mustacchi 95253548f91SRobert Mustacchi if (fprintf(f, "\t\tdefault:\n" 95353548f91SRobert Mustacchi "\t\t\treturn (NULL);\n" 95453548f91SRobert Mustacchi "\t}\n" 95553548f91SRobert Mustacchi "}\n") == -1) { 95653548f91SRobert Mustacchi int e = errno; 95753548f91SRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 95853548f91SRobert Mustacchi errno = e; 95953548f91SRobert Mustacchi errx(EXIT_FAILURE, "failed to write header to " 96053548f91SRobert Mustacchi "temporary file for %s", fname); 96153548f91SRobert Mustacchi } 96253548f91SRobert Mustacchi 96353548f91SRobert Mustacchi if (fflush(f) != 0 || fclose(f) != 0) { 96453548f91SRobert Mustacchi int e = errno; 96553548f91SRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 96653548f91SRobert Mustacchi errno = e; 96753548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to flush and close temporary file"); 96853548f91SRobert Mustacchi } 96953548f91SRobert Mustacchi 97053548f91SRobert Mustacchi if (renameat(dirfd, tmpname, dirfd, fname) != 0) { 97153548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to rename temporary file %s", 97253548f91SRobert Mustacchi tmpname); 97353548f91SRobert Mustacchi } 97453548f91SRobert Mustacchi 97553548f91SRobert Mustacchi free(tmpname); 97653548f91SRobert Mustacchi } 97753548f91SRobert Mustacchi 97853548f91SRobert Mustacchi /* 97953548f91SRobert Mustacchi * Look at a rule to determine whether or not we should consider including it or 98053548f91SRobert Mustacchi * not. At this point we've already filtered things such that we only get core 98153548f91SRobert Mustacchi * events. 98253548f91SRobert Mustacchi * 98353548f91SRobert Mustacchi * To consider an entry, we currently apply the following criteria: 98453548f91SRobert Mustacchi * 98553548f91SRobert Mustacchi * - The MSRIndex and MSRValue are zero. Programming additional MSRs is no 98653548f91SRobert Mustacchi * supported right now. 98753548f91SRobert Mustacchi * - TakenAlone is non-zero, which means that it cannot run at the same time as 98853548f91SRobert Mustacchi * another field. 98953548f91SRobert Mustacchi * - Offcore is one, indicating that it is off the core and we need to figure 99053548f91SRobert Mustacchi * out if we can support this. 99153548f91SRobert Mustacchi * - If the counter is fixed, don't use it for now. 99253548f91SRobert Mustacchi * - If more than one value is specified in the EventCode or UMask values 99353548f91SRobert Mustacchi */ 99453548f91SRobert Mustacchi static boolean_t 99553548f91SRobert Mustacchi cpcgen_skip_entry(nvlist_t *nvl, const char *path, uint_t ent) 99653548f91SRobert Mustacchi { 99753548f91SRobert Mustacchi char *event, *msridx, *msrval, *taken, *offcore, *counter; 99853548f91SRobert Mustacchi char *ecode, *umask; 99953548f91SRobert Mustacchi 100053548f91SRobert Mustacchi /* 100153548f91SRobert Mustacchi * Require EventName, it's kind of useless without that. 100253548f91SRobert Mustacchi */ 100353548f91SRobert Mustacchi if (nvlist_lookup_string(nvl, "EventName", &event) != 0) { 100453548f91SRobert Mustacchi errx(EXIT_FAILURE, "Found event without 'EventName' property " 100553548f91SRobert Mustacchi "in %s, entry %u", path, ent); 100653548f91SRobert Mustacchi } 100753548f91SRobert Mustacchi 100853548f91SRobert Mustacchi /* 100953548f91SRobert Mustacchi * If we can't find an expected value, whine about it. 101053548f91SRobert Mustacchi */ 101153548f91SRobert Mustacchi if (nvlist_lookup_string(nvl, "MSRIndex", &msridx) != 0 || 101253548f91SRobert Mustacchi nvlist_lookup_string(nvl, "MSRValue", &msrval) != 0 || 101353548f91SRobert Mustacchi nvlist_lookup_string(nvl, "Counter", &counter) != 0 || 101453548f91SRobert Mustacchi nvlist_lookup_string(nvl, "EventCode", &ecode) != 0 || 101553548f91SRobert Mustacchi nvlist_lookup_string(nvl, "UMask", &umask) != 0 || 101653548f91SRobert Mustacchi nvlist_lookup_string(nvl, "Offcore", &offcore) != 0) { 101753548f91SRobert Mustacchi warnx("Skipping event %s (index %u) from %s, missing required " 101853548f91SRobert Mustacchi "property", event, ent, path); 101953548f91SRobert Mustacchi return (B_TRUE); 102053548f91SRobert Mustacchi } 102153548f91SRobert Mustacchi 102253548f91SRobert Mustacchi /* 102353548f91SRobert Mustacchi * MSRIndex and MSRvalue comes as either "0" or "0x00". 102453548f91SRobert Mustacchi */ 102553548f91SRobert Mustacchi if ((strcmp(msridx, "0") != 0 && strcmp(msridx, "0x00") != 0) || 102653548f91SRobert Mustacchi (strcmp(msrval, "0") != 0 && strcmp(msridx, "0x00") != 0) || 102753548f91SRobert Mustacchi strcmp(offcore, "0") != 0 || strchr(ecode, ',') != NULL || 102853548f91SRobert Mustacchi strchr(umask, ',') != NULL) { 102953548f91SRobert Mustacchi return (B_TRUE); 103053548f91SRobert Mustacchi } 103153548f91SRobert Mustacchi 103253548f91SRobert Mustacchi /* 103353548f91SRobert Mustacchi * Unfortunately, not everything actually has "TakenAlone". If it 103453548f91SRobert Mustacchi * doesn't, we assume that it doesn't have to be. 103553548f91SRobert Mustacchi */ 103653548f91SRobert Mustacchi if (nvlist_lookup_string(nvl, "TakenAlone", &taken) == 0 && 103753548f91SRobert Mustacchi strcmp(taken, "0") != 0) { 103853548f91SRobert Mustacchi return (B_TRUE); 103953548f91SRobert Mustacchi } 104053548f91SRobert Mustacchi 104153548f91SRobert Mustacchi 104253548f91SRobert Mustacchi if (strncasecmp(counter, "fixed", strlen("fixed")) == 0) 104353548f91SRobert Mustacchi return (B_TRUE); 104453548f91SRobert Mustacchi 104553548f91SRobert Mustacchi return (B_FALSE); 104653548f91SRobert Mustacchi } 104753548f91SRobert Mustacchi 104853548f91SRobert Mustacchi /* 104953548f91SRobert Mustacchi * For each processor family, generate a data file that contains all of the 105053548f91SRobert Mustacchi * events that we support. Also generate a header that can be included that 105153548f91SRobert Mustacchi * declares all of the tables. 105253548f91SRobert Mustacchi */ 105353548f91SRobert Mustacchi static void 105453548f91SRobert Mustacchi cpcgen_gen(int dirfd) 105553548f91SRobert Mustacchi { 105653548f91SRobert Mustacchi cpc_map_t *map = cpcgen_maps; 105753548f91SRobert Mustacchi 105853548f91SRobert Mustacchi if (map == NULL) { 105953548f91SRobert Mustacchi errx(EXIT_FAILURE, "no platforms found or matched"); 106053548f91SRobert Mustacchi } 106153548f91SRobert Mustacchi 106253548f91SRobert Mustacchi for (map = cpcgen_maps; map != NULL; map = map->cmap_next) { 106353548f91SRobert Mustacchi int fd, ret; 106453548f91SRobert Mustacchi FILE *f; 106553548f91SRobert Mustacchi char *tmpname, *name; 106653548f91SRobert Mustacchi uint32_t length, i; 106753548f91SRobert Mustacchi 106853548f91SRobert Mustacchi if ((name = cpcgen_ops.cgen_op_name(map)) == NULL) { 106953548f91SRobert Mustacchi exit(EXIT_FAILURE); 107053548f91SRobert Mustacchi } 107153548f91SRobert Mustacchi 107253548f91SRobert Mustacchi if (asprintf(&tmpname, ".%s.%d", name, getpid()) == -1) { 107353548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to construct temporary file " 107453548f91SRobert Mustacchi "name"); 107553548f91SRobert Mustacchi } 107653548f91SRobert Mustacchi 107753548f91SRobert Mustacchi if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0444)) < 0) { 107853548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to create temporary file %s", 107953548f91SRobert Mustacchi tmpname); 108053548f91SRobert Mustacchi } 108153548f91SRobert Mustacchi 108253548f91SRobert Mustacchi if ((f = fdopen(fd, "w")) == NULL) { 108353548f91SRobert Mustacchi int e = errno; 108453548f91SRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 108553548f91SRobert Mustacchi errno = e; 108653548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to fdopen temporary file"); 108753548f91SRobert Mustacchi } 108853548f91SRobert Mustacchi 108953548f91SRobert Mustacchi if (!cpcgen_ops.cgen_op_file_before(f, map)) { 109053548f91SRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 109153548f91SRobert Mustacchi exit(EXIT_FAILURE); 109253548f91SRobert Mustacchi } 109353548f91SRobert Mustacchi 109453548f91SRobert Mustacchi /* 109553548f91SRobert Mustacchi * Iterate over array contents. 109653548f91SRobert Mustacchi */ 109753548f91SRobert Mustacchi if ((ret = nvlist_lookup_uint32(map->cmap_data, "length", 109853548f91SRobert Mustacchi &length)) != 0) { 109953548f91SRobert Mustacchi errx(EXIT_FAILURE, "failed to look up length property " 110053548f91SRobert Mustacchi "in parsed data for %s: %s", map->cmap_path, 110153548f91SRobert Mustacchi strerror(ret)); 110253548f91SRobert Mustacchi } 110353548f91SRobert Mustacchi 110453548f91SRobert Mustacchi for (i = 0; i < length; i++) { 110553548f91SRobert Mustacchi nvlist_t *nvl; 110653548f91SRobert Mustacchi char num[64]; 110753548f91SRobert Mustacchi 110853548f91SRobert Mustacchi (void) snprintf(num, sizeof (num), "%u", i); 110953548f91SRobert Mustacchi if ((ret = nvlist_lookup_nvlist(map->cmap_data, 111053548f91SRobert Mustacchi num, &nvl)) != 0) { 111153548f91SRobert Mustacchi errx(EXIT_FAILURE, "failed to look up array " 111253548f91SRobert Mustacchi "entry %u in parsed data for %s: %s", i, 111353548f91SRobert Mustacchi map->cmap_path, strerror(ret)); 111453548f91SRobert Mustacchi } 111553548f91SRobert Mustacchi 111653548f91SRobert Mustacchi if (cpcgen_skip_entry(nvl, map->cmap_path, i)) 111753548f91SRobert Mustacchi continue; 111853548f91SRobert Mustacchi 111953548f91SRobert Mustacchi if (!cpcgen_ops.cgen_op_event(f, nvl, map->cmap_path, 112053548f91SRobert Mustacchi i)) { 112153548f91SRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 112253548f91SRobert Mustacchi exit(EXIT_FAILURE); 112353548f91SRobert Mustacchi } 112453548f91SRobert Mustacchi } 112553548f91SRobert Mustacchi 112653548f91SRobert Mustacchi if (!cpcgen_ops.cgen_op_file_after(f, map)) { 112753548f91SRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 112853548f91SRobert Mustacchi exit(EXIT_FAILURE); 112953548f91SRobert Mustacchi } 113053548f91SRobert Mustacchi 113153548f91SRobert Mustacchi if (fflush(f) != 0 || fclose(f) != 0) { 113253548f91SRobert Mustacchi int e = errno; 113353548f91SRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 113453548f91SRobert Mustacchi errno = e; 113553548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to flush and close " 113653548f91SRobert Mustacchi "temporary file"); 113753548f91SRobert Mustacchi } 113853548f91SRobert Mustacchi 113953548f91SRobert Mustacchi if (renameat(dirfd, tmpname, dirfd, name) != 0) { 114053548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to rename temporary file %s", 114153548f91SRobert Mustacchi tmpname); 114253548f91SRobert Mustacchi } 114353548f91SRobert Mustacchi 114453548f91SRobert Mustacchi free(name); 114553548f91SRobert Mustacchi free(tmpname); 114653548f91SRobert Mustacchi } 114753548f91SRobert Mustacchi } 114853548f91SRobert Mustacchi 114953548f91SRobert Mustacchi static void 115053548f91SRobert Mustacchi cpcgen_usage(const char *fmt, ...) 115153548f91SRobert Mustacchi { 115253548f91SRobert Mustacchi if (fmt != NULL) { 115353548f91SRobert Mustacchi va_list ap; 115453548f91SRobert Mustacchi 115553548f91SRobert Mustacchi (void) fprintf(stderr, "%s: ", cpcgen_progname); 115653548f91SRobert Mustacchi va_start(ap, fmt); 115753548f91SRobert Mustacchi (void) vfprintf(stderr, fmt, ap); 115853548f91SRobert Mustacchi va_end(ap); 115953548f91SRobert Mustacchi } 116053548f91SRobert Mustacchi 116153548f91SRobert Mustacchi (void) fprintf(stderr, "Usage: %s -a|-p platform -c|-H|-m -d datadir " 116253548f91SRobert Mustacchi "-o outdir\n" 116353548f91SRobert Mustacchi "\n" 116453548f91SRobert Mustacchi "\t-a generate data for all platforms\n" 116553548f91SRobert Mustacchi "\t-c generate C file for CPC\n" 116653548f91SRobert Mustacchi "\t-d specify the directory containt perfmon data\n" 116753548f91SRobert Mustacchi "\t-h generate header file and common files\n" 116853548f91SRobert Mustacchi "\t-m generate manual pages for CPC data\n" 116953548f91SRobert Mustacchi "\t-o outut files in directory outdir\n" 117053548f91SRobert Mustacchi "\t-p generate data for a specified platform\n", 117153548f91SRobert Mustacchi cpcgen_progname); 117253548f91SRobert Mustacchi } 117353548f91SRobert Mustacchi 117453548f91SRobert Mustacchi int 117553548f91SRobert Mustacchi main(int argc, char *argv[]) 117653548f91SRobert Mustacchi { 117753548f91SRobert Mustacchi int c, outdirfd; 117853548f91SRobert Mustacchi boolean_t do_mpage = B_FALSE, do_cfile = B_FALSE, do_header = B_FALSE, 117953548f91SRobert Mustacchi do_all = B_FALSE; 118053548f91SRobert Mustacchi const char *datadir = NULL, *outdir = NULL, *platform = NULL; 118153548f91SRobert Mustacchi uint_t count = 0; 118253548f91SRobert Mustacchi 118353548f91SRobert Mustacchi cpcgen_progname = basename(argv[0]); 118453548f91SRobert Mustacchi 118553548f91SRobert Mustacchi while ((c = getopt(argc, argv, ":acd:hHmo:p:")) != -1) { 118653548f91SRobert Mustacchi switch (c) { 118753548f91SRobert Mustacchi case 'a': 118853548f91SRobert Mustacchi do_all = B_TRUE; 118953548f91SRobert Mustacchi break; 119053548f91SRobert Mustacchi case 'c': 119153548f91SRobert Mustacchi do_cfile = B_TRUE; 119253548f91SRobert Mustacchi break; 119353548f91SRobert Mustacchi case 'd': 119453548f91SRobert Mustacchi datadir = optarg; 119553548f91SRobert Mustacchi break; 119653548f91SRobert Mustacchi case 'm': 119753548f91SRobert Mustacchi do_mpage = B_TRUE; 119853548f91SRobert Mustacchi break; 119953548f91SRobert Mustacchi case 'H': 120053548f91SRobert Mustacchi do_header = B_TRUE; 120153548f91SRobert Mustacchi break; 120253548f91SRobert Mustacchi case 'o': 120353548f91SRobert Mustacchi outdir = optarg; 120453548f91SRobert Mustacchi break; 120553548f91SRobert Mustacchi case 'p': 120653548f91SRobert Mustacchi platform = optarg; 120753548f91SRobert Mustacchi break; 120853548f91SRobert Mustacchi case ':': 120953548f91SRobert Mustacchi cpcgen_usage("Option -%c requires an operand\n", 121053548f91SRobert Mustacchi optopt); 121153548f91SRobert Mustacchi return (2); 121253548f91SRobert Mustacchi case '?': 121353548f91SRobert Mustacchi cpcgen_usage("Unknown option: -%c\n", optopt); 121453548f91SRobert Mustacchi return (2); 121553548f91SRobert Mustacchi case 'h': 121653548f91SRobert Mustacchi default: 121753548f91SRobert Mustacchi cpcgen_usage(NULL); 121853548f91SRobert Mustacchi return (2); 121953548f91SRobert Mustacchi } 122053548f91SRobert Mustacchi } 122153548f91SRobert Mustacchi 122253548f91SRobert Mustacchi count = 0; 122353548f91SRobert Mustacchi if (do_mpage) 122453548f91SRobert Mustacchi count++; 122553548f91SRobert Mustacchi if (do_cfile) 122653548f91SRobert Mustacchi count++; 122753548f91SRobert Mustacchi if (do_header) 122853548f91SRobert Mustacchi count++; 122953548f91SRobert Mustacchi if (count > 1) { 123053548f91SRobert Mustacchi cpcgen_usage("Only one of -c, -h, and -m may be specified\n"); 123153548f91SRobert Mustacchi return (2); 123253548f91SRobert Mustacchi } else if (count == 0) { 123353548f91SRobert Mustacchi cpcgen_usage("One of -c, -h, and -m is required\n"); 123453548f91SRobert Mustacchi return (2); 123553548f91SRobert Mustacchi } 123653548f91SRobert Mustacchi 123753548f91SRobert Mustacchi count = 0; 123853548f91SRobert Mustacchi if (do_all) 123953548f91SRobert Mustacchi count++; 124053548f91SRobert Mustacchi if (platform != NULL) 124153548f91SRobert Mustacchi count++; 124253548f91SRobert Mustacchi if (count > 1) { 124353548f91SRobert Mustacchi cpcgen_usage("Only one of -a and -p may be specified\n"); 124453548f91SRobert Mustacchi return (2); 124553548f91SRobert Mustacchi } else if (count == 0) { 124653548f91SRobert Mustacchi cpcgen_usage("One of -a and -p is required\n"); 124753548f91SRobert Mustacchi return (2); 124853548f91SRobert Mustacchi } 124953548f91SRobert Mustacchi 125053548f91SRobert Mustacchi 125153548f91SRobert Mustacchi if (outdir == NULL) { 125253548f91SRobert Mustacchi cpcgen_usage("Missing required output directory (-o)\n"); 125353548f91SRobert Mustacchi return (2); 125453548f91SRobert Mustacchi } 125553548f91SRobert Mustacchi 125653548f91SRobert Mustacchi if ((outdirfd = open(outdir, O_RDONLY)) < 0) { 125753548f91SRobert Mustacchi err(EXIT_FAILURE, "failed to open output directory %s", outdir); 125853548f91SRobert Mustacchi } 125953548f91SRobert Mustacchi 126053548f91SRobert Mustacchi if (datadir == NULL) { 126153548f91SRobert Mustacchi cpcgen_usage("Missing required data directory (-d)\n"); 126253548f91SRobert Mustacchi return (2); 126353548f91SRobert Mustacchi } 126453548f91SRobert Mustacchi 126553548f91SRobert Mustacchi cpcgen_read_mapfile(datadir, platform); 126653548f91SRobert Mustacchi 126753548f91SRobert Mustacchi if (do_header) { 126853548f91SRobert Mustacchi cpcgen_common_files(outdirfd); 126953548f91SRobert Mustacchi return (0); 127053548f91SRobert Mustacchi } 127153548f91SRobert Mustacchi 127253548f91SRobert Mustacchi if (do_mpage) { 127353548f91SRobert Mustacchi cpcgen_ops.cgen_op_name = cpcgen_manual_name; 127453548f91SRobert Mustacchi cpcgen_ops.cgen_op_file_before = cpcgen_manual_file_before; 127553548f91SRobert Mustacchi cpcgen_ops.cgen_op_file_after = cpcgen_manual_file_after; 127653548f91SRobert Mustacchi cpcgen_ops.cgen_op_event = cpcgen_manual_event; 127753548f91SRobert Mustacchi } 127853548f91SRobert Mustacchi 127953548f91SRobert Mustacchi if (do_cfile) { 128053548f91SRobert Mustacchi cpcgen_ops.cgen_op_name = cpcgen_cfile_name; 128153548f91SRobert Mustacchi cpcgen_ops.cgen_op_file_before = cpcgen_cfile_file_before; 128253548f91SRobert Mustacchi cpcgen_ops.cgen_op_file_after = cpcgen_cfile_file_after; 128353548f91SRobert Mustacchi cpcgen_ops.cgen_op_event = cpcgen_cfile_event; 128453548f91SRobert Mustacchi } 128553548f91SRobert Mustacchi 128653548f91SRobert Mustacchi 128753548f91SRobert Mustacchi cpcgen_gen(outdirfd); 128853548f91SRobert Mustacchi 128953548f91SRobert Mustacchi return (0); 129053548f91SRobert Mustacchi } 1291