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 /* 13*08f1bbedSJohn 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 407e3dbbacSRobert Mustacchi 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; 467e3dbbacSRobert Mustacchi } cpc_proc_t; 477e3dbbacSRobert Mustacchi 487e3dbbacSRobert Mustacchi typedef enum cpc_file_type { 497e3dbbacSRobert Mustacchi CPC_FILE_CORE = 1 << 0, 507e3dbbacSRobert Mustacchi CPC_FILE_OFF_CORE = 1 << 1, 517e3dbbacSRobert Mustacchi CPC_FILE_UNCORE = 1 << 2, 527e3dbbacSRobert Mustacchi CPC_FILE_FP_MATH = 1 << 3, 537e3dbbacSRobert Mustacchi CPC_FILE_UNCORE_EXP = 1 << 4 547e3dbbacSRobert Mustacchi } cpc_type_t; 557e3dbbacSRobert Mustacchi 567e3dbbacSRobert Mustacchi typedef struct cpc_map { 577e3dbbacSRobert Mustacchi struct cpc_map *cmap_next; 587e3dbbacSRobert Mustacchi cpc_type_t cmap_type; 597e3dbbacSRobert Mustacchi nvlist_t *cmap_data; 607e3dbbacSRobert Mustacchi char *cmap_path; 617e3dbbacSRobert Mustacchi const char *cmap_name; 627e3dbbacSRobert Mustacchi cpc_proc_t *cmap_procs; 637e3dbbacSRobert Mustacchi } cpc_map_t; 647e3dbbacSRobert Mustacchi 657e3dbbacSRobert Mustacchi typedef struct cpc_whitelist { 667e3dbbacSRobert Mustacchi const char *cwhite_short; 677e3dbbacSRobert Mustacchi const char *cwhite_human; 687e3dbbacSRobert Mustacchi uint_t cwhite_mask; 697e3dbbacSRobert Mustacchi } cpc_whitelist_t; 707e3dbbacSRobert Mustacchi 717e3dbbacSRobert Mustacchi /* 727e3dbbacSRobert Mustacchi * List of architectures that we support generating this data for. This is done 737e3dbbacSRobert Mustacchi * so that processors that illumos doesn't support or run on aren't generated 747e3dbbacSRobert Mustacchi * (generally the Xeon Phi). 757e3dbbacSRobert Mustacchi */ 767e3dbbacSRobert Mustacchi static cpc_whitelist_t cpcgen_whitelist[] = { 777e3dbbacSRobert Mustacchi /* Nehalem */ 787e3dbbacSRobert Mustacchi { "NHM-EP", "nhm_ep", CPC_FILE_CORE }, 797e3dbbacSRobert Mustacchi { "NHM-EX", "nhm_ex", CPC_FILE_CORE }, 807e3dbbacSRobert Mustacchi /* Westmere */ 817e3dbbacSRobert Mustacchi { "WSM-EP-DP", "wsm_ep_dp", CPC_FILE_CORE }, 827e3dbbacSRobert Mustacchi { "WSM-EP-SP", "wsm_ep_sp", CPC_FILE_CORE }, 837e3dbbacSRobert Mustacchi { "WSM-EX", "wsm_ex", CPC_FILE_CORE }, 847e3dbbacSRobert Mustacchi /* Sandy Bridge */ 857e3dbbacSRobert Mustacchi { "SNB", "snb", CPC_FILE_CORE }, 867e3dbbacSRobert Mustacchi { "JKT", "jkt", CPC_FILE_CORE }, 877e3dbbacSRobert Mustacchi /* Ivy Bridge */ 887e3dbbacSRobert Mustacchi { "IVB", "ivb", CPC_FILE_CORE }, 897e3dbbacSRobert Mustacchi { "IVT", "ivt", CPC_FILE_CORE }, 907e3dbbacSRobert Mustacchi /* Haswell */ 917e3dbbacSRobert Mustacchi { "HSW", "hsw", CPC_FILE_CORE }, 927e3dbbacSRobert Mustacchi { "HSX", "hsx", CPC_FILE_CORE }, 937e3dbbacSRobert Mustacchi /* Broadwell */ 947e3dbbacSRobert Mustacchi { "BDW", "bdw", CPC_FILE_CORE }, 957e3dbbacSRobert Mustacchi { "BDW-DE", "bdw_de", CPC_FILE_CORE }, 967e3dbbacSRobert Mustacchi { "BDX", "bdx", CPC_FILE_CORE }, 977e3dbbacSRobert Mustacchi /* Skylake */ 987e3dbbacSRobert Mustacchi { "SKL", "skl", CPC_FILE_CORE }, 997e3dbbacSRobert Mustacchi { "SKX", "skx", CPC_FILE_CORE }, 1007e3dbbacSRobert Mustacchi /* Atom */ 1017e3dbbacSRobert Mustacchi { "BNL", "bnl", CPC_FILE_CORE }, 1027e3dbbacSRobert Mustacchi { "SLM", "slm", CPC_FILE_CORE }, 1037e3dbbacSRobert Mustacchi { "GLM", "glm", CPC_FILE_CORE }, 1047e3dbbacSRobert Mustacchi { "GLP", "glp", CPC_FILE_CORE }, 1057e3dbbacSRobert Mustacchi { NULL } 1067e3dbbacSRobert Mustacchi }; 1077e3dbbacSRobert Mustacchi 1087e3dbbacSRobert Mustacchi typedef struct cpc_papi { 1097e3dbbacSRobert Mustacchi const char *cpapi_intc; 1107e3dbbacSRobert Mustacchi const char *cpapi_papi; 1117e3dbbacSRobert Mustacchi } cpc_papi_t; 1127e3dbbacSRobert Mustacchi 1137e3dbbacSRobert Mustacchi /* 1147e3dbbacSRobert Mustacchi * This table maps events with an Intel specific name to the corresponding PAPI 1157e3dbbacSRobert Mustacchi * name. There may be multiple INtel events which map to the same PAPI event. 1167e3dbbacSRobert Mustacchi * This is usually because different processors have different names for an 1177e3dbbacSRobert Mustacchi * event. We use the title as opposed to the event codes because those can 1187e3dbbacSRobert Mustacchi * change somewhat arbitrarily between processor generations. 1197e3dbbacSRobert Mustacchi */ 1207e3dbbacSRobert Mustacchi static cpc_papi_t cpcgen_papi_map[] = { 1217e3dbbacSRobert Mustacchi { "CPU_CLK_UNHALTED.THREAD_P", "PAPI_tot_cyc" }, 1227e3dbbacSRobert Mustacchi { "INST_RETIRED.ANY_P", "PAPI_tot_ins" }, 1237e3dbbacSRobert Mustacchi { "BR_INST_RETIRED.ALL_BRANCHES", "PAPI_br_ins" }, 1247e3dbbacSRobert Mustacchi { "BR_MISP_RETIRED.ALL_BRANCHES", "PAPI_br_msp" }, 1257e3dbbacSRobert Mustacchi { "BR_INST_RETIRED.CONDITIONAL", "PAPI_br_cn" }, 1267e3dbbacSRobert Mustacchi { "CYCLE_ACTIVITY.CYCLES_L1D_MISS", "PAPI_l1_dcm" }, 1277e3dbbacSRobert Mustacchi { "L1I.HITS", "PAPI_l1_ich" }, 1287e3dbbacSRobert Mustacchi { "ICACHE.HIT", "PAPI_l1_ich" }, 1297e3dbbacSRobert Mustacchi { "L1I.MISS", "PAPI_L1_icm" }, 1307e3dbbacSRobert Mustacchi { "ICACHE.MISSES", "PAPI_l1_icm" }, 1317e3dbbacSRobert Mustacchi { "L1I.READS", "PAPI_l1_ica" }, 1327e3dbbacSRobert Mustacchi { "ICACHE.ACCESSES", "PAPI_l1_ica" }, 1337e3dbbacSRobert Mustacchi { "L1I.READS", "PAPI_l1_icr" }, 1347e3dbbacSRobert Mustacchi { "ICACHE.ACCESSES", "PAPI_l1_icr" }, 1357e3dbbacSRobert Mustacchi { "L2_RQSTS.CODE_RD_MISS", "PAPI_l2_icm" }, 1367e3dbbacSRobert Mustacchi { "L2_RQSTS.MISS", "PAPI_l2_tcm" }, 1377e3dbbacSRobert Mustacchi { "ITLB_MISSES.MISS_CAUSES_A_WALK", "PAPI_tlb_im" }, 1387e3dbbacSRobert Mustacchi { "DTLB_LOAD_MISSES.MISS_CAUSES_A_WALK", "PAPI_tlb_dm" }, 1397e3dbbacSRobert Mustacchi { "PAGE_WALKS.D_SIDE_WALKS", "PAPI_tlb_dm" }, 1407e3dbbacSRobert Mustacchi { "PAGE_WALKS.I_SIDE_WALKS", "PAPI_tlb_im" }, 1417e3dbbacSRobert Mustacchi { "PAGE_WALKS.WALKS", "PAPI_tlb_tl" }, 1427e3dbbacSRobert Mustacchi { "INST_QUEUE_WRITES", "PAPI_tot_iis" }, 1437e3dbbacSRobert Mustacchi { "MEM_INST_RETIRED.STORES" "PAPI_sr_ins" }, 1447e3dbbacSRobert Mustacchi { "MEM_INST_RETIRED.LOADS" "PAPI_ld_ins" }, 1457e3dbbacSRobert Mustacchi { NULL, NULL } 1467e3dbbacSRobert Mustacchi }; 1477e3dbbacSRobert Mustacchi 1487e3dbbacSRobert Mustacchi typedef struct cpcgen_ops { 1497e3dbbacSRobert Mustacchi char *(*cgen_op_name)(cpc_map_t *); 1507e3dbbacSRobert Mustacchi boolean_t (*cgen_op_file_before)(FILE *, cpc_map_t *); 1517e3dbbacSRobert Mustacchi boolean_t (*cgen_op_file_after)(FILE *, cpc_map_t *); 1527e3dbbacSRobert Mustacchi boolean_t (*cgen_op_event)(FILE *, nvlist_t *, const char *, uint32_t); 1537e3dbbacSRobert Mustacchi } cpcgen_ops_t; 1547e3dbbacSRobert Mustacchi 1557e3dbbacSRobert Mustacchi static cpcgen_ops_t cpcgen_ops; 1567e3dbbacSRobert Mustacchi static const char *cpcgen_mapfile = "/mapfile.csv"; 1577e3dbbacSRobert Mustacchi static const char *cpcgen_progname; 1587e3dbbacSRobert Mustacchi static cpc_map_t *cpcgen_maps; 1597e3dbbacSRobert Mustacchi 1607e3dbbacSRobert Mustacchi /* 1617e3dbbacSRobert Mustacchi * Constants used for generating data. 1627e3dbbacSRobert Mustacchi */ 1637e3dbbacSRobert Mustacchi /* BEGIN CSTYLED */ 1647e3dbbacSRobert Mustacchi static const char *cpcgen_cfile_header = "" 1657e3dbbacSRobert Mustacchi "/*\n" 1667e3dbbacSRobert Mustacchi " * Copyright (c) 2018, Intel Corporation\n" 1677e3dbbacSRobert Mustacchi " * Copyright (c) 2018, Joyent, Inc\n" 1687e3dbbacSRobert Mustacchi " * All rights reserved.\n" 1697e3dbbacSRobert Mustacchi " *\n" 1707e3dbbacSRobert Mustacchi " * Redistribution and use in source and binary forms, with or without\n" 1717e3dbbacSRobert Mustacchi " * modification, are permitted provided that the following conditions are met:\n" 1727e3dbbacSRobert Mustacchi " * \n" 1737e3dbbacSRobert Mustacchi " * 1. Redistributions of source code must retain the above copyright notice,\n" 1747e3dbbacSRobert Mustacchi " * this list of conditions and the following disclaimer.\n" 1757e3dbbacSRobert Mustacchi " * \n" 1767e3dbbacSRobert Mustacchi " * 2. Redistributions in binary form must reproduce the above copyright \n" 1777e3dbbacSRobert Mustacchi " * notice, this list of conditions and the following disclaimer in the\n" 1787e3dbbacSRobert Mustacchi " * documentation and/or other materials provided with the distribution.\n" 1797e3dbbacSRobert Mustacchi " * \n" 1807e3dbbacSRobert Mustacchi " * 3. Neither the name of the Intel Corporation nor the names of its \n" 1817e3dbbacSRobert Mustacchi " * contributors may be used to endorse or promote products derived from\n" 1827e3dbbacSRobert Mustacchi " * this software without specific prior written permission.\n" 1837e3dbbacSRobert Mustacchi " *\n" 1847e3dbbacSRobert Mustacchi " * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n" 1857e3dbbacSRobert Mustacchi " * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n" 1867e3dbbacSRobert Mustacchi " * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n" 1877e3dbbacSRobert Mustacchi " * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n" 1887e3dbbacSRobert Mustacchi " * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n" 1897e3dbbacSRobert Mustacchi " * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n" 1907e3dbbacSRobert Mustacchi " * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n" 1917e3dbbacSRobert Mustacchi " * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n" 1927e3dbbacSRobert Mustacchi " * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n" 1937e3dbbacSRobert Mustacchi " * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n" 1947e3dbbacSRobert Mustacchi " * POSSIBILITY OF SUCH DAMAGE.\n" 1957e3dbbacSRobert Mustacchi " *\n" 1967e3dbbacSRobert Mustacchi " * This file was automatically generated by cpcgen from the data file\n" 1977e3dbbacSRobert Mustacchi " * data/perfmon%s\n" 1987e3dbbacSRobert Mustacchi " *\n" 1997e3dbbacSRobert Mustacchi " * Do not modify this file. Your changes will be lost!\n" 2007e3dbbacSRobert Mustacchi " */\n" 2017e3dbbacSRobert Mustacchi "\n"; 2027e3dbbacSRobert Mustacchi /* END CSTYLED */ 2037e3dbbacSRobert Mustacchi 2047e3dbbacSRobert Mustacchi static const char *cpcgen_cfile_table_start = "" 2057e3dbbacSRobert Mustacchi "#include <core_pcbe_table.h>\n" 2067e3dbbacSRobert Mustacchi "\n" 2077e3dbbacSRobert Mustacchi "const struct events_table_t pcbe_core_events_%s[] = {\n"; 2087e3dbbacSRobert Mustacchi 2097e3dbbacSRobert Mustacchi static const char *cpcgen_cfile_table_end = "" 2107e3dbbacSRobert Mustacchi "\t{ NT_END, 0, 0, \"\" }\n" 2117e3dbbacSRobert Mustacchi "};\n"; 2127e3dbbacSRobert Mustacchi 2137e3dbbacSRobert Mustacchi /* BEGIN CSTYLED */ 2147e3dbbacSRobert Mustacchi static const char *cpcgen_manual_header = "" 2157e3dbbacSRobert Mustacchi ".\\\" Copyright (c) 2018, Intel Corporation \n" 2167e3dbbacSRobert Mustacchi ".\\\" Copyright (c) 2018, Joyent, Inc.\n" 2177e3dbbacSRobert Mustacchi ".\\\" All rights reserved.\n" 2187e3dbbacSRobert Mustacchi ".\\\"\n" 2197e3dbbacSRobert Mustacchi ".\\\" Redistribution and use in source and binary forms, with or without \n" 2207e3dbbacSRobert Mustacchi ".\\\" modification, are permitted provided that the following conditions are met:\n" 2217e3dbbacSRobert Mustacchi ".\\\"\n" 2227e3dbbacSRobert Mustacchi ".\\\" 1. Redistributions of source code must retain the above copyright notice,\n" 2237e3dbbacSRobert Mustacchi ".\\\" this list of conditions and the following disclaimer.\n" 2247e3dbbacSRobert Mustacchi ".\\\"\n" 2257e3dbbacSRobert Mustacchi ".\\\" 2. Redistributions in binary form must reproduce the above copyright\n" 2267e3dbbacSRobert Mustacchi ".\\\" notice, this list of conditions and the following disclaimer in the\n" 2277e3dbbacSRobert Mustacchi ".\\\" documentation and/or other materials provided with the distribution.\n" 2287e3dbbacSRobert Mustacchi ".\\\"\n" 2297e3dbbacSRobert Mustacchi ".\\\" 3. Neither the name of the Intel Corporation nor the names of its\n" 2307e3dbbacSRobert Mustacchi ".\\\" contributors may be used to endorse or promote products derived from\n" 2317e3dbbacSRobert Mustacchi ".\\\" this software without specific prior written permission.\n" 2327e3dbbacSRobert Mustacchi ".\\\"\n" 2337e3dbbacSRobert Mustacchi ".\\\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n" 2347e3dbbacSRobert Mustacchi ".\\\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n" 2357e3dbbacSRobert Mustacchi ".\\\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n" 2367e3dbbacSRobert Mustacchi ".\\\" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n" 2377e3dbbacSRobert Mustacchi ".\\\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n" 2387e3dbbacSRobert Mustacchi ".\\\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n" 2397e3dbbacSRobert Mustacchi ".\\\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n" 2407e3dbbacSRobert Mustacchi ".\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n" 2417e3dbbacSRobert Mustacchi ".\\\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n" 2427e3dbbacSRobert Mustacchi ".\\\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n" 2437e3dbbacSRobert Mustacchi ".\\\" POSSIBILITY OF SUCH DAMAGE.\n" 2447e3dbbacSRobert Mustacchi ".\\\"\n" 2457e3dbbacSRobert Mustacchi ".\\\" This file was automatically generated by cpcgen from the data file\n" 2467e3dbbacSRobert Mustacchi ".\\\" data/perfmon%s\n" 2477e3dbbacSRobert Mustacchi ".\\\"\n" 2487e3dbbacSRobert Mustacchi ".\\\" Do not modify this file. Your changes will be lost!\n" 2497e3dbbacSRobert Mustacchi ".\\\"\n" 2507e3dbbacSRobert Mustacchi ".\\\" We would like to thank Intel for providing the perfmon data for use in\n" 2517e3dbbacSRobert Mustacchi ".\\\" our manual pages.\n" 2527e3dbbacSRobert Mustacchi ".Dd June 18, 2018\n" 2537e3dbbacSRobert Mustacchi ".Dt %s_EVENTS 3CPC\n" 2547e3dbbacSRobert Mustacchi ".Os\n" 2557e3dbbacSRobert Mustacchi ".Sh NAME\n" 2567e3dbbacSRobert Mustacchi ".Nm %s_events\n" 2577e3dbbacSRobert Mustacchi ".Nd processor model specific performance counter events\n" 2587e3dbbacSRobert Mustacchi ".Sh DESCRIPTION\n" 2597e3dbbacSRobert Mustacchi "This manual page describes events specific to the following Intel CPU\n" 2607e3dbbacSRobert Mustacchi "models and is derived from Intel's perfmon data.\n" 2617e3dbbacSRobert Mustacchi "For more information, please consult the Intel Software Developer's Manual " 2627e3dbbacSRobert Mustacchi "or Intel's perfmon website.\n" 2637e3dbbacSRobert Mustacchi ".Pp\n" 2647e3dbbacSRobert Mustacchi "CPU models described by this document:\n" 2657e3dbbacSRobert Mustacchi ".Bl -bullet\n"; 2667e3dbbacSRobert Mustacchi /* END CSTYLED */ 2677e3dbbacSRobert Mustacchi 2687e3dbbacSRobert Mustacchi static const char *cpcgen_manual_data = "" 2697e3dbbacSRobert Mustacchi ".El\n" 2707e3dbbacSRobert Mustacchi ".Pp\n" 2717e3dbbacSRobert Mustacchi "The following events are supported:\n" 2727e3dbbacSRobert Mustacchi ".Bl -tag -width Sy\n"; 2737e3dbbacSRobert Mustacchi 2747e3dbbacSRobert Mustacchi static const char *cpcgen_manual_trailer = "" 2757e3dbbacSRobert Mustacchi ".El\n" 2767e3dbbacSRobert Mustacchi ".Sh SEE ALSO\n" 2777e3dbbacSRobert Mustacchi ".Xr cpc 3CPC\n" 2787e3dbbacSRobert Mustacchi ".Pp\n" 2797e3dbbacSRobert Mustacchi ".Lk https://download.01.org/perfmon/index/"; 2807e3dbbacSRobert Mustacchi 2817e3dbbacSRobert Mustacchi static cpc_map_t * 2827e3dbbacSRobert Mustacchi cpcgen_map_lookup(const char *path) 2837e3dbbacSRobert Mustacchi { 2847e3dbbacSRobert Mustacchi cpc_map_t *m; 2857e3dbbacSRobert Mustacchi 2867e3dbbacSRobert Mustacchi for (m = cpcgen_maps; m != NULL; m = m->cmap_next) { 2877e3dbbacSRobert Mustacchi if (strcmp(path, m->cmap_path) == 0) { 2887e3dbbacSRobert Mustacchi return (m); 2897e3dbbacSRobert Mustacchi } 2907e3dbbacSRobert Mustacchi } 2917e3dbbacSRobert Mustacchi 2927e3dbbacSRobert Mustacchi return (NULL); 2937e3dbbacSRobert Mustacchi } 2947e3dbbacSRobert Mustacchi 2957e3dbbacSRobert Mustacchi /* 2967e3dbbacSRobert Mustacchi * Parse a string of the form 'GenuineIntel-6-2E' and get out the family and 2977e3dbbacSRobert Mustacchi * model. 2987e3dbbacSRobert Mustacchi */ 2997e3dbbacSRobert Mustacchi static void 3007e3dbbacSRobert Mustacchi cpcgen_parse_model(char *fsr, uint_t *family, uint_t *model) 3017e3dbbacSRobert Mustacchi { 3027e3dbbacSRobert Mustacchi const char *bstr = "GenuineIntel"; 3037e3dbbacSRobert Mustacchi const char *brand, *fam, *mod; 3047e3dbbacSRobert Mustacchi char *last; 3057e3dbbacSRobert Mustacchi long l; 3067e3dbbacSRobert Mustacchi 3077e3dbbacSRobert Mustacchi if ((brand = strtok_r(fsr, "-", &last)) == NULL || 3087e3dbbacSRobert Mustacchi (fam = strtok_r(NULL, "-", &last)) == NULL || 3097e3dbbacSRobert Mustacchi (mod = strtok_r(NULL, "-", &last)) == NULL) { 3107e3dbbacSRobert Mustacchi errx(EXIT_FAILURE, "failed to parse processor id \"%s\"", fsr); 3117e3dbbacSRobert Mustacchi } 3127e3dbbacSRobert Mustacchi 3137e3dbbacSRobert Mustacchi if (strcmp(bstr, brand) != 0) { 3147e3dbbacSRobert Mustacchi errx(EXIT_FAILURE, "brand string \"%s\" did not match \"%s\"", 3157e3dbbacSRobert Mustacchi brand, bstr); 3167e3dbbacSRobert Mustacchi } 3177e3dbbacSRobert Mustacchi 3187e3dbbacSRobert Mustacchi errno = 0; 3197e3dbbacSRobert Mustacchi l = strtol(fam, &last, 16); 320*08f1bbedSJohn Levon if (errno != 0 || l < 0 || l >= INT_MAX || *last != '\0') { 3217e3dbbacSRobert Mustacchi errx(EXIT_FAILURE, "failed to parse family \"%s\"", fam); 3227e3dbbacSRobert Mustacchi } 3237e3dbbacSRobert Mustacchi *family = (uint_t)l; 3247e3dbbacSRobert Mustacchi 3257e3dbbacSRobert Mustacchi l = strtol(mod, &last, 16); 326*08f1bbedSJohn Levon if (errno != 0 || l < 0 || l >= INT_MAX || *last != '\0') { 3277e3dbbacSRobert Mustacchi errx(EXIT_FAILURE, "failed to parse model \"%s\"", mod); 3287e3dbbacSRobert Mustacchi } 3297e3dbbacSRobert Mustacchi *model = (uint_t)l; 3307e3dbbacSRobert Mustacchi } 3317e3dbbacSRobert Mustacchi 3327e3dbbacSRobert Mustacchi static nvlist_t * 3337e3dbbacSRobert Mustacchi cpcgen_read_datafile(const char *datadir, const char *file) 3347e3dbbacSRobert Mustacchi { 3357e3dbbacSRobert Mustacchi int fd; 3367e3dbbacSRobert Mustacchi char *path; 3377e3dbbacSRobert Mustacchi struct stat st; 3387e3dbbacSRobert Mustacchi void *map; 3397e3dbbacSRobert Mustacchi nvlist_t *nvl; 3407e3dbbacSRobert Mustacchi nvlist_parse_json_error_t jerr; 3417e3dbbacSRobert Mustacchi 3427e3dbbacSRobert Mustacchi if (asprintf(&path, "%s/%s", datadir, file) == -1) { 3437e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to construct path to data file %s", 3447e3dbbacSRobert Mustacchi file); 3457e3dbbacSRobert Mustacchi } 3467e3dbbacSRobert Mustacchi 3477e3dbbacSRobert Mustacchi if ((fd = open(path, O_RDONLY)) < 0) { 3487e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to open data file %s", path); 3497e3dbbacSRobert Mustacchi } 3507e3dbbacSRobert Mustacchi 3517e3dbbacSRobert Mustacchi if (fstat(fd, &st) != 0) { 3527e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to stat %s", path); 3537e3dbbacSRobert Mustacchi } 3547e3dbbacSRobert Mustacchi 3557e3dbbacSRobert Mustacchi if ((map = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, 3567e3dbbacSRobert Mustacchi fd, 0)) == MAP_FAILED) { 3577e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to mmap %s", path); 3587e3dbbacSRobert Mustacchi } 3597e3dbbacSRobert Mustacchi 3607e3dbbacSRobert Mustacchi if (nvlist_parse_json(map, st.st_size, &nvl, NVJSON_FORCE_INTEGER, 3617e3dbbacSRobert Mustacchi &jerr) != 0) { 3627e3dbbacSRobert Mustacchi errx(EXIT_FAILURE, "failed to parse file %s at pos %ld: %s", 3637e3dbbacSRobert Mustacchi path, jerr.nje_pos, jerr.nje_message); 3647e3dbbacSRobert Mustacchi } 3657e3dbbacSRobert Mustacchi 3667e3dbbacSRobert Mustacchi if (munmap(map, st.st_size) != 0) { 3677e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to munmap %s", path); 3687e3dbbacSRobert Mustacchi } 3697e3dbbacSRobert Mustacchi 3707e3dbbacSRobert Mustacchi if (close(fd) != 0) { 3717e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to close data file %s", path); 3727e3dbbacSRobert Mustacchi } 3737e3dbbacSRobert Mustacchi free(path); 3747e3dbbacSRobert Mustacchi 3757e3dbbacSRobert Mustacchi return (nvl); 3767e3dbbacSRobert Mustacchi } 3777e3dbbacSRobert Mustacchi 3787e3dbbacSRobert Mustacchi /* 3797e3dbbacSRobert Mustacchi * Check the whitelist to see if we should use this model. 3807e3dbbacSRobert Mustacchi */ 3817e3dbbacSRobert Mustacchi static const char * 3827e3dbbacSRobert Mustacchi cpcgen_use_arch(const char *path, cpc_type_t type, const char *platform) 3837e3dbbacSRobert Mustacchi { 3847e3dbbacSRobert Mustacchi const char *slash; 3857e3dbbacSRobert Mustacchi size_t len; 3867e3dbbacSRobert Mustacchi uint_t i; 3877e3dbbacSRobert Mustacchi 3887e3dbbacSRobert Mustacchi if (*path != '/') { 3897e3dbbacSRobert Mustacchi errx(EXIT_FAILURE, "invalid path in mapfile: \"%s\": missing " 3907e3dbbacSRobert Mustacchi "leading '/'", path); 3917e3dbbacSRobert Mustacchi } 3927e3dbbacSRobert Mustacchi if ((slash = strchr(path + 1, '/')) == NULL) { 3937e3dbbacSRobert Mustacchi errx(EXIT_FAILURE, "invalid path in mapfile: \"%s\": missing " 3947e3dbbacSRobert Mustacchi "second '/'", path); 3957e3dbbacSRobert Mustacchi } 3967e3dbbacSRobert Mustacchi /* Account for the last '/' character. */ 3977e3dbbacSRobert Mustacchi len = slash - path - 1; 3987e3dbbacSRobert Mustacchi assert(len > 0); 3997e3dbbacSRobert Mustacchi 4007e3dbbacSRobert Mustacchi for (i = 0; cpcgen_whitelist[i].cwhite_short != NULL; i++) { 4017e3dbbacSRobert Mustacchi if (platform != NULL && strcasecmp(platform, 4027e3dbbacSRobert Mustacchi cpcgen_whitelist[i].cwhite_short) != 0) 4037e3dbbacSRobert Mustacchi continue; 4047e3dbbacSRobert Mustacchi if (strncmp(path + 1, cpcgen_whitelist[i].cwhite_short, 4057e3dbbacSRobert Mustacchi len) == 0 && 4067e3dbbacSRobert Mustacchi (cpcgen_whitelist[i].cwhite_mask & type) == type) { 4077e3dbbacSRobert Mustacchi return (cpcgen_whitelist[i].cwhite_human); 4087e3dbbacSRobert Mustacchi } 4097e3dbbacSRobert Mustacchi } 4107e3dbbacSRobert Mustacchi 4117e3dbbacSRobert Mustacchi return (NULL); 4127e3dbbacSRobert Mustacchi } 4137e3dbbacSRobert Mustacchi 4147e3dbbacSRobert Mustacchi /* 4157e3dbbacSRobert Mustacchi * Read in the mapfile.csv that is used to map between processor families and 4167e3dbbacSRobert Mustacchi * parse this. Each line has a comma separated value. 4177e3dbbacSRobert Mustacchi */ 4187e3dbbacSRobert Mustacchi static void 4197e3dbbacSRobert Mustacchi cpcgen_read_mapfile(const char *datadir, const char *platform) 4207e3dbbacSRobert Mustacchi { 4217e3dbbacSRobert Mustacchi FILE *map; 4227e3dbbacSRobert Mustacchi char *mappath, *last; 4237e3dbbacSRobert Mustacchi char *data = NULL; 4247e3dbbacSRobert Mustacchi size_t datalen = 0; 4257e3dbbacSRobert Mustacchi uint_t lineno; 4267e3dbbacSRobert Mustacchi 4277e3dbbacSRobert Mustacchi if (asprintf(&mappath, "%s/%s", datadir, cpcgen_mapfile) == -1) { 4287e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to construct path to mapfile"); 4297e3dbbacSRobert Mustacchi } 4307e3dbbacSRobert Mustacchi 4317e3dbbacSRobert Mustacchi if ((map = fopen(mappath, "r")) == NULL) { 4327e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to open data mapfile %s", mappath); 4337e3dbbacSRobert Mustacchi } 4347e3dbbacSRobert Mustacchi 4357e3dbbacSRobert Mustacchi lineno = 0; 4367e3dbbacSRobert Mustacchi while (getline(&data, &datalen, map) != -1) { 4377e3dbbacSRobert Mustacchi char *fstr, *path, *tstr; 4387e3dbbacSRobert Mustacchi const char *name; 4397e3dbbacSRobert Mustacchi uint_t family, model; 4407e3dbbacSRobert Mustacchi cpc_type_t type; 4417e3dbbacSRobert Mustacchi cpc_map_t *map; 4427e3dbbacSRobert Mustacchi cpc_proc_t *proc; 4437e3dbbacSRobert Mustacchi 4447e3dbbacSRobert Mustacchi /* 4457e3dbbacSRobert Mustacchi * The first line contains the header: 4467e3dbbacSRobert Mustacchi * Family-model,Version,Filename,EventType 4477e3dbbacSRobert Mustacchi */ 4487e3dbbacSRobert Mustacchi lineno++; 4497e3dbbacSRobert Mustacchi if (lineno == 1) { 4507e3dbbacSRobert Mustacchi continue; 4517e3dbbacSRobert Mustacchi } 4527e3dbbacSRobert Mustacchi 4537e3dbbacSRobert Mustacchi if ((fstr = strtok_r(data, ",", &last)) == NULL || 4547e3dbbacSRobert Mustacchi strtok_r(NULL, ",", &last) == NULL || 4557e3dbbacSRobert Mustacchi (path = strtok_r(NULL, ",", &last)) == NULL || 4567e3dbbacSRobert Mustacchi (tstr = strtok_r(NULL, "\n", &last)) == NULL) { 4577e3dbbacSRobert Mustacchi errx(EXIT_FAILURE, "failed to parse mapfile line " 4587e3dbbacSRobert Mustacchi "%u in %s", lineno, mappath); 4597e3dbbacSRobert Mustacchi } 4607e3dbbacSRobert Mustacchi 4617e3dbbacSRobert Mustacchi cpcgen_parse_model(fstr, &family, &model); 4627e3dbbacSRobert Mustacchi 4637e3dbbacSRobert Mustacchi if (strcmp(tstr, "core") == 0) { 4647e3dbbacSRobert Mustacchi type = CPC_FILE_CORE; 4657e3dbbacSRobert Mustacchi } else if (strcmp(tstr, "offcore") == 0) { 4667e3dbbacSRobert Mustacchi type = CPC_FILE_OFF_CORE; 4677e3dbbacSRobert Mustacchi } else if (strcmp(tstr, "uncore") == 0) { 4687e3dbbacSRobert Mustacchi type = CPC_FILE_UNCORE; 4697e3dbbacSRobert Mustacchi } else if (strcmp(tstr, "fp_arith_inst") == 0) { 4707e3dbbacSRobert Mustacchi type = CPC_FILE_FP_MATH; 4717e3dbbacSRobert Mustacchi } else if (strcmp(tstr, "uncore experimental") == 0) { 4727e3dbbacSRobert Mustacchi type = CPC_FILE_UNCORE_EXP; 4737e3dbbacSRobert Mustacchi } else { 4747e3dbbacSRobert Mustacchi errx(EXIT_FAILURE, "unknown file type \"%s\" on line " 4757e3dbbacSRobert Mustacchi "%u", tstr, lineno); 4767e3dbbacSRobert Mustacchi } 4777e3dbbacSRobert Mustacchi 4787e3dbbacSRobert Mustacchi if ((name = cpcgen_use_arch(path, type, platform)) == NULL) 4797e3dbbacSRobert Mustacchi continue; 4807e3dbbacSRobert Mustacchi 4817e3dbbacSRobert Mustacchi if ((map = cpcgen_map_lookup(path)) == NULL) { 4827e3dbbacSRobert Mustacchi nvlist_t *parsed; 4837e3dbbacSRobert Mustacchi 4847e3dbbacSRobert Mustacchi parsed = cpcgen_read_datafile(datadir, path); 4857e3dbbacSRobert Mustacchi 4867e3dbbacSRobert Mustacchi if ((map = calloc(1, sizeof (cpc_map_t))) == NULL) { 4877e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to allocate space " 4887e3dbbacSRobert Mustacchi "for cpc file"); 4897e3dbbacSRobert Mustacchi } 4907e3dbbacSRobert Mustacchi 4917e3dbbacSRobert Mustacchi if ((map->cmap_path = strdup(path)) == NULL) { 4927e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to duplicate path " 4937e3dbbacSRobert Mustacchi "string"); 4947e3dbbacSRobert Mustacchi } 4957e3dbbacSRobert Mustacchi 4967e3dbbacSRobert Mustacchi map->cmap_type = type; 4977e3dbbacSRobert Mustacchi map->cmap_data = parsed; 4987e3dbbacSRobert Mustacchi map->cmap_next = cpcgen_maps; 4997e3dbbacSRobert Mustacchi map->cmap_name = name; 5007e3dbbacSRobert Mustacchi cpcgen_maps = map; 5017e3dbbacSRobert Mustacchi } 5027e3dbbacSRobert Mustacchi 5037e3dbbacSRobert Mustacchi if ((proc = malloc(sizeof (cpc_proc_t))) == NULL) { 5047e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to allocate memory for " 5057e3dbbacSRobert Mustacchi "family and model tracking"); 5067e3dbbacSRobert Mustacchi } 5077e3dbbacSRobert Mustacchi 5087e3dbbacSRobert Mustacchi proc->cproc_family = family; 5097e3dbbacSRobert Mustacchi proc->cproc_model = model; 5107e3dbbacSRobert Mustacchi proc->cproc_next = map->cmap_procs; 5117e3dbbacSRobert Mustacchi map->cmap_procs = proc; 5127e3dbbacSRobert Mustacchi } 5137e3dbbacSRobert Mustacchi 5147e3dbbacSRobert Mustacchi if (errno != 0 || ferror(map)) { 5157e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to read %s", mappath); 5167e3dbbacSRobert Mustacchi } 5177e3dbbacSRobert Mustacchi 5187e3dbbacSRobert Mustacchi if (fclose(map) == EOF) { 5197e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to close %s", mappath); 5207e3dbbacSRobert Mustacchi } 5217e3dbbacSRobert Mustacchi free(data); 5227e3dbbacSRobert Mustacchi free(mappath); 5237e3dbbacSRobert Mustacchi } 5247e3dbbacSRobert Mustacchi 5257e3dbbacSRobert Mustacchi static char * 5267e3dbbacSRobert Mustacchi cpcgen_manual_name(cpc_map_t *map) 5277e3dbbacSRobert Mustacchi { 5287e3dbbacSRobert Mustacchi char *name; 5297e3dbbacSRobert Mustacchi 5307e3dbbacSRobert Mustacchi if (asprintf(&name, "%s_events.3cpc", map->cmap_name) == -1) { 5317e3dbbacSRobert Mustacchi warn("failed to assemble manual page name for %s", 5327e3dbbacSRobert Mustacchi map->cmap_path); 5337e3dbbacSRobert Mustacchi return (NULL); 5347e3dbbacSRobert Mustacchi } 5357e3dbbacSRobert Mustacchi 5367e3dbbacSRobert Mustacchi return (name); 5377e3dbbacSRobert Mustacchi } 5387e3dbbacSRobert Mustacchi 5397e3dbbacSRobert Mustacchi static boolean_t 5407e3dbbacSRobert Mustacchi cpcgen_manual_file_before(FILE *f, cpc_map_t *map) 5417e3dbbacSRobert Mustacchi { 5427e3dbbacSRobert Mustacchi size_t i; 5437e3dbbacSRobert Mustacchi char *upper; 5447e3dbbacSRobert Mustacchi cpc_proc_t *proc; 5457e3dbbacSRobert Mustacchi 5467e3dbbacSRobert Mustacchi if ((upper = strdup(map->cmap_name)) == NULL) { 5477e3dbbacSRobert Mustacchi warn("failed to duplicate manual name for %s", map->cmap_name); 5487e3dbbacSRobert Mustacchi return (B_FALSE); 5497e3dbbacSRobert Mustacchi } 5507e3dbbacSRobert Mustacchi 5517e3dbbacSRobert Mustacchi for (i = 0; upper[i] != '\0'; i++) { 5527e3dbbacSRobert Mustacchi upper[i] = toupper(upper[i]); 5537e3dbbacSRobert Mustacchi } 5547e3dbbacSRobert Mustacchi 5557e3dbbacSRobert Mustacchi if (fprintf(f, cpcgen_manual_header, map->cmap_path, upper, 5567e3dbbacSRobert Mustacchi map->cmap_name) == -1) { 5577e3dbbacSRobert Mustacchi warn("failed to write out manual header for %s", 5587e3dbbacSRobert Mustacchi map->cmap_name); 5597e3dbbacSRobert Mustacchi free(upper); 5607e3dbbacSRobert Mustacchi return (B_FALSE); 5617e3dbbacSRobert Mustacchi } 5627e3dbbacSRobert Mustacchi 5637e3dbbacSRobert Mustacchi for (proc = map->cmap_procs; proc != NULL; proc = proc->cproc_next) { 5647e3dbbacSRobert Mustacchi if (fprintf(f, ".It\n.Sy Family 0x%x, Model 0x%x\n", 5657e3dbbacSRobert Mustacchi proc->cproc_family, proc->cproc_model) == -1) { 5667e3dbbacSRobert Mustacchi warn("failed to write out model information for %s", 5677e3dbbacSRobert Mustacchi map->cmap_name); 5687e3dbbacSRobert Mustacchi free(upper); 5697e3dbbacSRobert Mustacchi return (B_FALSE); 5707e3dbbacSRobert Mustacchi } 5717e3dbbacSRobert Mustacchi } 5727e3dbbacSRobert Mustacchi 5737e3dbbacSRobert Mustacchi if (fprintf(f, cpcgen_manual_data, map->cmap_path, upper, 5747e3dbbacSRobert Mustacchi map->cmap_name) == -1) { 5757e3dbbacSRobert Mustacchi warn("failed to write out manual header for %s", 5767e3dbbacSRobert Mustacchi map->cmap_name); 5777e3dbbacSRobert Mustacchi free(upper); 5787e3dbbacSRobert Mustacchi return (B_FALSE); 5797e3dbbacSRobert Mustacchi } 5807e3dbbacSRobert Mustacchi 5817e3dbbacSRobert Mustacchi free(upper); 5827e3dbbacSRobert Mustacchi return (B_TRUE); 5837e3dbbacSRobert Mustacchi } 5847e3dbbacSRobert Mustacchi 5857e3dbbacSRobert Mustacchi static boolean_t 5867e3dbbacSRobert Mustacchi cpcgen_manual_file_after(FILE *f, cpc_map_t *map) 5877e3dbbacSRobert Mustacchi { 5887e3dbbacSRobert Mustacchi if (fprintf(f, cpcgen_manual_trailer) == -1) { 5897e3dbbacSRobert Mustacchi warn("failed to write out manual header for %s", 5907e3dbbacSRobert Mustacchi map->cmap_name); 5917e3dbbacSRobert Mustacchi return (B_FALSE); 5927e3dbbacSRobert Mustacchi } 5937e3dbbacSRobert Mustacchi 5947e3dbbacSRobert Mustacchi return (B_TRUE); 5957e3dbbacSRobert Mustacchi } 5967e3dbbacSRobert Mustacchi 5977e3dbbacSRobert Mustacchi static boolean_t 5987e3dbbacSRobert Mustacchi cpcgen_manual_event(FILE *f, nvlist_t *nvl, const char *path, uint32_t ent) 5997e3dbbacSRobert Mustacchi { 6007e3dbbacSRobert Mustacchi char *event, *lname, *brief = NULL, *public = NULL, *errata = NULL; 6017e3dbbacSRobert Mustacchi size_t i; 6027e3dbbacSRobert Mustacchi 6037e3dbbacSRobert Mustacchi if (nvlist_lookup_string(nvl, "EventName", &event) != 0) { 6047e3dbbacSRobert Mustacchi warnx("Found event without 'EventName' property " 6057e3dbbacSRobert Mustacchi "in %s, entry %u", path, ent); 6067e3dbbacSRobert Mustacchi return (B_FALSE); 6077e3dbbacSRobert Mustacchi } 6087e3dbbacSRobert Mustacchi 6097e3dbbacSRobert Mustacchi /* 6107e3dbbacSRobert Mustacchi * Intel uses capital names. CPC historically uses lower case names. 6117e3dbbacSRobert Mustacchi */ 6127e3dbbacSRobert Mustacchi if ((lname = strdup(event)) == NULL) { 6137e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to duplicate event name %s", event); 6147e3dbbacSRobert Mustacchi } 6157e3dbbacSRobert Mustacchi for (i = 0; lname[i] != '\0'; i++) { 6167e3dbbacSRobert Mustacchi lname[i] = tolower(event[i]); 6177e3dbbacSRobert Mustacchi } 6187e3dbbacSRobert Mustacchi 6197e3dbbacSRobert Mustacchi /* 6207e3dbbacSRobert Mustacchi * Try to get the other event fields, but if they're not there, don't 6217e3dbbacSRobert Mustacchi * worry about it. 6227e3dbbacSRobert Mustacchi */ 6237e3dbbacSRobert Mustacchi (void) nvlist_lookup_string(nvl, "BriefDescription", &brief); 6247e3dbbacSRobert Mustacchi (void) nvlist_lookup_string(nvl, "PublicDescription", &public); 6257e3dbbacSRobert Mustacchi (void) nvlist_lookup_string(nvl, "Errata", &errata); 6267e3dbbacSRobert Mustacchi if (errata != NULL && (strcmp(errata, "0") == 0 || 6277e3dbbacSRobert Mustacchi strcmp(errata, "null") == 0)) { 6287e3dbbacSRobert Mustacchi errata = NULL; 6297e3dbbacSRobert Mustacchi } 6307e3dbbacSRobert Mustacchi 6317e3dbbacSRobert Mustacchi if (fprintf(f, ".It Sy %s\n", lname) == -1) { 6327e3dbbacSRobert Mustacchi warn("failed to write out probe entry %s", event); 6337e3dbbacSRobert Mustacchi free(lname); 6347e3dbbacSRobert Mustacchi return (B_FALSE); 6357e3dbbacSRobert Mustacchi } 6367e3dbbacSRobert Mustacchi 6377e3dbbacSRobert Mustacchi if (public != NULL) { 6387e3dbbacSRobert Mustacchi if (fprintf(f, "%s\n", public) == -1) { 6397e3dbbacSRobert Mustacchi warn("failed to write out probe entry %s", event); 6407e3dbbacSRobert Mustacchi free(lname); 6417e3dbbacSRobert Mustacchi return (B_FALSE); 6427e3dbbacSRobert Mustacchi } 6437e3dbbacSRobert Mustacchi } else if (brief != NULL) { 6447e3dbbacSRobert Mustacchi if (fprintf(f, "%s\n", brief) == -1) { 6457e3dbbacSRobert Mustacchi warn("failed to write out probe entry %s", event); 6467e3dbbacSRobert Mustacchi free(lname); 6477e3dbbacSRobert Mustacchi return (B_FALSE); 6487e3dbbacSRobert Mustacchi } 6497e3dbbacSRobert Mustacchi } 6507e3dbbacSRobert Mustacchi 6517e3dbbacSRobert Mustacchi if (errata != NULL) { 6527e3dbbacSRobert Mustacchi if (fprintf(f, ".Pp\nThe following errata may apply to this: " 6537e3dbbacSRobert Mustacchi "%s\n", errata) == -1) { 6547e3dbbacSRobert Mustacchi 6557e3dbbacSRobert Mustacchi warn("failed to write out probe entry %s", event); 6567e3dbbacSRobert Mustacchi free(lname); 6577e3dbbacSRobert Mustacchi return (B_FALSE); 6587e3dbbacSRobert Mustacchi } 6597e3dbbacSRobert Mustacchi } 6607e3dbbacSRobert Mustacchi 6617e3dbbacSRobert Mustacchi free(lname); 6627e3dbbacSRobert Mustacchi return (B_TRUE); 6637e3dbbacSRobert Mustacchi } 6647e3dbbacSRobert Mustacchi 6657e3dbbacSRobert Mustacchi static char * 6667e3dbbacSRobert Mustacchi cpcgen_cfile_name(cpc_map_t *map) 6677e3dbbacSRobert Mustacchi { 6687e3dbbacSRobert Mustacchi char *name; 6697e3dbbacSRobert Mustacchi 6707e3dbbacSRobert Mustacchi if (asprintf(&name, "core_pcbe_%s.c", map->cmap_name) == -1) { 6717e3dbbacSRobert Mustacchi warn("failed to assemble file name for %s", map->cmap_path); 6727e3dbbacSRobert Mustacchi return (NULL); 6737e3dbbacSRobert Mustacchi } 6747e3dbbacSRobert Mustacchi 6757e3dbbacSRobert Mustacchi return (name); 6767e3dbbacSRobert Mustacchi } 6777e3dbbacSRobert Mustacchi 6787e3dbbacSRobert Mustacchi static boolean_t 6797e3dbbacSRobert Mustacchi cpcgen_cfile_file_before(FILE *f, cpc_map_t *map) 6807e3dbbacSRobert Mustacchi { 6817e3dbbacSRobert Mustacchi if (fprintf(f, cpcgen_cfile_header, map->cmap_path) == -1) { 6827e3dbbacSRobert Mustacchi warn("failed to write header to temporary file for %s", 6837e3dbbacSRobert Mustacchi map->cmap_path); 6847e3dbbacSRobert Mustacchi return (B_FALSE); 6857e3dbbacSRobert Mustacchi } 6867e3dbbacSRobert Mustacchi 6877e3dbbacSRobert Mustacchi if (fprintf(f, cpcgen_cfile_table_start, map->cmap_name) == -1) { 6887e3dbbacSRobert Mustacchi warn("failed to write header to temporary file for %s", 6897e3dbbacSRobert Mustacchi map->cmap_path); 6907e3dbbacSRobert Mustacchi return (B_FALSE); 6917e3dbbacSRobert Mustacchi } 6927e3dbbacSRobert Mustacchi 6937e3dbbacSRobert Mustacchi return (B_TRUE); 6947e3dbbacSRobert Mustacchi } 6957e3dbbacSRobert Mustacchi 6967e3dbbacSRobert Mustacchi static boolean_t 6977e3dbbacSRobert Mustacchi cpcgen_cfile_file_after(FILE *f, cpc_map_t *map) 6987e3dbbacSRobert Mustacchi { 6997e3dbbacSRobert Mustacchi if (fprintf(f, cpcgen_cfile_table_end) == -1) { 7007e3dbbacSRobert Mustacchi warn("failed to write footer to temporary file for %s", 7017e3dbbacSRobert Mustacchi map->cmap_path); 7027e3dbbacSRobert Mustacchi return (B_FALSE); 7037e3dbbacSRobert Mustacchi } 7047e3dbbacSRobert Mustacchi 7057e3dbbacSRobert Mustacchi return (B_TRUE); 7067e3dbbacSRobert Mustacchi } 7077e3dbbacSRobert Mustacchi 7087e3dbbacSRobert Mustacchi static boolean_t 7097e3dbbacSRobert Mustacchi cpcgen_cfile_event(FILE *f, nvlist_t *nvl, const char *path, uint_t ent) 7107e3dbbacSRobert Mustacchi { 7117e3dbbacSRobert Mustacchi char *ecode, *umask, *name, *counter, *lname, *cmask; 7127e3dbbacSRobert Mustacchi size_t i; 7137e3dbbacSRobert Mustacchi 7147e3dbbacSRobert Mustacchi if (nvlist_lookup_string(nvl, "EventName", &name) != 0) { 7157e3dbbacSRobert Mustacchi warnx("Found event without 'EventName' property " 7167e3dbbacSRobert Mustacchi "in %s, entry %u", path, ent); 7177e3dbbacSRobert Mustacchi return (B_FALSE); 7187e3dbbacSRobert Mustacchi } 7197e3dbbacSRobert Mustacchi 7207e3dbbacSRobert Mustacchi if (nvlist_lookup_string(nvl, "EventCode", &ecode) != 0 || 7217e3dbbacSRobert Mustacchi nvlist_lookup_string(nvl, "UMask", &umask) != 0 || 7227e3dbbacSRobert Mustacchi nvlist_lookup_string(nvl, "Counter", &counter) != 0) { 7237e3dbbacSRobert Mustacchi warnx("event %s (index %u) from %s, missing " 7247e3dbbacSRobert Mustacchi "required properties for C file translation", 7257e3dbbacSRobert Mustacchi name, ent, path); 7267e3dbbacSRobert Mustacchi return (B_FALSE); 7277e3dbbacSRobert Mustacchi } 7287e3dbbacSRobert Mustacchi 7297e3dbbacSRobert Mustacchi /* 7307e3dbbacSRobert Mustacchi * While we could try and parse the counters manually, just do this the 7317e3dbbacSRobert Mustacchi * max power way for now based on all possible values. 7327e3dbbacSRobert Mustacchi */ 7337e3dbbacSRobert Mustacchi if (strcmp(counter, "0") == 0 || strcmp(counter, "0,") == 0) { 7347e3dbbacSRobert Mustacchi cmask = "C0"; 7357e3dbbacSRobert Mustacchi } else if (strcmp(counter, "1") == 0) { 7367e3dbbacSRobert Mustacchi cmask = "C1"; 7377e3dbbacSRobert Mustacchi } else if (strcmp(counter, "2") == 0) { 7387e3dbbacSRobert Mustacchi cmask = "C2"; 7397e3dbbacSRobert Mustacchi } else if (strcmp(counter, "3") == 0) { 7407e3dbbacSRobert Mustacchi cmask = "C3"; 7417e3dbbacSRobert Mustacchi } else if (strcmp(counter, "0,1") == 0) { 7427e3dbbacSRobert Mustacchi cmask = "C0|C1"; 7437e3dbbacSRobert Mustacchi } else if (strcmp(counter, "0,1,2") == 0) { 7447e3dbbacSRobert Mustacchi cmask = "C0|C1|C2"; 7457e3dbbacSRobert Mustacchi } else if (strcmp(counter, "0,1,2,3") == 0) { 7467e3dbbacSRobert Mustacchi cmask = "C0|C1|C2|C3"; 7477e3dbbacSRobert Mustacchi } else if (strcmp(counter, "0,2,3") == 0) { 7487e3dbbacSRobert Mustacchi cmask = "C0|C2|C3"; 7497e3dbbacSRobert Mustacchi } else if (strcmp(counter, "1,2,3") == 0) { 7507e3dbbacSRobert Mustacchi cmask = "C1|C2|C3"; 7517e3dbbacSRobert Mustacchi } else if (strcmp(counter, "2,3") == 0) { 7527e3dbbacSRobert Mustacchi cmask = "C2|C3"; 7537e3dbbacSRobert Mustacchi } else { 7547e3dbbacSRobert Mustacchi warnx("event %s (index %u) from %s, has unknown " 7557e3dbbacSRobert Mustacchi "counter value \"%s\"", name, ent, path, counter); 7567e3dbbacSRobert Mustacchi return (B_FALSE); 7577e3dbbacSRobert Mustacchi } 7587e3dbbacSRobert Mustacchi 7597e3dbbacSRobert Mustacchi 7607e3dbbacSRobert Mustacchi /* 7617e3dbbacSRobert Mustacchi * Intel uses capital names. CPC historically uses lower case names. 7627e3dbbacSRobert Mustacchi */ 7637e3dbbacSRobert Mustacchi if ((lname = strdup(name)) == NULL) { 7647e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to duplicate event name %s", name); 7657e3dbbacSRobert Mustacchi } 7667e3dbbacSRobert Mustacchi for (i = 0; lname[i] != '\0'; i++) { 7677e3dbbacSRobert Mustacchi lname[i] = tolower(name[i]); 7687e3dbbacSRobert Mustacchi } 7697e3dbbacSRobert Mustacchi 7707e3dbbacSRobert Mustacchi if (fprintf(f, "\t{ %s, %s, %s, \"%s\" },\n", ecode, umask, cmask, 7717e3dbbacSRobert Mustacchi lname) == -1) { 7727e3dbbacSRobert Mustacchi warn("failed to write out entry %s from %s", name, path); 7737e3dbbacSRobert Mustacchi free(lname); 7747e3dbbacSRobert Mustacchi return (B_FALSE); 7757e3dbbacSRobert Mustacchi } 7767e3dbbacSRobert Mustacchi 7777e3dbbacSRobert Mustacchi free(lname); 7787e3dbbacSRobert Mustacchi 7797e3dbbacSRobert Mustacchi /* 7807e3dbbacSRobert Mustacchi * Check if we have any PAPI aliases. 7817e3dbbacSRobert Mustacchi */ 7827e3dbbacSRobert Mustacchi for (i = 0; cpcgen_papi_map[i].cpapi_intc != NULL; i++) { 7837e3dbbacSRobert Mustacchi if (strcmp(name, cpcgen_papi_map[i].cpapi_intc) != 0) 7847e3dbbacSRobert Mustacchi continue; 7857e3dbbacSRobert Mustacchi 7867e3dbbacSRobert Mustacchi if (fprintf(f, "\t{ %s, %s, %s, \"%s\" },\n", ecode, umask, 7877e3dbbacSRobert Mustacchi cmask, cpcgen_papi_map[i].cpapi_papi) == -1) { 7887e3dbbacSRobert Mustacchi warn("failed to write out entry %s from %s", name, 7897e3dbbacSRobert Mustacchi path); 7907e3dbbacSRobert Mustacchi return (B_FALSE); 7917e3dbbacSRobert Mustacchi } 7927e3dbbacSRobert Mustacchi } 7937e3dbbacSRobert Mustacchi 7947e3dbbacSRobert Mustacchi return (B_TRUE); 7957e3dbbacSRobert Mustacchi } 7967e3dbbacSRobert Mustacchi 7977e3dbbacSRobert Mustacchi /* 7987e3dbbacSRobert Mustacchi * Generate a header file that declares all of these arrays and provide a map 7997e3dbbacSRobert Mustacchi * for models to the corresponding table to use. 8007e3dbbacSRobert Mustacchi */ 8017e3dbbacSRobert Mustacchi static void 8027e3dbbacSRobert Mustacchi cpcgen_common_files(int dirfd) 8037e3dbbacSRobert Mustacchi { 8047e3dbbacSRobert Mustacchi const char *fname = "core_pcbe_cpcgen.h"; 8057e3dbbacSRobert Mustacchi char *tmpname; 8067e3dbbacSRobert Mustacchi int fd; 8077e3dbbacSRobert Mustacchi FILE *f; 8087e3dbbacSRobert Mustacchi cpc_map_t *map; 8097e3dbbacSRobert Mustacchi 8107e3dbbacSRobert Mustacchi if (asprintf(&tmpname, ".%s.%d", fname, getpid()) == -1) { 8117e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to construct temporary file name"); 8127e3dbbacSRobert Mustacchi } 8137e3dbbacSRobert Mustacchi 8147e3dbbacSRobert Mustacchi if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0644)) < 0) { 8157e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to create temporary file %s", 8167e3dbbacSRobert Mustacchi tmpname); 8177e3dbbacSRobert Mustacchi } 8187e3dbbacSRobert Mustacchi 8197e3dbbacSRobert Mustacchi if ((f = fdopen(fd, "w")) == NULL) { 8207e3dbbacSRobert Mustacchi int e = errno; 8217e3dbbacSRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 8227e3dbbacSRobert Mustacchi errno = e; 8237e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to fdopen temporary file"); 8247e3dbbacSRobert Mustacchi } 8257e3dbbacSRobert Mustacchi 8267e3dbbacSRobert Mustacchi if (fprintf(f, cpcgen_cfile_header, cpcgen_mapfile) == -1) { 8277e3dbbacSRobert Mustacchi int e = errno; 8287e3dbbacSRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 8297e3dbbacSRobert Mustacchi errno = e; 8307e3dbbacSRobert Mustacchi errx(EXIT_FAILURE, "failed to write header to temporary file " 8317e3dbbacSRobert Mustacchi "for %s", fname); 8327e3dbbacSRobert Mustacchi } 8337e3dbbacSRobert Mustacchi 8347e3dbbacSRobert Mustacchi if (fprintf(f, "#ifndef _CORE_PCBE_CPCGEN_H\n" 8357e3dbbacSRobert Mustacchi "#define\t_CORE_PCBE_CPCGEN_H\n" 8367e3dbbacSRobert Mustacchi "\n" 8377e3dbbacSRobert Mustacchi "#ifdef __cplusplus\n" 8387e3dbbacSRobert Mustacchi "extern \"C\" {\n" 8397e3dbbacSRobert Mustacchi "#endif\n" 8407e3dbbacSRobert Mustacchi "\n" 8417e3dbbacSRobert Mustacchi "extern const struct events_table_t *core_cpcgen_table(uint_t);\n" 8427e3dbbacSRobert Mustacchi "\n") == -1) { 8437e3dbbacSRobert Mustacchi int e = errno; 8447e3dbbacSRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 8457e3dbbacSRobert Mustacchi errno = e; 8467e3dbbacSRobert Mustacchi errx(EXIT_FAILURE, "failed to write header to " 8477e3dbbacSRobert Mustacchi "temporary file for %s", fname); 8487e3dbbacSRobert Mustacchi } 8497e3dbbacSRobert Mustacchi 8507e3dbbacSRobert Mustacchi for (map = cpcgen_maps; map != NULL; map = map->cmap_next) { 8517e3dbbacSRobert Mustacchi if (fprintf(f, "extern const struct events_table_t " 8527e3dbbacSRobert Mustacchi "pcbe_core_events_%s[];\n", map->cmap_name) == -1) { 8537e3dbbacSRobert Mustacchi int e = errno; 8547e3dbbacSRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 8557e3dbbacSRobert Mustacchi errno = e; 8567e3dbbacSRobert Mustacchi errx(EXIT_FAILURE, "failed to write entry to " 8577e3dbbacSRobert Mustacchi "temporary file for %s", fname); 8587e3dbbacSRobert Mustacchi } 8597e3dbbacSRobert Mustacchi } 8607e3dbbacSRobert Mustacchi 8617e3dbbacSRobert Mustacchi if (fprintf(f, "\n" 8627e3dbbacSRobert Mustacchi "#ifdef __cplusplus\n" 8637e3dbbacSRobert Mustacchi "}\n" 8647e3dbbacSRobert Mustacchi "#endif\n" 8657e3dbbacSRobert Mustacchi "\n" 8667e3dbbacSRobert Mustacchi "#endif /* _CORE_PCBE_CPCGEN_H */\n") == -1) { 8677e3dbbacSRobert Mustacchi int e = errno; 8687e3dbbacSRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 8697e3dbbacSRobert Mustacchi errno = e; 8707e3dbbacSRobert Mustacchi errx(EXIT_FAILURE, "failed to write header to " 8717e3dbbacSRobert Mustacchi "temporary file for %s", fname); 8727e3dbbacSRobert Mustacchi } 8737e3dbbacSRobert Mustacchi 8747e3dbbacSRobert Mustacchi if (fflush(f) != 0 || fclose(f) != 0) { 8757e3dbbacSRobert Mustacchi int e = errno; 8767e3dbbacSRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 8777e3dbbacSRobert Mustacchi errno = e; 8787e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to flush and close temporary file"); 8797e3dbbacSRobert Mustacchi } 8807e3dbbacSRobert Mustacchi 8817e3dbbacSRobert Mustacchi if (renameat(dirfd, tmpname, dirfd, fname) != 0) { 8827e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to rename temporary file %s", 8837e3dbbacSRobert Mustacchi tmpname); 8847e3dbbacSRobert Mustacchi } 8857e3dbbacSRobert Mustacchi 8867e3dbbacSRobert Mustacchi free(tmpname); 8877e3dbbacSRobert Mustacchi 8887e3dbbacSRobert Mustacchi /* Now again for the .c file. */ 8897e3dbbacSRobert Mustacchi fname = "core_pcbe_cpcgen.c"; 8907e3dbbacSRobert Mustacchi if (asprintf(&tmpname, ".%s.%d", fname, getpid()) == -1) { 8917e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to construct temporary file name"); 8927e3dbbacSRobert Mustacchi } 8937e3dbbacSRobert Mustacchi 8947e3dbbacSRobert Mustacchi if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0644)) < 0) { 8957e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to create temporary file %s", 8967e3dbbacSRobert Mustacchi tmpname); 8977e3dbbacSRobert Mustacchi } 8987e3dbbacSRobert Mustacchi 8997e3dbbacSRobert Mustacchi if ((f = fdopen(fd, "w")) == NULL) { 9007e3dbbacSRobert Mustacchi int e = errno; 9017e3dbbacSRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 9027e3dbbacSRobert Mustacchi errno = e; 9037e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to fdopen temporary file"); 9047e3dbbacSRobert Mustacchi } 9057e3dbbacSRobert Mustacchi 9067e3dbbacSRobert Mustacchi if (fprintf(f, cpcgen_cfile_header, cpcgen_mapfile) == -1) { 9077e3dbbacSRobert Mustacchi int e = errno; 9087e3dbbacSRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 9097e3dbbacSRobert Mustacchi errno = e; 9107e3dbbacSRobert Mustacchi errx(EXIT_FAILURE, "failed to write header to temporary file " 9117e3dbbacSRobert Mustacchi "for %s", fname); 9127e3dbbacSRobert Mustacchi } 9137e3dbbacSRobert Mustacchi 9147e3dbbacSRobert Mustacchi if (fprintf(f, "#include <core_pcbe_table.h>\n" 9157e3dbbacSRobert Mustacchi "#include <sys/null.h>\n" 9167e3dbbacSRobert Mustacchi "#include \"core_pcbe_cpcgen.h\"\n" 9177e3dbbacSRobert Mustacchi "\n" 9187e3dbbacSRobert Mustacchi "const struct events_table_t *\n" 9197e3dbbacSRobert Mustacchi "core_cpcgen_table(uint_t model)\n" 9207e3dbbacSRobert Mustacchi "{\n" 9217e3dbbacSRobert Mustacchi "\tswitch (model) {\n") == -1) { 9227e3dbbacSRobert Mustacchi int e = errno; 9237e3dbbacSRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 9247e3dbbacSRobert Mustacchi errno = e; 9257e3dbbacSRobert Mustacchi errx(EXIT_FAILURE, "failed to write header to " 9267e3dbbacSRobert Mustacchi "temporary file for %s", fname); 9277e3dbbacSRobert Mustacchi } 9287e3dbbacSRobert Mustacchi 9297e3dbbacSRobert Mustacchi for (map = cpcgen_maps; map != NULL; map = map->cmap_next) { 9307e3dbbacSRobert Mustacchi cpc_proc_t *p; 9317e3dbbacSRobert Mustacchi for (p = map->cmap_procs; p != NULL; p = p->cproc_next) { 9327e3dbbacSRobert Mustacchi assert(p->cproc_family == 6); 9337e3dbbacSRobert Mustacchi if (fprintf(f, "\t\tcase 0x%x:\n", p->cproc_model) == 9347e3dbbacSRobert Mustacchi -1) { 9357e3dbbacSRobert Mustacchi int e = errno; 9367e3dbbacSRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 9377e3dbbacSRobert Mustacchi errno = e; 9387e3dbbacSRobert Mustacchi errx(EXIT_FAILURE, "failed to write header to " 9397e3dbbacSRobert Mustacchi "temporary file for %s", fname); 9407e3dbbacSRobert Mustacchi } 9417e3dbbacSRobert Mustacchi } 9427e3dbbacSRobert Mustacchi if (fprintf(f, "\t\t\treturn (pcbe_core_events_%s);\n", 9437e3dbbacSRobert Mustacchi map->cmap_name) == -1) { 9447e3dbbacSRobert Mustacchi int e = errno; 9457e3dbbacSRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 9467e3dbbacSRobert Mustacchi errno = e; 9477e3dbbacSRobert Mustacchi errx(EXIT_FAILURE, "failed to write entry to " 9487e3dbbacSRobert Mustacchi "temporary file for %s", fname); 9497e3dbbacSRobert Mustacchi } 9507e3dbbacSRobert Mustacchi } 9517e3dbbacSRobert Mustacchi 9527e3dbbacSRobert Mustacchi if (fprintf(f, "\t\tdefault:\n" 9537e3dbbacSRobert Mustacchi "\t\t\treturn (NULL);\n" 9547e3dbbacSRobert Mustacchi "\t}\n" 9557e3dbbacSRobert Mustacchi "}\n") == -1) { 9567e3dbbacSRobert Mustacchi int e = errno; 9577e3dbbacSRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 9587e3dbbacSRobert Mustacchi errno = e; 9597e3dbbacSRobert Mustacchi errx(EXIT_FAILURE, "failed to write header to " 9607e3dbbacSRobert Mustacchi "temporary file for %s", fname); 9617e3dbbacSRobert Mustacchi } 9627e3dbbacSRobert Mustacchi 9637e3dbbacSRobert Mustacchi if (fflush(f) != 0 || fclose(f) != 0) { 9647e3dbbacSRobert Mustacchi int e = errno; 9657e3dbbacSRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 9667e3dbbacSRobert Mustacchi errno = e; 9677e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to flush and close temporary file"); 9687e3dbbacSRobert Mustacchi } 9697e3dbbacSRobert Mustacchi 9707e3dbbacSRobert Mustacchi if (renameat(dirfd, tmpname, dirfd, fname) != 0) { 9717e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to rename temporary file %s", 9727e3dbbacSRobert Mustacchi tmpname); 9737e3dbbacSRobert Mustacchi } 9747e3dbbacSRobert Mustacchi 9757e3dbbacSRobert Mustacchi free(tmpname); 9767e3dbbacSRobert Mustacchi } 9777e3dbbacSRobert Mustacchi 9787e3dbbacSRobert Mustacchi /* 9797e3dbbacSRobert Mustacchi * Look at a rule to determine whether or not we should consider including it or 9807e3dbbacSRobert Mustacchi * not. At this point we've already filtered things such that we only get core 9817e3dbbacSRobert Mustacchi * events. 9827e3dbbacSRobert Mustacchi * 9837e3dbbacSRobert Mustacchi * To consider an entry, we currently apply the following criteria: 9847e3dbbacSRobert Mustacchi * 9857e3dbbacSRobert Mustacchi * - The MSRIndex and MSRValue are zero. Programming additional MSRs is no 9867e3dbbacSRobert Mustacchi * supported right now. 9877e3dbbacSRobert Mustacchi * - TakenAlone is non-zero, which means that it cannot run at the same time as 9887e3dbbacSRobert Mustacchi * another field. 9897e3dbbacSRobert Mustacchi * - Offcore is one, indicating that it is off the core and we need to figure 9907e3dbbacSRobert Mustacchi * out if we can support this. 9917e3dbbacSRobert Mustacchi * - If the counter is fixed, don't use it for now. 9927e3dbbacSRobert Mustacchi * - If more than one value is specified in the EventCode or UMask values 9937e3dbbacSRobert Mustacchi */ 9947e3dbbacSRobert Mustacchi static boolean_t 9957e3dbbacSRobert Mustacchi cpcgen_skip_entry(nvlist_t *nvl, const char *path, uint_t ent) 9967e3dbbacSRobert Mustacchi { 9977e3dbbacSRobert Mustacchi char *event, *msridx, *msrval, *taken, *offcore, *counter; 9987e3dbbacSRobert Mustacchi char *ecode, *umask; 9997e3dbbacSRobert Mustacchi 10007e3dbbacSRobert Mustacchi /* 10017e3dbbacSRobert Mustacchi * Require EventName, it's kind of useless without that. 10027e3dbbacSRobert Mustacchi */ 10037e3dbbacSRobert Mustacchi if (nvlist_lookup_string(nvl, "EventName", &event) != 0) { 10047e3dbbacSRobert Mustacchi errx(EXIT_FAILURE, "Found event without 'EventName' property " 10057e3dbbacSRobert Mustacchi "in %s, entry %u", path, ent); 10067e3dbbacSRobert Mustacchi } 10077e3dbbacSRobert Mustacchi 10087e3dbbacSRobert Mustacchi /* 10097e3dbbacSRobert Mustacchi * If we can't find an expected value, whine about it. 10107e3dbbacSRobert Mustacchi */ 10117e3dbbacSRobert Mustacchi if (nvlist_lookup_string(nvl, "MSRIndex", &msridx) != 0 || 10127e3dbbacSRobert Mustacchi nvlist_lookup_string(nvl, "MSRValue", &msrval) != 0 || 10137e3dbbacSRobert Mustacchi nvlist_lookup_string(nvl, "Counter", &counter) != 0 || 10147e3dbbacSRobert Mustacchi nvlist_lookup_string(nvl, "EventCode", &ecode) != 0 || 10157e3dbbacSRobert Mustacchi nvlist_lookup_string(nvl, "UMask", &umask) != 0 || 10167e3dbbacSRobert Mustacchi nvlist_lookup_string(nvl, "Offcore", &offcore) != 0) { 10177e3dbbacSRobert Mustacchi warnx("Skipping event %s (index %u) from %s, missing required " 10187e3dbbacSRobert Mustacchi "property", event, ent, path); 10197e3dbbacSRobert Mustacchi return (B_TRUE); 10207e3dbbacSRobert Mustacchi } 10217e3dbbacSRobert Mustacchi 10227e3dbbacSRobert Mustacchi /* 10237e3dbbacSRobert Mustacchi * MSRIndex and MSRvalue comes as either "0" or "0x00". 10247e3dbbacSRobert Mustacchi */ 10257e3dbbacSRobert Mustacchi if ((strcmp(msridx, "0") != 0 && strcmp(msridx, "0x00") != 0) || 10267e3dbbacSRobert Mustacchi (strcmp(msrval, "0") != 0 && strcmp(msridx, "0x00") != 0) || 10277e3dbbacSRobert Mustacchi strcmp(offcore, "0") != 0 || strchr(ecode, ',') != NULL || 10287e3dbbacSRobert Mustacchi strchr(umask, ',') != NULL) { 10297e3dbbacSRobert Mustacchi return (B_TRUE); 10307e3dbbacSRobert Mustacchi } 10317e3dbbacSRobert Mustacchi 10327e3dbbacSRobert Mustacchi /* 10337e3dbbacSRobert Mustacchi * Unfortunately, not everything actually has "TakenAlone". If it 10347e3dbbacSRobert Mustacchi * doesn't, we assume that it doesn't have to be. 10357e3dbbacSRobert Mustacchi */ 10367e3dbbacSRobert Mustacchi if (nvlist_lookup_string(nvl, "TakenAlone", &taken) == 0 && 10377e3dbbacSRobert Mustacchi strcmp(taken, "0") != 0) { 10387e3dbbacSRobert Mustacchi return (B_TRUE); 10397e3dbbacSRobert Mustacchi } 10407e3dbbacSRobert Mustacchi 10417e3dbbacSRobert Mustacchi 10427e3dbbacSRobert Mustacchi if (strncasecmp(counter, "fixed", strlen("fixed")) == 0) 10437e3dbbacSRobert Mustacchi return (B_TRUE); 10447e3dbbacSRobert Mustacchi 10457e3dbbacSRobert Mustacchi return (B_FALSE); 10467e3dbbacSRobert Mustacchi } 10477e3dbbacSRobert Mustacchi 10487e3dbbacSRobert Mustacchi /* 10497e3dbbacSRobert Mustacchi * For each processor family, generate a data file that contains all of the 10507e3dbbacSRobert Mustacchi * events that we support. Also generate a header that can be included that 10517e3dbbacSRobert Mustacchi * declares all of the tables. 10527e3dbbacSRobert Mustacchi */ 10537e3dbbacSRobert Mustacchi static void 10547e3dbbacSRobert Mustacchi cpcgen_gen(int dirfd) 10557e3dbbacSRobert Mustacchi { 10567e3dbbacSRobert Mustacchi cpc_map_t *map = cpcgen_maps; 10577e3dbbacSRobert Mustacchi 10587e3dbbacSRobert Mustacchi if (map == NULL) { 10597e3dbbacSRobert Mustacchi errx(EXIT_FAILURE, "no platforms found or matched"); 10607e3dbbacSRobert Mustacchi } 10617e3dbbacSRobert Mustacchi 10627e3dbbacSRobert Mustacchi for (map = cpcgen_maps; map != NULL; map = map->cmap_next) { 10637e3dbbacSRobert Mustacchi int fd, ret; 10647e3dbbacSRobert Mustacchi FILE *f; 10657e3dbbacSRobert Mustacchi char *tmpname, *name; 10667e3dbbacSRobert Mustacchi uint32_t length, i; 10677e3dbbacSRobert Mustacchi 10687e3dbbacSRobert Mustacchi if ((name = cpcgen_ops.cgen_op_name(map)) == NULL) { 10697e3dbbacSRobert Mustacchi exit(EXIT_FAILURE); 10707e3dbbacSRobert Mustacchi } 10717e3dbbacSRobert Mustacchi 10727e3dbbacSRobert Mustacchi if (asprintf(&tmpname, ".%s.%d", name, getpid()) == -1) { 10737e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to construct temporary file " 10747e3dbbacSRobert Mustacchi "name"); 10757e3dbbacSRobert Mustacchi } 10767e3dbbacSRobert Mustacchi 10777e3dbbacSRobert Mustacchi if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0444)) < 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 (!cpcgen_ops.cgen_op_file_before(f, map)) { 10907e3dbbacSRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 10917e3dbbacSRobert Mustacchi exit(EXIT_FAILURE); 10927e3dbbacSRobert Mustacchi } 10937e3dbbacSRobert Mustacchi 10947e3dbbacSRobert Mustacchi /* 10957e3dbbacSRobert Mustacchi * Iterate over array contents. 10967e3dbbacSRobert Mustacchi */ 10977e3dbbacSRobert Mustacchi if ((ret = nvlist_lookup_uint32(map->cmap_data, "length", 10987e3dbbacSRobert Mustacchi &length)) != 0) { 10997e3dbbacSRobert Mustacchi errx(EXIT_FAILURE, "failed to look up length property " 11007e3dbbacSRobert Mustacchi "in parsed data for %s: %s", map->cmap_path, 11017e3dbbacSRobert Mustacchi strerror(ret)); 11027e3dbbacSRobert Mustacchi } 11037e3dbbacSRobert Mustacchi 11047e3dbbacSRobert Mustacchi for (i = 0; i < length; i++) { 11057e3dbbacSRobert Mustacchi nvlist_t *nvl; 11067e3dbbacSRobert Mustacchi char num[64]; 11077e3dbbacSRobert Mustacchi 11087e3dbbacSRobert Mustacchi (void) snprintf(num, sizeof (num), "%u", i); 11097e3dbbacSRobert Mustacchi if ((ret = nvlist_lookup_nvlist(map->cmap_data, 11107e3dbbacSRobert Mustacchi num, &nvl)) != 0) { 11117e3dbbacSRobert Mustacchi errx(EXIT_FAILURE, "failed to look up array " 11127e3dbbacSRobert Mustacchi "entry %u in parsed data for %s: %s", i, 11137e3dbbacSRobert Mustacchi map->cmap_path, strerror(ret)); 11147e3dbbacSRobert Mustacchi } 11157e3dbbacSRobert Mustacchi 11167e3dbbacSRobert Mustacchi if (cpcgen_skip_entry(nvl, map->cmap_path, i)) 11177e3dbbacSRobert Mustacchi continue; 11187e3dbbacSRobert Mustacchi 11197e3dbbacSRobert Mustacchi if (!cpcgen_ops.cgen_op_event(f, nvl, map->cmap_path, 11207e3dbbacSRobert Mustacchi i)) { 11217e3dbbacSRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 11227e3dbbacSRobert Mustacchi exit(EXIT_FAILURE); 11237e3dbbacSRobert Mustacchi } 11247e3dbbacSRobert Mustacchi } 11257e3dbbacSRobert Mustacchi 11267e3dbbacSRobert Mustacchi if (!cpcgen_ops.cgen_op_file_after(f, map)) { 11277e3dbbacSRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 11287e3dbbacSRobert Mustacchi exit(EXIT_FAILURE); 11297e3dbbacSRobert Mustacchi } 11307e3dbbacSRobert Mustacchi 11317e3dbbacSRobert Mustacchi if (fflush(f) != 0 || fclose(f) != 0) { 11327e3dbbacSRobert Mustacchi int e = errno; 11337e3dbbacSRobert Mustacchi (void) unlinkat(dirfd, tmpname, 0); 11347e3dbbacSRobert Mustacchi errno = e; 11357e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to flush and close " 11367e3dbbacSRobert Mustacchi "temporary file"); 11377e3dbbacSRobert Mustacchi } 11387e3dbbacSRobert Mustacchi 11397e3dbbacSRobert Mustacchi if (renameat(dirfd, tmpname, dirfd, name) != 0) { 11407e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to rename temporary file %s", 11417e3dbbacSRobert Mustacchi tmpname); 11427e3dbbacSRobert Mustacchi } 11437e3dbbacSRobert Mustacchi 11447e3dbbacSRobert Mustacchi free(name); 11457e3dbbacSRobert Mustacchi free(tmpname); 11467e3dbbacSRobert Mustacchi } 11477e3dbbacSRobert Mustacchi } 11487e3dbbacSRobert Mustacchi 11497e3dbbacSRobert Mustacchi static void 11507e3dbbacSRobert Mustacchi cpcgen_usage(const char *fmt, ...) 11517e3dbbacSRobert Mustacchi { 11527e3dbbacSRobert Mustacchi if (fmt != NULL) { 11537e3dbbacSRobert Mustacchi va_list ap; 11547e3dbbacSRobert Mustacchi 11557e3dbbacSRobert Mustacchi (void) fprintf(stderr, "%s: ", cpcgen_progname); 11567e3dbbacSRobert Mustacchi va_start(ap, fmt); 11577e3dbbacSRobert Mustacchi (void) vfprintf(stderr, fmt, ap); 11587e3dbbacSRobert Mustacchi va_end(ap); 11597e3dbbacSRobert Mustacchi } 11607e3dbbacSRobert Mustacchi 11617e3dbbacSRobert Mustacchi (void) fprintf(stderr, "Usage: %s -a|-p platform -c|-H|-m -d datadir " 11627e3dbbacSRobert Mustacchi "-o outdir\n" 11637e3dbbacSRobert Mustacchi "\n" 11647e3dbbacSRobert Mustacchi "\t-a generate data for all platforms\n" 11657e3dbbacSRobert Mustacchi "\t-c generate C file for CPC\n" 11667e3dbbacSRobert Mustacchi "\t-d specify the directory containt perfmon data\n" 11677e3dbbacSRobert Mustacchi "\t-h generate header file and common files\n" 11687e3dbbacSRobert Mustacchi "\t-m generate manual pages for CPC data\n" 11697e3dbbacSRobert Mustacchi "\t-o outut files in directory outdir\n" 11707e3dbbacSRobert Mustacchi "\t-p generate data for a specified platform\n", 11717e3dbbacSRobert Mustacchi cpcgen_progname); 11727e3dbbacSRobert Mustacchi } 11737e3dbbacSRobert Mustacchi 11747e3dbbacSRobert Mustacchi int 11757e3dbbacSRobert Mustacchi main(int argc, char *argv[]) 11767e3dbbacSRobert Mustacchi { 11777e3dbbacSRobert Mustacchi int c, outdirfd; 11787e3dbbacSRobert Mustacchi boolean_t do_mpage = B_FALSE, do_cfile = B_FALSE, do_header = B_FALSE, 11797e3dbbacSRobert Mustacchi do_all = B_FALSE; 11807e3dbbacSRobert Mustacchi const char *datadir = NULL, *outdir = NULL, *platform = NULL; 11817e3dbbacSRobert Mustacchi uint_t count = 0; 11827e3dbbacSRobert Mustacchi 11837e3dbbacSRobert Mustacchi cpcgen_progname = basename(argv[0]); 11847e3dbbacSRobert Mustacchi 11857e3dbbacSRobert Mustacchi while ((c = getopt(argc, argv, ":acd:hHmo:p:")) != -1) { 11867e3dbbacSRobert Mustacchi switch (c) { 11877e3dbbacSRobert Mustacchi case 'a': 11887e3dbbacSRobert Mustacchi do_all = B_TRUE; 11897e3dbbacSRobert Mustacchi break; 11907e3dbbacSRobert Mustacchi case 'c': 11917e3dbbacSRobert Mustacchi do_cfile = B_TRUE; 11927e3dbbacSRobert Mustacchi break; 11937e3dbbacSRobert Mustacchi case 'd': 11947e3dbbacSRobert Mustacchi datadir = optarg; 11957e3dbbacSRobert Mustacchi break; 11967e3dbbacSRobert Mustacchi case 'm': 11977e3dbbacSRobert Mustacchi do_mpage = B_TRUE; 11987e3dbbacSRobert Mustacchi break; 11997e3dbbacSRobert Mustacchi case 'H': 12007e3dbbacSRobert Mustacchi do_header = B_TRUE; 12017e3dbbacSRobert Mustacchi break; 12027e3dbbacSRobert Mustacchi case 'o': 12037e3dbbacSRobert Mustacchi outdir = optarg; 12047e3dbbacSRobert Mustacchi break; 12057e3dbbacSRobert Mustacchi case 'p': 12067e3dbbacSRobert Mustacchi platform = optarg; 12077e3dbbacSRobert Mustacchi break; 12087e3dbbacSRobert Mustacchi case ':': 12097e3dbbacSRobert Mustacchi cpcgen_usage("Option -%c requires an operand\n", 12107e3dbbacSRobert Mustacchi optopt); 12117e3dbbacSRobert Mustacchi return (2); 12127e3dbbacSRobert Mustacchi case '?': 12137e3dbbacSRobert Mustacchi cpcgen_usage("Unknown option: -%c\n", optopt); 12147e3dbbacSRobert Mustacchi return (2); 12157e3dbbacSRobert Mustacchi case 'h': 12167e3dbbacSRobert Mustacchi default: 12177e3dbbacSRobert Mustacchi cpcgen_usage(NULL); 12187e3dbbacSRobert Mustacchi return (2); 12197e3dbbacSRobert Mustacchi } 12207e3dbbacSRobert Mustacchi } 12217e3dbbacSRobert Mustacchi 12227e3dbbacSRobert Mustacchi count = 0; 12237e3dbbacSRobert Mustacchi if (do_mpage) 12247e3dbbacSRobert Mustacchi count++; 12257e3dbbacSRobert Mustacchi if (do_cfile) 12267e3dbbacSRobert Mustacchi count++; 12277e3dbbacSRobert Mustacchi if (do_header) 12287e3dbbacSRobert Mustacchi count++; 12297e3dbbacSRobert Mustacchi if (count > 1) { 12307e3dbbacSRobert Mustacchi cpcgen_usage("Only one of -c, -h, and -m may be specified\n"); 12317e3dbbacSRobert Mustacchi return (2); 12327e3dbbacSRobert Mustacchi } else if (count == 0) { 12337e3dbbacSRobert Mustacchi cpcgen_usage("One of -c, -h, and -m is required\n"); 12347e3dbbacSRobert Mustacchi return (2); 12357e3dbbacSRobert Mustacchi } 12367e3dbbacSRobert Mustacchi 12377e3dbbacSRobert Mustacchi count = 0; 12387e3dbbacSRobert Mustacchi if (do_all) 12397e3dbbacSRobert Mustacchi count++; 12407e3dbbacSRobert Mustacchi if (platform != NULL) 12417e3dbbacSRobert Mustacchi count++; 12427e3dbbacSRobert Mustacchi if (count > 1) { 12437e3dbbacSRobert Mustacchi cpcgen_usage("Only one of -a and -p may be specified\n"); 12447e3dbbacSRobert Mustacchi return (2); 12457e3dbbacSRobert Mustacchi } else if (count == 0) { 12467e3dbbacSRobert Mustacchi cpcgen_usage("One of -a and -p is required\n"); 12477e3dbbacSRobert Mustacchi return (2); 12487e3dbbacSRobert Mustacchi } 12497e3dbbacSRobert Mustacchi 12507e3dbbacSRobert Mustacchi 12517e3dbbacSRobert Mustacchi if (outdir == NULL) { 12527e3dbbacSRobert Mustacchi cpcgen_usage("Missing required output directory (-o)\n"); 12537e3dbbacSRobert Mustacchi return (2); 12547e3dbbacSRobert Mustacchi } 12557e3dbbacSRobert Mustacchi 12567e3dbbacSRobert Mustacchi if ((outdirfd = open(outdir, O_RDONLY)) < 0) { 12577e3dbbacSRobert Mustacchi err(EXIT_FAILURE, "failed to open output directory %s", outdir); 12587e3dbbacSRobert Mustacchi } 12597e3dbbacSRobert Mustacchi 12607e3dbbacSRobert Mustacchi if (datadir == NULL) { 12617e3dbbacSRobert Mustacchi cpcgen_usage("Missing required data directory (-d)\n"); 12627e3dbbacSRobert Mustacchi return (2); 12637e3dbbacSRobert Mustacchi } 12647e3dbbacSRobert Mustacchi 12657e3dbbacSRobert Mustacchi cpcgen_read_mapfile(datadir, platform); 12667e3dbbacSRobert Mustacchi 12677e3dbbacSRobert Mustacchi if (do_header) { 12687e3dbbacSRobert Mustacchi cpcgen_common_files(outdirfd); 12697e3dbbacSRobert Mustacchi return (0); 12707e3dbbacSRobert Mustacchi } 12717e3dbbacSRobert Mustacchi 12727e3dbbacSRobert Mustacchi if (do_mpage) { 12737e3dbbacSRobert Mustacchi cpcgen_ops.cgen_op_name = cpcgen_manual_name; 12747e3dbbacSRobert Mustacchi cpcgen_ops.cgen_op_file_before = cpcgen_manual_file_before; 12757e3dbbacSRobert Mustacchi cpcgen_ops.cgen_op_file_after = cpcgen_manual_file_after; 12767e3dbbacSRobert Mustacchi cpcgen_ops.cgen_op_event = cpcgen_manual_event; 12777e3dbbacSRobert Mustacchi } 12787e3dbbacSRobert Mustacchi 12797e3dbbacSRobert Mustacchi if (do_cfile) { 12807e3dbbacSRobert Mustacchi cpcgen_ops.cgen_op_name = cpcgen_cfile_name; 12817e3dbbacSRobert Mustacchi cpcgen_ops.cgen_op_file_before = cpcgen_cfile_file_before; 12827e3dbbacSRobert Mustacchi cpcgen_ops.cgen_op_file_after = cpcgen_cfile_file_after; 12837e3dbbacSRobert Mustacchi cpcgen_ops.cgen_op_event = cpcgen_cfile_event; 12847e3dbbacSRobert Mustacchi } 12857e3dbbacSRobert Mustacchi 12867e3dbbacSRobert Mustacchi 12877e3dbbacSRobert Mustacchi cpcgen_gen(outdirfd); 12887e3dbbacSRobert Mustacchi 12897e3dbbacSRobert Mustacchi return (0); 12907e3dbbacSRobert Mustacchi } 1291