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