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