112ae924aSRobert Mustacchi /*
212ae924aSRobert Mustacchi * This file and its contents are supplied under the terms of the
312ae924aSRobert Mustacchi * Common Development and Distribution License ("CDDL"), version 1.0.
412ae924aSRobert Mustacchi * You may only use this file in accordance with the terms of version
512ae924aSRobert Mustacchi * 1.0 of the CDDL.
612ae924aSRobert Mustacchi *
712ae924aSRobert Mustacchi * A full copy of the text of the CDDL should have accompanied this
812ae924aSRobert Mustacchi * source. A copy of the CDDL is also available via the Internet at
912ae924aSRobert Mustacchi * http://www.illumos.org/license/CDDL.
1012ae924aSRobert Mustacchi */
1112ae924aSRobert Mustacchi
1212ae924aSRobert Mustacchi /*
13e9e38cc6SJohn Levon * Copyright (c) 2019, Joyent, Inc.
1412ae924aSRobert Mustacchi */
1512ae924aSRobert Mustacchi
1612ae924aSRobert Mustacchi /*
17*d573a566SRobert Mustacchi * This program transforms Intel perfmon and AMD PMC data files into C files and
18*d573a566SRobert Mustacchi * manual pages.
1912ae924aSRobert Mustacchi */
2012ae924aSRobert Mustacchi
2112ae924aSRobert Mustacchi #include <stdio.h>
2212ae924aSRobert Mustacchi #include <stdarg.h>
2312ae924aSRobert Mustacchi #include <unistd.h>
2412ae924aSRobert Mustacchi #include <err.h>
2512ae924aSRobert Mustacchi #include <libgen.h>
2612ae924aSRobert Mustacchi #include <libnvpair.h>
2712ae924aSRobert Mustacchi #include <strings.h>
2812ae924aSRobert Mustacchi #include <errno.h>
2912ae924aSRobert Mustacchi #include <limits.h>
3012ae924aSRobert Mustacchi #include <sys/mman.h>
3112ae924aSRobert Mustacchi #include <sys/param.h>
3212ae924aSRobert Mustacchi #include <assert.h>
3312ae924aSRobert Mustacchi #include <ctype.h>
3412ae924aSRobert Mustacchi #include <sys/types.h>
3512ae924aSRobert Mustacchi #include <sys/stat.h>
3612ae924aSRobert Mustacchi #include <fcntl.h>
37*d573a566SRobert Mustacchi #include <dirent.h>
3812ae924aSRobert Mustacchi
3912ae924aSRobert Mustacchi #include <json_nvlist.h>
4012ae924aSRobert Mustacchi
4112ae924aSRobert Mustacchi #define EXIT_USAGE 2
42fea24e13SRobert Mustacchi #define CPROC_MAX_STEPPINGS 16
4312ae924aSRobert Mustacchi
44*d573a566SRobert Mustacchi typedef enum {
45*d573a566SRobert Mustacchi CPCGEN_MODE_UNKNOWN = 0,
46*d573a566SRobert Mustacchi CPCGEN_MODE_INTEL,
47*d573a566SRobert Mustacchi CPCGEN_MODE_AMD
48*d573a566SRobert Mustacchi } cpc_mode_t;
49*d573a566SRobert Mustacchi
5012ae924aSRobert Mustacchi typedef struct cpc_proc {
5112ae924aSRobert Mustacchi struct cpc_proc *cproc_next;
5212ae924aSRobert Mustacchi uint_t cproc_family;
5312ae924aSRobert Mustacchi uint_t cproc_model;
54fea24e13SRobert Mustacchi uint_t cproc_nsteps;
55fea24e13SRobert Mustacchi uint_t cproc_steppings[CPROC_MAX_STEPPINGS];
5612ae924aSRobert Mustacchi } cpc_proc_t;
5712ae924aSRobert Mustacchi
5812ae924aSRobert Mustacchi typedef enum cpc_file_type {
5912ae924aSRobert Mustacchi CPC_FILE_CORE = 1 << 0,
6012ae924aSRobert Mustacchi CPC_FILE_OFF_CORE = 1 << 1,
6112ae924aSRobert Mustacchi CPC_FILE_UNCORE = 1 << 2,
6212ae924aSRobert Mustacchi CPC_FILE_FP_MATH = 1 << 3,
6312ae924aSRobert Mustacchi CPC_FILE_UNCORE_EXP = 1 << 4
6412ae924aSRobert Mustacchi } cpc_type_t;
6512ae924aSRobert Mustacchi
6612ae924aSRobert Mustacchi typedef struct cpc_map {
6712ae924aSRobert Mustacchi struct cpc_map *cmap_next;
6812ae924aSRobert Mustacchi cpc_type_t cmap_type;
6912ae924aSRobert Mustacchi nvlist_t *cmap_data;
7012ae924aSRobert Mustacchi char *cmap_path;
7112ae924aSRobert Mustacchi const char *cmap_name;
7212ae924aSRobert Mustacchi cpc_proc_t *cmap_procs;
7312ae924aSRobert Mustacchi } cpc_map_t;
7412ae924aSRobert Mustacchi
7512ae924aSRobert Mustacchi typedef struct cpc_whitelist {
7612ae924aSRobert Mustacchi const char *cwhite_short;
7712ae924aSRobert Mustacchi const char *cwhite_human;
7812ae924aSRobert Mustacchi uint_t cwhite_mask;
7912ae924aSRobert Mustacchi } cpc_whitelist_t;
8012ae924aSRobert Mustacchi
8112ae924aSRobert Mustacchi /*
8212ae924aSRobert Mustacchi * List of architectures that we support generating this data for. This is done
8312ae924aSRobert Mustacchi * so that processors that illumos doesn't support or run on aren't generated
8412ae924aSRobert Mustacchi * (generally the Xeon Phi).
8512ae924aSRobert Mustacchi */
86*d573a566SRobert Mustacchi static cpc_whitelist_t cpcgen_intel_whitelist[] = {
8712ae924aSRobert Mustacchi /* Nehalem */
8812ae924aSRobert Mustacchi { "NHM-EP", "nhm_ep", CPC_FILE_CORE },
8912ae924aSRobert Mustacchi { "NHM-EX", "nhm_ex", CPC_FILE_CORE },
9012ae924aSRobert Mustacchi /* Westmere */
9112ae924aSRobert Mustacchi { "WSM-EP-DP", "wsm_ep_dp", CPC_FILE_CORE },
9212ae924aSRobert Mustacchi { "WSM-EP-SP", "wsm_ep_sp", CPC_FILE_CORE },
9312ae924aSRobert Mustacchi { "WSM-EX", "wsm_ex", CPC_FILE_CORE },
9412ae924aSRobert Mustacchi /* Sandy Bridge */
9512ae924aSRobert Mustacchi { "SNB", "snb", CPC_FILE_CORE },
9612ae924aSRobert Mustacchi { "JKT", "jkt", CPC_FILE_CORE },
9712ae924aSRobert Mustacchi /* Ivy Bridge */
9812ae924aSRobert Mustacchi { "IVB", "ivb", CPC_FILE_CORE },
9912ae924aSRobert Mustacchi { "IVT", "ivt", CPC_FILE_CORE },
10012ae924aSRobert Mustacchi /* Haswell */
10112ae924aSRobert Mustacchi { "HSW", "hsw", CPC_FILE_CORE },
10212ae924aSRobert Mustacchi { "HSX", "hsx", CPC_FILE_CORE },
10312ae924aSRobert Mustacchi /* Broadwell */
10412ae924aSRobert Mustacchi { "BDW", "bdw", CPC_FILE_CORE },
10512ae924aSRobert Mustacchi { "BDW-DE", "bdw_de", CPC_FILE_CORE },
10612ae924aSRobert Mustacchi { "BDX", "bdx", CPC_FILE_CORE },
10712ae924aSRobert Mustacchi /* Skylake */
10812ae924aSRobert Mustacchi { "SKL", "skl", CPC_FILE_CORE },
10912ae924aSRobert Mustacchi { "SKX", "skx", CPC_FILE_CORE },
110fea24e13SRobert Mustacchi /* Cascade Lake */
111fea24e13SRobert Mustacchi { "CLX", "clx", CPC_FILE_CORE },
11212ae924aSRobert Mustacchi /* Atom */
11312ae924aSRobert Mustacchi { "BNL", "bnl", CPC_FILE_CORE },
11412ae924aSRobert Mustacchi { "SLM", "slm", CPC_FILE_CORE },
11512ae924aSRobert Mustacchi { "GLM", "glm", CPC_FILE_CORE },
11612ae924aSRobert Mustacchi { "GLP", "glp", CPC_FILE_CORE },
11712ae924aSRobert Mustacchi { NULL }
11812ae924aSRobert Mustacchi };
11912ae924aSRobert Mustacchi
12012ae924aSRobert Mustacchi typedef struct cpc_papi {
12112ae924aSRobert Mustacchi const char *cpapi_intc;
12212ae924aSRobert Mustacchi const char *cpapi_papi;
12312ae924aSRobert Mustacchi } cpc_papi_t;
12412ae924aSRobert Mustacchi
12512ae924aSRobert Mustacchi /*
12612ae924aSRobert Mustacchi * This table maps events with an Intel specific name to the corresponding PAPI
127fea24e13SRobert Mustacchi * name. There may be multiple Intel events which map to the same PAPI event.
12812ae924aSRobert Mustacchi * This is usually because different processors have different names for an
12912ae924aSRobert Mustacchi * event. We use the title as opposed to the event codes because those can
13012ae924aSRobert Mustacchi * change somewhat arbitrarily between processor generations.
13112ae924aSRobert Mustacchi */
132*d573a566SRobert Mustacchi static cpc_papi_t cpcgen_intel_papi_map[] = {
13312ae924aSRobert Mustacchi { "CPU_CLK_UNHALTED.THREAD_P", "PAPI_tot_cyc" },
13412ae924aSRobert Mustacchi { "INST_RETIRED.ANY_P", "PAPI_tot_ins" },
13512ae924aSRobert Mustacchi { "BR_INST_RETIRED.ALL_BRANCHES", "PAPI_br_ins" },
13612ae924aSRobert Mustacchi { "BR_MISP_RETIRED.ALL_BRANCHES", "PAPI_br_msp" },
13712ae924aSRobert Mustacchi { "BR_INST_RETIRED.CONDITIONAL", "PAPI_br_cn" },
13812ae924aSRobert Mustacchi { "CYCLE_ACTIVITY.CYCLES_L1D_MISS", "PAPI_l1_dcm" },
13912ae924aSRobert Mustacchi { "L1I.HITS", "PAPI_l1_ich" },
14012ae924aSRobert Mustacchi { "ICACHE.HIT", "PAPI_l1_ich" },
14112ae924aSRobert Mustacchi { "L1I.MISS", "PAPI_L1_icm" },
14212ae924aSRobert Mustacchi { "ICACHE.MISSES", "PAPI_l1_icm" },
14312ae924aSRobert Mustacchi { "L1I.READS", "PAPI_l1_ica" },
14412ae924aSRobert Mustacchi { "ICACHE.ACCESSES", "PAPI_l1_ica" },
14512ae924aSRobert Mustacchi { "L1I.READS", "PAPI_l1_icr" },
14612ae924aSRobert Mustacchi { "ICACHE.ACCESSES", "PAPI_l1_icr" },
14712ae924aSRobert Mustacchi { "L2_RQSTS.CODE_RD_MISS", "PAPI_l2_icm" },
14812ae924aSRobert Mustacchi { "L2_RQSTS.MISS", "PAPI_l2_tcm" },
14912ae924aSRobert Mustacchi { "ITLB_MISSES.MISS_CAUSES_A_WALK", "PAPI_tlb_im" },
15012ae924aSRobert Mustacchi { "DTLB_LOAD_MISSES.MISS_CAUSES_A_WALK", "PAPI_tlb_dm" },
15112ae924aSRobert Mustacchi { "PAGE_WALKS.D_SIDE_WALKS", "PAPI_tlb_dm" },
15212ae924aSRobert Mustacchi { "PAGE_WALKS.I_SIDE_WALKS", "PAPI_tlb_im" },
15312ae924aSRobert Mustacchi { "PAGE_WALKS.WALKS", "PAPI_tlb_tl" },
15412ae924aSRobert Mustacchi { "INST_QUEUE_WRITES", "PAPI_tot_iis" },
15512ae924aSRobert Mustacchi { "MEM_INST_RETIRED.STORES" "PAPI_sr_ins" },
15612ae924aSRobert Mustacchi { "MEM_INST_RETIRED.LOADS" "PAPI_ld_ins" },
15712ae924aSRobert Mustacchi { NULL, NULL }
15812ae924aSRobert Mustacchi };
15912ae924aSRobert Mustacchi
16012ae924aSRobert Mustacchi typedef struct cpcgen_ops {
161*d573a566SRobert Mustacchi void (*cgen_op_gather)(const char *, const char *);
162*d573a566SRobert Mustacchi void (*cgen_op_common)(int);
16312ae924aSRobert Mustacchi char *(*cgen_op_name)(cpc_map_t *);
164*d573a566SRobert Mustacchi boolean_t (*cgen_op_skip)(nvlist_t *, const char *, uint_t);
16512ae924aSRobert Mustacchi boolean_t (*cgen_op_file_before)(FILE *, cpc_map_t *);
16612ae924aSRobert Mustacchi boolean_t (*cgen_op_file_after)(FILE *, cpc_map_t *);
16712ae924aSRobert Mustacchi boolean_t (*cgen_op_event)(FILE *, nvlist_t *, const char *, uint32_t);
16812ae924aSRobert Mustacchi } cpcgen_ops_t;
16912ae924aSRobert Mustacchi
17012ae924aSRobert Mustacchi static cpcgen_ops_t cpcgen_ops;
171*d573a566SRobert Mustacchi static const char *cpcgen_intel_mapfile = "/mapfile.csv";
17212ae924aSRobert Mustacchi static const char *cpcgen_progname;
17312ae924aSRobert Mustacchi static cpc_map_t *cpcgen_maps;
174*d573a566SRobert Mustacchi static cpc_mode_t cpcgen_mode = CPCGEN_MODE_UNKNOWN;
17512ae924aSRobert Mustacchi
17612ae924aSRobert Mustacchi /*
17712ae924aSRobert Mustacchi * Constants used for generating data.
17812ae924aSRobert Mustacchi */
17912ae924aSRobert Mustacchi /* BEGIN CSTYLED */
180*d573a566SRobert Mustacchi static const char *cpcgen_cfile_intel_header = ""
18112ae924aSRobert Mustacchi "/*\n"
18212ae924aSRobert Mustacchi " * Copyright (c) 2018, Intel Corporation\n"
18312ae924aSRobert Mustacchi " * Copyright (c) 2018, Joyent, Inc\n"
18412ae924aSRobert Mustacchi " * All rights reserved.\n"
18512ae924aSRobert Mustacchi " *\n"
18612ae924aSRobert Mustacchi " * Redistribution and use in source and binary forms, with or without\n"
18712ae924aSRobert Mustacchi " * modification, are permitted provided that the following conditions are met:\n"
18812ae924aSRobert Mustacchi " * \n"
18912ae924aSRobert Mustacchi " * 1. Redistributions of source code must retain the above copyright notice,\n"
19012ae924aSRobert Mustacchi " * this list of conditions and the following disclaimer.\n"
19112ae924aSRobert Mustacchi " * \n"
19212ae924aSRobert Mustacchi " * 2. Redistributions in binary form must reproduce the above copyright \n"
19312ae924aSRobert Mustacchi " * notice, this list of conditions and the following disclaimer in the\n"
19412ae924aSRobert Mustacchi " * documentation and/or other materials provided with the distribution.\n"
19512ae924aSRobert Mustacchi " * \n"
19612ae924aSRobert Mustacchi " * 3. Neither the name of the Intel Corporation nor the names of its \n"
19712ae924aSRobert Mustacchi " * contributors may be used to endorse or promote products derived from\n"
19812ae924aSRobert Mustacchi " * this software without specific prior written permission.\n"
19912ae924aSRobert Mustacchi " *\n"
20012ae924aSRobert Mustacchi " * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n"
20112ae924aSRobert Mustacchi " * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n"
20212ae924aSRobert Mustacchi " * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
20312ae924aSRobert Mustacchi " * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n"
20412ae924aSRobert Mustacchi " * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n"
20512ae924aSRobert Mustacchi " * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n"
20612ae924aSRobert Mustacchi " * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n"
20712ae924aSRobert Mustacchi " * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n"
20812ae924aSRobert Mustacchi " * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n"
20912ae924aSRobert Mustacchi " * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n"
21012ae924aSRobert Mustacchi " * POSSIBILITY OF SUCH DAMAGE.\n"
21112ae924aSRobert Mustacchi " *\n"
21212ae924aSRobert Mustacchi " * This file was automatically generated by cpcgen from the data file\n"
21312ae924aSRobert Mustacchi " * data/perfmon%s\n"
21412ae924aSRobert Mustacchi " *\n"
21512ae924aSRobert Mustacchi " * Do not modify this file. Your changes will be lost!\n"
21612ae924aSRobert Mustacchi " */\n"
21712ae924aSRobert Mustacchi "\n";
21812ae924aSRobert Mustacchi /* END CSTYLED */
21912ae924aSRobert Mustacchi
220*d573a566SRobert Mustacchi static const char *cpcgen_cfile_intel_table_start = ""
22112ae924aSRobert Mustacchi "#include <core_pcbe_table.h>\n"
22212ae924aSRobert Mustacchi "\n"
22312ae924aSRobert Mustacchi "const struct events_table_t pcbe_core_events_%s[] = {\n";
22412ae924aSRobert Mustacchi
225*d573a566SRobert Mustacchi static const char *cpcgen_cfile_intel_table_end = ""
22612ae924aSRobert Mustacchi "\t{ NT_END, 0, 0, \"\" }\n"
22712ae924aSRobert Mustacchi "};\n";
22812ae924aSRobert Mustacchi
22912ae924aSRobert Mustacchi /* BEGIN CSTYLED */
230*d573a566SRobert Mustacchi static const char *cpcgen_manual_intel_intel_header = ""
23112ae924aSRobert Mustacchi ".\\\" Copyright (c) 2018, Intel Corporation \n"
23212ae924aSRobert Mustacchi ".\\\" Copyright (c) 2018, Joyent, Inc.\n"
23312ae924aSRobert Mustacchi ".\\\" All rights reserved.\n"
23412ae924aSRobert Mustacchi ".\\\"\n"
23512ae924aSRobert Mustacchi ".\\\" Redistribution and use in source and binary forms, with or without \n"
23612ae924aSRobert Mustacchi ".\\\" modification, are permitted provided that the following conditions are met:\n"
23712ae924aSRobert Mustacchi ".\\\"\n"
23812ae924aSRobert Mustacchi ".\\\" 1. Redistributions of source code must retain the above copyright notice,\n"
23912ae924aSRobert Mustacchi ".\\\" this list of conditions and the following disclaimer.\n"
24012ae924aSRobert Mustacchi ".\\\"\n"
24112ae924aSRobert Mustacchi ".\\\" 2. Redistributions in binary form must reproduce the above copyright\n"
24212ae924aSRobert Mustacchi ".\\\" notice, this list of conditions and the following disclaimer in the\n"
24312ae924aSRobert Mustacchi ".\\\" documentation and/or other materials provided with the distribution.\n"
24412ae924aSRobert Mustacchi ".\\\"\n"
24512ae924aSRobert Mustacchi ".\\\" 3. Neither the name of the Intel Corporation nor the names of its\n"
24612ae924aSRobert Mustacchi ".\\\" contributors may be used to endorse or promote products derived from\n"
24712ae924aSRobert Mustacchi ".\\\" this software without specific prior written permission.\n"
24812ae924aSRobert Mustacchi ".\\\"\n"
24912ae924aSRobert Mustacchi ".\\\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n"
25012ae924aSRobert Mustacchi ".\\\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n"
25112ae924aSRobert Mustacchi ".\\\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
25212ae924aSRobert Mustacchi ".\\\" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n"
25312ae924aSRobert Mustacchi ".\\\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n"
25412ae924aSRobert Mustacchi ".\\\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n"
25512ae924aSRobert Mustacchi ".\\\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n"
25612ae924aSRobert Mustacchi ".\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n"
25712ae924aSRobert Mustacchi ".\\\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n"
25812ae924aSRobert Mustacchi ".\\\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n"
25912ae924aSRobert Mustacchi ".\\\" POSSIBILITY OF SUCH DAMAGE.\n"
26012ae924aSRobert Mustacchi ".\\\"\n"
26112ae924aSRobert Mustacchi ".\\\" This file was automatically generated by cpcgen from the data file\n"
26212ae924aSRobert Mustacchi ".\\\" data/perfmon%s\n"
26312ae924aSRobert Mustacchi ".\\\"\n"
26412ae924aSRobert Mustacchi ".\\\" Do not modify this file. Your changes will be lost!\n"
26512ae924aSRobert Mustacchi ".\\\"\n"
26612ae924aSRobert Mustacchi ".\\\" We would like to thank Intel for providing the perfmon data for use in\n"
26712ae924aSRobert Mustacchi ".\\\" our manual pages.\n"
26812ae924aSRobert Mustacchi ".Dd June 18, 2018\n"
26912ae924aSRobert Mustacchi ".Dt %s_EVENTS 3CPC\n"
27012ae924aSRobert Mustacchi ".Os\n"
27112ae924aSRobert Mustacchi ".Sh NAME\n"
27212ae924aSRobert Mustacchi ".Nm %s_events\n"
27312ae924aSRobert Mustacchi ".Nd processor model specific performance counter events\n"
27412ae924aSRobert Mustacchi ".Sh DESCRIPTION\n"
27512ae924aSRobert Mustacchi "This manual page describes events specific to the following Intel CPU\n"
27612ae924aSRobert Mustacchi "models and is derived from Intel's perfmon data.\n"
27712ae924aSRobert Mustacchi "For more information, please consult the Intel Software Developer's Manual "
27812ae924aSRobert Mustacchi "or Intel's perfmon website.\n"
27912ae924aSRobert Mustacchi ".Pp\n"
28012ae924aSRobert Mustacchi "CPU models described by this document:\n"
28112ae924aSRobert Mustacchi ".Bl -bullet\n";
28212ae924aSRobert Mustacchi /* END CSTYLED */
28312ae924aSRobert Mustacchi
284*d573a566SRobert Mustacchi static const char *cpcgen_manual_intel_data = ""
28512ae924aSRobert Mustacchi ".El\n"
28612ae924aSRobert Mustacchi ".Pp\n"
28712ae924aSRobert Mustacchi "The following events are supported:\n"
28812ae924aSRobert Mustacchi ".Bl -tag -width Sy\n";
28912ae924aSRobert Mustacchi
290*d573a566SRobert Mustacchi static const char *cpcgen_manual_intel_trailer = ""
29112ae924aSRobert Mustacchi ".El\n"
29212ae924aSRobert Mustacchi ".Sh SEE ALSO\n"
29312ae924aSRobert Mustacchi ".Xr cpc 3CPC\n"
29412ae924aSRobert Mustacchi ".Pp\n"
29512ae924aSRobert Mustacchi ".Lk https://download.01.org/perfmon/index/";
29612ae924aSRobert Mustacchi
297*d573a566SRobert Mustacchi static const char *cpcgen_cfile_cddl_header = ""
298*d573a566SRobert Mustacchi "/*\n"
299*d573a566SRobert Mustacchi " * This file and its contents are supplied under the terms of the\n"
300*d573a566SRobert Mustacchi " * Common Development and Distribution License (\"CDDL\"), version 1.0.\n"
301*d573a566SRobert Mustacchi " * You may only use this file in accordance with the terms of version\n"
302*d573a566SRobert Mustacchi " * 1.0 of the CDDL.\n"
303*d573a566SRobert Mustacchi " *\n"
304*d573a566SRobert Mustacchi " * A full copy of the text of the CDDL should have accompanied this\n"
305*d573a566SRobert Mustacchi " * source. A copy of the CDDL is also available via the Internet at\n"
306*d573a566SRobert Mustacchi " * http://www.illumos.org/license/CDDL.\n"
307*d573a566SRobert Mustacchi " */\n"
308*d573a566SRobert Mustacchi "\n"
309*d573a566SRobert Mustacchi "/*\n"
310*d573a566SRobert Mustacchi " * Copyright 2019 Joyent, Inc\n"
311*d573a566SRobert Mustacchi " */\n"
312*d573a566SRobert Mustacchi "\n"
313*d573a566SRobert Mustacchi "/*\n"
314*d573a566SRobert Mustacchi " * This file was automatically generated by cpcgen.\n"
315*d573a566SRobert Mustacchi " */\n"
316*d573a566SRobert Mustacchi "\n"
317*d573a566SRobert Mustacchi "/*\n"
318*d573a566SRobert Mustacchi " * Do not modify this file. Your changes will be lost!\n"
319*d573a566SRobert Mustacchi " */\n"
320*d573a566SRobert Mustacchi "\n";
321*d573a566SRobert Mustacchi
322*d573a566SRobert Mustacchi static const char *cpcgen_manual_amd_header = ""
323*d573a566SRobert Mustacchi ".\\\" This file was automatically generated by cpcgen from the data file\n"
324*d573a566SRobert Mustacchi ".\\\" data/amdpmc/%s\n"
325*d573a566SRobert Mustacchi ".\\\"\n"
326*d573a566SRobert Mustacchi ".\\\" Do not modify this file. Your changes will be lost!\n"
327*d573a566SRobert Mustacchi ".\\\"\n"
328*d573a566SRobert Mustacchi ".\\\" We would like to thank AMD for providing the PMC data for use in\n"
329*d573a566SRobert Mustacchi ".\\\" our manual pages.\n"
330*d573a566SRobert Mustacchi ".Dd March 25, 2019\n"
331*d573a566SRobert Mustacchi ".Dt AMD_%s_EVENTS 3CPC\n"
332*d573a566SRobert Mustacchi ".Os\n"
333*d573a566SRobert Mustacchi ".Sh NAME\n"
334*d573a566SRobert Mustacchi ".Nm amd_%s_events\n"
335*d573a566SRobert Mustacchi ".Nd AMD family %s processor performance monitoring events\n"
336*d573a566SRobert Mustacchi ".Sh DESCRIPTION\n"
337*d573a566SRobert Mustacchi "This manual page describes events specfic to AMD family %s processors.\n"
338*d573a566SRobert Mustacchi "For more information, please consult the appropriate AMD BIOS and Kernel\n"
339*d573a566SRobert Mustacchi "Developer's guide or Open-Source Register Reference manual.\n"
340*d573a566SRobert Mustacchi ".Pp\n"
341*d573a566SRobert Mustacchi "Each of the events listed below includes the AMD mnemonic which matches\n"
342*d573a566SRobert Mustacchi "the name found in the AMD manual and a brief summary of the event.\n"
343*d573a566SRobert Mustacchi "If available, a more detailed description of the event follows and then\n"
344*d573a566SRobert Mustacchi "any additional unit values that modify the event.\n"
345*d573a566SRobert Mustacchi "Each unit can be combined to create a new event in the system by placing\n"
346*d573a566SRobert Mustacchi "the '.' character between the event name and the unit name.\n"
347*d573a566SRobert Mustacchi ".Pp\n"
348*d573a566SRobert Mustacchi "The following events are supported:\n"
349*d573a566SRobert Mustacchi ".Bl -tag -width Sy\n";
350*d573a566SRobert Mustacchi
351*d573a566SRobert Mustacchi static const char *cpcgen_manual_amd_trailer = ""
352*d573a566SRobert Mustacchi ".El\n"
353*d573a566SRobert Mustacchi ".Sh SEE ALSO\n"
354*d573a566SRobert Mustacchi ".Xr cpc 3CPC\n";
355*d573a566SRobert Mustacchi
356*d573a566SRobert Mustacchi static const char *cpcgen_cfile_amd_header = ""
357*d573a566SRobert Mustacchi "/*\n"
358*d573a566SRobert Mustacchi " * This file was automatically generated by cpcgen from the data file\n"
359*d573a566SRobert Mustacchi " * data/perfmon%s\n"
360*d573a566SRobert Mustacchi " *\n"
361*d573a566SRobert Mustacchi " * Do not modify this file. Your changes will be lost!\n"
362*d573a566SRobert Mustacchi " */\n"
363*d573a566SRobert Mustacchi "\n";
364*d573a566SRobert Mustacchi
365*d573a566SRobert Mustacchi static const char *cpcgen_cfile_amd_table_start = ""
366*d573a566SRobert Mustacchi "#include <opteron_pcbe_table.h>\n"
367*d573a566SRobert Mustacchi "#include <sys/null.h>\n"
368*d573a566SRobert Mustacchi "\n"
369*d573a566SRobert Mustacchi "const amd_event_t opteron_pcbe_%s_events[] = {\n";
370*d573a566SRobert Mustacchi
371*d573a566SRobert Mustacchi static const char *cpcgen_cfile_amd_table_end = ""
372*d573a566SRobert Mustacchi "\t{ NULL, 0, 0 }\n"
373*d573a566SRobert Mustacchi "};\n";
374*d573a566SRobert Mustacchi
37512ae924aSRobert Mustacchi static cpc_map_t *
cpcgen_map_lookup(const char * path)37612ae924aSRobert Mustacchi cpcgen_map_lookup(const char *path)
37712ae924aSRobert Mustacchi {
37812ae924aSRobert Mustacchi cpc_map_t *m;
37912ae924aSRobert Mustacchi
38012ae924aSRobert Mustacchi for (m = cpcgen_maps; m != NULL; m = m->cmap_next) {
38112ae924aSRobert Mustacchi if (strcmp(path, m->cmap_path) == 0) {
38212ae924aSRobert Mustacchi return (m);
38312ae924aSRobert Mustacchi }
38412ae924aSRobert Mustacchi }
38512ae924aSRobert Mustacchi
38612ae924aSRobert Mustacchi return (NULL);
38712ae924aSRobert Mustacchi }
38812ae924aSRobert Mustacchi
38912ae924aSRobert Mustacchi /*
39012ae924aSRobert Mustacchi * Parse a string of the form 'GenuineIntel-6-2E' and get out the family and
39112ae924aSRobert Mustacchi * model.
39212ae924aSRobert Mustacchi */
39312ae924aSRobert Mustacchi static void
cpcgen_parse_model(char * fsr,uint_t * family,uint_t * model,uint_t * nstepp,uint_t * steppings)394fea24e13SRobert Mustacchi cpcgen_parse_model(char *fsr, uint_t *family, uint_t *model, uint_t *nstepp,
395fea24e13SRobert Mustacchi uint_t *steppings)
39612ae924aSRobert Mustacchi {
39712ae924aSRobert Mustacchi const char *bstr = "GenuineIntel";
398fea24e13SRobert Mustacchi const char *brand, *fam, *mod, *step;
39912ae924aSRobert Mustacchi char *last;
40012ae924aSRobert Mustacchi long l;
401fea24e13SRobert Mustacchi uint_t nstep = 0;
40212ae924aSRobert Mustacchi
403fea24e13SRobert Mustacchi /*
404fea24e13SRobert Mustacchi * Tokeninze the string. There may be an optional stepping portion,
405fea24e13SRobert Mustacchi * which has a range of steppings enclosed by '[' and ']' characters.
406fea24e13SRobert Mustacchi * While the other parts are required, the stepping may be missing.
407fea24e13SRobert Mustacchi */
40812ae924aSRobert Mustacchi if ((brand = strtok_r(fsr, "-", &last)) == NULL ||
40912ae924aSRobert Mustacchi (fam = strtok_r(NULL, "-", &last)) == NULL ||
41012ae924aSRobert Mustacchi (mod = strtok_r(NULL, "-", &last)) == NULL) {
41112ae924aSRobert Mustacchi errx(EXIT_FAILURE, "failed to parse processor id \"%s\"", fsr);
41212ae924aSRobert Mustacchi }
413fea24e13SRobert Mustacchi step = strtok_r(NULL, "-", &last);
41412ae924aSRobert Mustacchi
41512ae924aSRobert Mustacchi if (strcmp(bstr, brand) != 0) {
41612ae924aSRobert Mustacchi errx(EXIT_FAILURE, "brand string \"%s\" did not match \"%s\"",
41712ae924aSRobert Mustacchi brand, bstr);
41812ae924aSRobert Mustacchi }
41912ae924aSRobert Mustacchi
42012ae924aSRobert Mustacchi errno = 0;
42112ae924aSRobert Mustacchi l = strtol(fam, &last, 16);
422fea24e13SRobert Mustacchi if (errno != 0 || l < 0 || l > UINT_MAX || *last != '\0') {
42312ae924aSRobert Mustacchi errx(EXIT_FAILURE, "failed to parse family \"%s\"", fam);
42412ae924aSRobert Mustacchi }
42512ae924aSRobert Mustacchi *family = (uint_t)l;
42612ae924aSRobert Mustacchi
42712ae924aSRobert Mustacchi l = strtol(mod, &last, 16);
428fea24e13SRobert Mustacchi if (errno != 0 || l < 0 || l > UINT_MAX || *last != '\0') {
42912ae924aSRobert Mustacchi errx(EXIT_FAILURE, "failed to parse model \"%s\"", mod);
43012ae924aSRobert Mustacchi }
43112ae924aSRobert Mustacchi *model = (uint_t)l;
432fea24e13SRobert Mustacchi
433fea24e13SRobert Mustacchi if (step == NULL) {
434fea24e13SRobert Mustacchi *nstepp = 0;
435fea24e13SRobert Mustacchi return;
436fea24e13SRobert Mustacchi }
437fea24e13SRobert Mustacchi
438fea24e13SRobert Mustacchi if (*step != '[' || ((last = strrchr(step, ']')) == NULL)) {
439fea24e13SRobert Mustacchi errx(EXIT_FAILURE, "failed to parse stepping \"%s\": missing "
440fea24e13SRobert Mustacchi "stepping range brackets", step);
441fea24e13SRobert Mustacchi }
442fea24e13SRobert Mustacchi step++;
443fea24e13SRobert Mustacchi *last = '\0';
444fea24e13SRobert Mustacchi while (*step != '\0') {
445fea24e13SRobert Mustacchi if (!isxdigit(*step)) {
446fea24e13SRobert Mustacchi errx(EXIT_FAILURE, "failed to parse stepping: invalid "
447fea24e13SRobert Mustacchi "stepping identifier '0x%x'", *step);
448fea24e13SRobert Mustacchi }
449fea24e13SRobert Mustacchi
450fea24e13SRobert Mustacchi if (nstep >= CPROC_MAX_STEPPINGS) {
451fea24e13SRobert Mustacchi errx(EXIT_FAILURE, "failed to parse stepping: "
452fea24e13SRobert Mustacchi "encountered too many steppings");
453fea24e13SRobert Mustacchi }
454fea24e13SRobert Mustacchi
455fea24e13SRobert Mustacchi switch (*step) {
456fea24e13SRobert Mustacchi case '0':
457fea24e13SRobert Mustacchi steppings[nstep] = 0x0;
458fea24e13SRobert Mustacchi break;
459fea24e13SRobert Mustacchi case '1':
460fea24e13SRobert Mustacchi steppings[nstep] = 0x1;
461fea24e13SRobert Mustacchi break;
462fea24e13SRobert Mustacchi case '2':
463fea24e13SRobert Mustacchi steppings[nstep] = 0x2;
464fea24e13SRobert Mustacchi break;
465fea24e13SRobert Mustacchi case '3':
466fea24e13SRobert Mustacchi steppings[nstep] = 0x3;
467fea24e13SRobert Mustacchi break;
468fea24e13SRobert Mustacchi case '4':
469fea24e13SRobert Mustacchi steppings[nstep] = 0x4;
470fea24e13SRobert Mustacchi break;
471fea24e13SRobert Mustacchi case '5':
472fea24e13SRobert Mustacchi steppings[nstep] = 0x5;
473fea24e13SRobert Mustacchi break;
474fea24e13SRobert Mustacchi case '6':
475fea24e13SRobert Mustacchi steppings[nstep] = 0x6;
476fea24e13SRobert Mustacchi break;
477fea24e13SRobert Mustacchi case '7':
478fea24e13SRobert Mustacchi steppings[nstep] = 0x7;
479fea24e13SRobert Mustacchi break;
480fea24e13SRobert Mustacchi case '8':
481fea24e13SRobert Mustacchi steppings[nstep] = 0x8;
482fea24e13SRobert Mustacchi break;
483fea24e13SRobert Mustacchi case '9':
484fea24e13SRobert Mustacchi steppings[nstep] = 0x9;
485fea24e13SRobert Mustacchi break;
486fea24e13SRobert Mustacchi case 'a':
487fea24e13SRobert Mustacchi case 'A':
488fea24e13SRobert Mustacchi steppings[nstep] = 0xa;
489fea24e13SRobert Mustacchi break;
490fea24e13SRobert Mustacchi case 'b':
491fea24e13SRobert Mustacchi case 'B':
492fea24e13SRobert Mustacchi steppings[nstep] = 0xb;
493fea24e13SRobert Mustacchi break;
494fea24e13SRobert Mustacchi case 'c':
495fea24e13SRobert Mustacchi case 'C':
496fea24e13SRobert Mustacchi steppings[nstep] = 0xc;
497fea24e13SRobert Mustacchi break;
498fea24e13SRobert Mustacchi case 'd':
499fea24e13SRobert Mustacchi case 'D':
500fea24e13SRobert Mustacchi steppings[nstep] = 0xd;
501fea24e13SRobert Mustacchi break;
502fea24e13SRobert Mustacchi case 'e':
503fea24e13SRobert Mustacchi case 'E':
504fea24e13SRobert Mustacchi steppings[nstep] = 0xe;
505fea24e13SRobert Mustacchi break;
506fea24e13SRobert Mustacchi case 'f':
507fea24e13SRobert Mustacchi case 'F':
508fea24e13SRobert Mustacchi steppings[nstep] = 0xf;
509fea24e13SRobert Mustacchi break;
510fea24e13SRobert Mustacchi default:
511fea24e13SRobert Mustacchi errx(EXIT_FAILURE, "encountered non-hex stepping "
512fea24e13SRobert Mustacchi "character: '%c'", *step);
513fea24e13SRobert Mustacchi }
514fea24e13SRobert Mustacchi nstep++;
515fea24e13SRobert Mustacchi step++;
516fea24e13SRobert Mustacchi }
517fea24e13SRobert Mustacchi
518fea24e13SRobert Mustacchi *nstepp = nstep;
51912ae924aSRobert Mustacchi }
52012ae924aSRobert Mustacchi
52112ae924aSRobert Mustacchi static nvlist_t *
cpcgen_read_datafile(const char * datadir,const char * file)52212ae924aSRobert Mustacchi cpcgen_read_datafile(const char *datadir, const char *file)
52312ae924aSRobert Mustacchi {
52412ae924aSRobert Mustacchi int fd;
52512ae924aSRobert Mustacchi char *path;
52612ae924aSRobert Mustacchi struct stat st;
52712ae924aSRobert Mustacchi void *map;
52812ae924aSRobert Mustacchi nvlist_t *nvl;
52912ae924aSRobert Mustacchi nvlist_parse_json_error_t jerr;
53012ae924aSRobert Mustacchi
53112ae924aSRobert Mustacchi if (asprintf(&path, "%s/%s", datadir, file) == -1) {
53212ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to construct path to data file %s",
53312ae924aSRobert Mustacchi file);
53412ae924aSRobert Mustacchi }
53512ae924aSRobert Mustacchi
53612ae924aSRobert Mustacchi if ((fd = open(path, O_RDONLY)) < 0) {
53712ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to open data file %s", path);
53812ae924aSRobert Mustacchi }
53912ae924aSRobert Mustacchi
54012ae924aSRobert Mustacchi if (fstat(fd, &st) != 0) {
54112ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to stat %s", path);
54212ae924aSRobert Mustacchi }
54312ae924aSRobert Mustacchi
54412ae924aSRobert Mustacchi if ((map = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
54512ae924aSRobert Mustacchi fd, 0)) == MAP_FAILED) {
54612ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to mmap %s", path);
54712ae924aSRobert Mustacchi }
54812ae924aSRobert Mustacchi
54912ae924aSRobert Mustacchi if (nvlist_parse_json(map, st.st_size, &nvl, NVJSON_FORCE_INTEGER,
55012ae924aSRobert Mustacchi &jerr) != 0) {
55112ae924aSRobert Mustacchi errx(EXIT_FAILURE, "failed to parse file %s at pos %ld: %s",
55212ae924aSRobert Mustacchi path, jerr.nje_pos, jerr.nje_message);
55312ae924aSRobert Mustacchi }
55412ae924aSRobert Mustacchi
55512ae924aSRobert Mustacchi if (munmap(map, st.st_size) != 0) {
55612ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to munmap %s", path);
55712ae924aSRobert Mustacchi }
55812ae924aSRobert Mustacchi
55912ae924aSRobert Mustacchi if (close(fd) != 0) {
56012ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to close data file %s", path);
56112ae924aSRobert Mustacchi }
56212ae924aSRobert Mustacchi free(path);
56312ae924aSRobert Mustacchi
56412ae924aSRobert Mustacchi return (nvl);
56512ae924aSRobert Mustacchi }
56612ae924aSRobert Mustacchi
56712ae924aSRobert Mustacchi /*
56812ae924aSRobert Mustacchi * Check the whitelist to see if we should use this model.
56912ae924aSRobert Mustacchi */
57012ae924aSRobert Mustacchi static const char *
cpcgen_use_arch(const char * path,cpc_type_t type,const char * platform)57112ae924aSRobert Mustacchi cpcgen_use_arch(const char *path, cpc_type_t type, const char *platform)
57212ae924aSRobert Mustacchi {
57312ae924aSRobert Mustacchi const char *slash;
57412ae924aSRobert Mustacchi size_t len;
57512ae924aSRobert Mustacchi uint_t i;
57612ae924aSRobert Mustacchi
57712ae924aSRobert Mustacchi if (*path != '/') {
57812ae924aSRobert Mustacchi errx(EXIT_FAILURE, "invalid path in mapfile: \"%s\": missing "
57912ae924aSRobert Mustacchi "leading '/'", path);
58012ae924aSRobert Mustacchi }
58112ae924aSRobert Mustacchi if ((slash = strchr(path + 1, '/')) == NULL) {
58212ae924aSRobert Mustacchi errx(EXIT_FAILURE, "invalid path in mapfile: \"%s\": missing "
58312ae924aSRobert Mustacchi "second '/'", path);
58412ae924aSRobert Mustacchi }
58512ae924aSRobert Mustacchi /* Account for the last '/' character. */
58612ae924aSRobert Mustacchi len = slash - path - 1;
58712ae924aSRobert Mustacchi assert(len > 0);
58812ae924aSRobert Mustacchi
589*d573a566SRobert Mustacchi for (i = 0; cpcgen_intel_whitelist[i].cwhite_short != NULL; i++) {
59012ae924aSRobert Mustacchi if (platform != NULL && strcasecmp(platform,
591*d573a566SRobert Mustacchi cpcgen_intel_whitelist[i].cwhite_short) != 0)
59212ae924aSRobert Mustacchi continue;
593*d573a566SRobert Mustacchi if (strncmp(path + 1, cpcgen_intel_whitelist[i].cwhite_short,
59412ae924aSRobert Mustacchi len) == 0 &&
595*d573a566SRobert Mustacchi (cpcgen_intel_whitelist[i].cwhite_mask & type) == type) {
596*d573a566SRobert Mustacchi return (cpcgen_intel_whitelist[i].cwhite_human);
59712ae924aSRobert Mustacchi }
59812ae924aSRobert Mustacchi }
59912ae924aSRobert Mustacchi
60012ae924aSRobert Mustacchi return (NULL);
60112ae924aSRobert Mustacchi }
60212ae924aSRobert Mustacchi
60312ae924aSRobert Mustacchi /*
604*d573a566SRobert Mustacchi * Determine which CPU Vendor we're transmuting data from.
605*d573a566SRobert Mustacchi */
606*d573a566SRobert Mustacchi static void
cpcgen_determine_vendor(const char * datadir)607*d573a566SRobert Mustacchi cpcgen_determine_vendor(const char *datadir)
608*d573a566SRobert Mustacchi {
609*d573a566SRobert Mustacchi char *mappath;
610*d573a566SRobert Mustacchi struct stat st;
611*d573a566SRobert Mustacchi
612*d573a566SRobert Mustacchi if (asprintf(&mappath, "%s/%s", datadir, cpcgen_intel_mapfile) == -1) {
613*d573a566SRobert Mustacchi err(EXIT_FAILURE, "failed to construct path to mapfile");
614*d573a566SRobert Mustacchi }
615*d573a566SRobert Mustacchi
616*d573a566SRobert Mustacchi if (stat(mappath, &st) == 0) {
617*d573a566SRobert Mustacchi cpcgen_mode = CPCGEN_MODE_INTEL;
618*d573a566SRobert Mustacchi } else {
619*d573a566SRobert Mustacchi if (errno != ENOENT) {
620*d573a566SRobert Mustacchi err(EXIT_FAILURE, "stat(2) of %s failed unexpectedly");
621*d573a566SRobert Mustacchi }
622*d573a566SRobert Mustacchi
623*d573a566SRobert Mustacchi cpcgen_mode = CPCGEN_MODE_AMD;
624*d573a566SRobert Mustacchi }
625*d573a566SRobert Mustacchi
626*d573a566SRobert Mustacchi free(mappath);
627*d573a566SRobert Mustacchi }
628*d573a566SRobert Mustacchi
629*d573a566SRobert Mustacchi /*
630*d573a566SRobert Mustacchi * Read in all the data files that exist for AMD.
631*d573a566SRobert Mustacchi *
632*d573a566SRobert Mustacchi * Our family names for AMD systems are based on the family and type so a given
633*d573a566SRobert Mustacchi * name will look like f17h_core.json.
634*d573a566SRobert Mustacchi */
635*d573a566SRobert Mustacchi static void
cpcgen_read_amd(const char * datadir,const char * platform)636*d573a566SRobert Mustacchi cpcgen_read_amd(const char *datadir, const char *platform)
637*d573a566SRobert Mustacchi {
638*d573a566SRobert Mustacchi DIR *dir;
639*d573a566SRobert Mustacchi struct dirent *d;
640*d573a566SRobert Mustacchi const char *suffix = ".json";
641*d573a566SRobert Mustacchi const size_t slen = strlen(suffix);
642*d573a566SRobert Mustacchi
643*d573a566SRobert Mustacchi if ((dir = opendir(datadir)) == NULL) {
644*d573a566SRobert Mustacchi err(EXIT_FAILURE, "failed to open directory %s", datadir);
645*d573a566SRobert Mustacchi }
646*d573a566SRobert Mustacchi
647*d573a566SRobert Mustacchi while ((d = readdir(dir)) != NULL) {
648*d573a566SRobert Mustacchi char *name, *c;
649*d573a566SRobert Mustacchi cpc_map_t *map;
650*d573a566SRobert Mustacchi nvlist_t *parsed;
651*d573a566SRobert Mustacchi
652*d573a566SRobert Mustacchi if ((name = strdup(d->d_name)) == NULL) {
653*d573a566SRobert Mustacchi errx(EXIT_FAILURE, "ran out of memory duplicating "
654*d573a566SRobert Mustacchi "name %s", d->d_name);
655*d573a566SRobert Mustacchi }
656*d573a566SRobert Mustacchi c = strstr(name, suffix);
657*d573a566SRobert Mustacchi
658*d573a566SRobert Mustacchi if (c == NULL) {
659*d573a566SRobert Mustacchi free(name);
660*d573a566SRobert Mustacchi continue;
661*d573a566SRobert Mustacchi }
662*d573a566SRobert Mustacchi
663*d573a566SRobert Mustacchi if (*(c + slen) != '\0') {
664*d573a566SRobert Mustacchi free(name);
665*d573a566SRobert Mustacchi continue;
666*d573a566SRobert Mustacchi }
667*d573a566SRobert Mustacchi
668*d573a566SRobert Mustacchi *c = '\0';
669*d573a566SRobert Mustacchi c = strchr(name, '_');
670*d573a566SRobert Mustacchi if (c == NULL) {
671*d573a566SRobert Mustacchi free(name);
672*d573a566SRobert Mustacchi continue;
673*d573a566SRobert Mustacchi }
674*d573a566SRobert Mustacchi *c = '\0';
675*d573a566SRobert Mustacchi c++;
676*d573a566SRobert Mustacchi if (strcmp(c, "core") != 0) {
677*d573a566SRobert Mustacchi errx(EXIT_FAILURE, "unexpected AMD JSON file name: %s",
678*d573a566SRobert Mustacchi d->d_name);
679*d573a566SRobert Mustacchi }
680*d573a566SRobert Mustacchi
681*d573a566SRobert Mustacchi if (platform != NULL && strcmp(platform, name) != 0) {
682*d573a566SRobert Mustacchi free(name);
683*d573a566SRobert Mustacchi continue;
684*d573a566SRobert Mustacchi }
685*d573a566SRobert Mustacchi
686*d573a566SRobert Mustacchi if ((map = calloc(1, sizeof (cpc_map_t))) == NULL) {
687*d573a566SRobert Mustacchi err(EXIT_FAILURE, "failed to allocate space for cpc "
688*d573a566SRobert Mustacchi "file");
689*d573a566SRobert Mustacchi }
690*d573a566SRobert Mustacchi
691*d573a566SRobert Mustacchi parsed = cpcgen_read_datafile(datadir, d->d_name);
692*d573a566SRobert Mustacchi if ((map->cmap_path = strdup(d->d_name)) == NULL) {
693*d573a566SRobert Mustacchi err(EXIT_FAILURE, "failed to duplicate path string");
694*d573a566SRobert Mustacchi }
695*d573a566SRobert Mustacchi map->cmap_type = CPC_FILE_CORE;
696*d573a566SRobert Mustacchi map->cmap_data = parsed;
697*d573a566SRobert Mustacchi map->cmap_name = name;
698*d573a566SRobert Mustacchi map->cmap_procs = NULL;
699*d573a566SRobert Mustacchi
700*d573a566SRobert Mustacchi map->cmap_next = cpcgen_maps;
701*d573a566SRobert Mustacchi cpcgen_maps = map;
702*d573a566SRobert Mustacchi }
703*d573a566SRobert Mustacchi }
704*d573a566SRobert Mustacchi
705*d573a566SRobert Mustacchi /*
70612ae924aSRobert Mustacchi * Read in the mapfile.csv that is used to map between processor families and
70712ae924aSRobert Mustacchi * parse this. Each line has a comma separated value.
70812ae924aSRobert Mustacchi */
70912ae924aSRobert Mustacchi static void
cpcgen_read_intel(const char * datadir,const char * platform)710*d573a566SRobert Mustacchi cpcgen_read_intel(const char *datadir, const char *platform)
71112ae924aSRobert Mustacchi {
71212ae924aSRobert Mustacchi FILE *map;
71312ae924aSRobert Mustacchi char *mappath, *last;
71412ae924aSRobert Mustacchi char *data = NULL;
71512ae924aSRobert Mustacchi size_t datalen = 0;
71612ae924aSRobert Mustacchi uint_t lineno;
71712ae924aSRobert Mustacchi
718*d573a566SRobert Mustacchi if (asprintf(&mappath, "%s/%s", datadir, cpcgen_intel_mapfile) == -1) {
71912ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to construct path to mapfile");
72012ae924aSRobert Mustacchi }
72112ae924aSRobert Mustacchi
72212ae924aSRobert Mustacchi if ((map = fopen(mappath, "r")) == NULL) {
72312ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to open data mapfile %s", mappath);
72412ae924aSRobert Mustacchi }
72512ae924aSRobert Mustacchi
72612ae924aSRobert Mustacchi lineno = 0;
72712ae924aSRobert Mustacchi while (getline(&data, &datalen, map) != -1) {
72812ae924aSRobert Mustacchi char *fstr, *path, *tstr;
72912ae924aSRobert Mustacchi const char *name;
730fea24e13SRobert Mustacchi uint_t family, model, nsteps;
731fea24e13SRobert Mustacchi uint_t steppings[CPROC_MAX_STEPPINGS];
732fea24e13SRobert Mustacchi
73312ae924aSRobert Mustacchi cpc_type_t type;
73412ae924aSRobert Mustacchi cpc_map_t *map;
73512ae924aSRobert Mustacchi cpc_proc_t *proc;
73612ae924aSRobert Mustacchi
73712ae924aSRobert Mustacchi /*
73812ae924aSRobert Mustacchi * The first line contains the header:
73912ae924aSRobert Mustacchi * Family-model,Version,Filename,EventType
74012ae924aSRobert Mustacchi */
74112ae924aSRobert Mustacchi lineno++;
74212ae924aSRobert Mustacchi if (lineno == 1) {
74312ae924aSRobert Mustacchi continue;
74412ae924aSRobert Mustacchi }
74512ae924aSRobert Mustacchi
74612ae924aSRobert Mustacchi if ((fstr = strtok_r(data, ",", &last)) == NULL ||
74712ae924aSRobert Mustacchi strtok_r(NULL, ",", &last) == NULL ||
74812ae924aSRobert Mustacchi (path = strtok_r(NULL, ",", &last)) == NULL ||
74912ae924aSRobert Mustacchi (tstr = strtok_r(NULL, "\n", &last)) == NULL) {
75012ae924aSRobert Mustacchi errx(EXIT_FAILURE, "failed to parse mapfile line "
75112ae924aSRobert Mustacchi "%u in %s", lineno, mappath);
75212ae924aSRobert Mustacchi }
75312ae924aSRobert Mustacchi
754fea24e13SRobert Mustacchi cpcgen_parse_model(fstr, &family, &model, &nsteps, steppings);
75512ae924aSRobert Mustacchi
75612ae924aSRobert Mustacchi if (strcmp(tstr, "core") == 0) {
75712ae924aSRobert Mustacchi type = CPC_FILE_CORE;
75812ae924aSRobert Mustacchi } else if (strcmp(tstr, "offcore") == 0) {
75912ae924aSRobert Mustacchi type = CPC_FILE_OFF_CORE;
76012ae924aSRobert Mustacchi } else if (strcmp(tstr, "uncore") == 0) {
76112ae924aSRobert Mustacchi type = CPC_FILE_UNCORE;
76212ae924aSRobert Mustacchi } else if (strcmp(tstr, "fp_arith_inst") == 0) {
76312ae924aSRobert Mustacchi type = CPC_FILE_FP_MATH;
76412ae924aSRobert Mustacchi } else if (strcmp(tstr, "uncore experimental") == 0) {
76512ae924aSRobert Mustacchi type = CPC_FILE_UNCORE_EXP;
76612ae924aSRobert Mustacchi } else {
76712ae924aSRobert Mustacchi errx(EXIT_FAILURE, "unknown file type \"%s\" on line "
76812ae924aSRobert Mustacchi "%u", tstr, lineno);
76912ae924aSRobert Mustacchi }
77012ae924aSRobert Mustacchi
77112ae924aSRobert Mustacchi if ((name = cpcgen_use_arch(path, type, platform)) == NULL)
77212ae924aSRobert Mustacchi continue;
77312ae924aSRobert Mustacchi
77412ae924aSRobert Mustacchi if ((map = cpcgen_map_lookup(path)) == NULL) {
77512ae924aSRobert Mustacchi nvlist_t *parsed;
77612ae924aSRobert Mustacchi
77712ae924aSRobert Mustacchi parsed = cpcgen_read_datafile(datadir, path);
77812ae924aSRobert Mustacchi
77912ae924aSRobert Mustacchi if ((map = calloc(1, sizeof (cpc_map_t))) == NULL) {
78012ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to allocate space "
78112ae924aSRobert Mustacchi "for cpc file");
78212ae924aSRobert Mustacchi }
78312ae924aSRobert Mustacchi
78412ae924aSRobert Mustacchi if ((map->cmap_path = strdup(path)) == NULL) {
78512ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to duplicate path "
78612ae924aSRobert Mustacchi "string");
78712ae924aSRobert Mustacchi }
78812ae924aSRobert Mustacchi
78912ae924aSRobert Mustacchi map->cmap_type = type;
79012ae924aSRobert Mustacchi map->cmap_data = parsed;
79112ae924aSRobert Mustacchi map->cmap_name = name;
792fea24e13SRobert Mustacchi map->cmap_procs = NULL;
793*d573a566SRobert Mustacchi
794*d573a566SRobert Mustacchi map->cmap_next = cpcgen_maps;
79512ae924aSRobert Mustacchi cpcgen_maps = map;
79612ae924aSRobert Mustacchi }
79712ae924aSRobert Mustacchi
798fea24e13SRobert Mustacchi if ((proc = calloc(1, sizeof (cpc_proc_t))) == NULL) {
79912ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to allocate memory for "
80012ae924aSRobert Mustacchi "family and model tracking");
80112ae924aSRobert Mustacchi }
80212ae924aSRobert Mustacchi
80312ae924aSRobert Mustacchi proc->cproc_family = family;
80412ae924aSRobert Mustacchi proc->cproc_model = model;
805fea24e13SRobert Mustacchi proc->cproc_nsteps = nsteps;
806fea24e13SRobert Mustacchi if (nsteps > 0) {
807fea24e13SRobert Mustacchi bcopy(steppings, proc->cproc_steppings,
808fea24e13SRobert Mustacchi sizeof (steppings));
809fea24e13SRobert Mustacchi }
81012ae924aSRobert Mustacchi proc->cproc_next = map->cmap_procs;
81112ae924aSRobert Mustacchi map->cmap_procs = proc;
81212ae924aSRobert Mustacchi }
81312ae924aSRobert Mustacchi
81412ae924aSRobert Mustacchi if (errno != 0 || ferror(map)) {
81512ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to read %s", mappath);
81612ae924aSRobert Mustacchi }
81712ae924aSRobert Mustacchi
81812ae924aSRobert Mustacchi if (fclose(map) == EOF) {
81912ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to close %s", mappath);
82012ae924aSRobert Mustacchi }
82112ae924aSRobert Mustacchi free(data);
82212ae924aSRobert Mustacchi free(mappath);
82312ae924aSRobert Mustacchi }
82412ae924aSRobert Mustacchi
82512ae924aSRobert Mustacchi static char *
cpcgen_manual_intel_name(cpc_map_t * map)826*d573a566SRobert Mustacchi cpcgen_manual_intel_name(cpc_map_t *map)
82712ae924aSRobert Mustacchi {
82812ae924aSRobert Mustacchi char *name;
82912ae924aSRobert Mustacchi
83012ae924aSRobert Mustacchi if (asprintf(&name, "%s_events.3cpc", map->cmap_name) == -1) {
83112ae924aSRobert Mustacchi warn("failed to assemble manual page name for %s",
83212ae924aSRobert Mustacchi map->cmap_path);
83312ae924aSRobert Mustacchi return (NULL);
83412ae924aSRobert Mustacchi }
83512ae924aSRobert Mustacchi
83612ae924aSRobert Mustacchi return (name);
83712ae924aSRobert Mustacchi }
83812ae924aSRobert Mustacchi
83912ae924aSRobert Mustacchi static boolean_t
cpcgen_manual_intel_file_before(FILE * f,cpc_map_t * map)840*d573a566SRobert Mustacchi cpcgen_manual_intel_file_before(FILE *f, cpc_map_t *map)
84112ae924aSRobert Mustacchi {
84212ae924aSRobert Mustacchi size_t i;
84312ae924aSRobert Mustacchi char *upper;
84412ae924aSRobert Mustacchi cpc_proc_t *proc;
84512ae924aSRobert Mustacchi
84612ae924aSRobert Mustacchi if ((upper = strdup(map->cmap_name)) == NULL) {
84712ae924aSRobert Mustacchi warn("failed to duplicate manual name for %s", map->cmap_name);
84812ae924aSRobert Mustacchi return (B_FALSE);
84912ae924aSRobert Mustacchi }
85012ae924aSRobert Mustacchi
85112ae924aSRobert Mustacchi for (i = 0; upper[i] != '\0'; i++) {
85212ae924aSRobert Mustacchi upper[i] = toupper(upper[i]);
85312ae924aSRobert Mustacchi }
85412ae924aSRobert Mustacchi
855*d573a566SRobert Mustacchi if (fprintf(f, cpcgen_manual_intel_intel_header, map->cmap_path, upper,
85612ae924aSRobert Mustacchi map->cmap_name) == -1) {
85712ae924aSRobert Mustacchi warn("failed to write out manual header for %s",
85812ae924aSRobert Mustacchi map->cmap_name);
85912ae924aSRobert Mustacchi free(upper);
86012ae924aSRobert Mustacchi return (B_FALSE);
86112ae924aSRobert Mustacchi }
862*d573a566SRobert Mustacchi free(upper);
86312ae924aSRobert Mustacchi
86412ae924aSRobert Mustacchi for (proc = map->cmap_procs; proc != NULL; proc = proc->cproc_next) {
865fea24e13SRobert Mustacchi if (proc->cproc_nsteps > 0) {
866fea24e13SRobert Mustacchi uint_t step;
867fea24e13SRobert Mustacchi
868fea24e13SRobert Mustacchi for (step = 0; step < proc->cproc_nsteps; step++) {
869fea24e13SRobert Mustacchi if (fprintf(f, ".It\n.Sy Family 0x%x, Model "
870fea24e13SRobert Mustacchi "0x%x, Stepping 0x%x\n",
871fea24e13SRobert Mustacchi proc->cproc_family, proc->cproc_model,
872fea24e13SRobert Mustacchi proc->cproc_steppings[step]) == -1) {
873fea24e13SRobert Mustacchi warn("failed to write out model "
874fea24e13SRobert Mustacchi "information for %s",
87512ae924aSRobert Mustacchi map->cmap_name);
87612ae924aSRobert Mustacchi return (B_FALSE);
87712ae924aSRobert Mustacchi }
87812ae924aSRobert Mustacchi }
879fea24e13SRobert Mustacchi } else {
880fea24e13SRobert Mustacchi if (fprintf(f, ".It\n.Sy Family 0x%x, Model 0x%x\n",
881fea24e13SRobert Mustacchi proc->cproc_family, proc->cproc_model) == -1) {
882fea24e13SRobert Mustacchi warn("failed to write out model information "
883fea24e13SRobert Mustacchi "for %s", map->cmap_name);
884fea24e13SRobert Mustacchi return (B_FALSE);
885fea24e13SRobert Mustacchi }
886fea24e13SRobert Mustacchi }
887fea24e13SRobert Mustacchi }
88812ae924aSRobert Mustacchi
889*d573a566SRobert Mustacchi if (fprintf(f, cpcgen_manual_intel_data) == -1) {
89012ae924aSRobert Mustacchi warn("failed to write out manual header for %s",
89112ae924aSRobert Mustacchi map->cmap_name);
89212ae924aSRobert Mustacchi return (B_FALSE);
89312ae924aSRobert Mustacchi }
89412ae924aSRobert Mustacchi
89512ae924aSRobert Mustacchi free(upper);
89612ae924aSRobert Mustacchi return (B_TRUE);
89712ae924aSRobert Mustacchi }
89812ae924aSRobert Mustacchi
89912ae924aSRobert Mustacchi static boolean_t
cpcgen_manual_intel_file_after(FILE * f,cpc_map_t * map)900*d573a566SRobert Mustacchi cpcgen_manual_intel_file_after(FILE *f, cpc_map_t *map)
90112ae924aSRobert Mustacchi {
902*d573a566SRobert Mustacchi if (fprintf(f, cpcgen_manual_intel_trailer) == -1) {
90312ae924aSRobert Mustacchi warn("failed to write out manual header for %s",
90412ae924aSRobert Mustacchi map->cmap_name);
90512ae924aSRobert Mustacchi return (B_FALSE);
90612ae924aSRobert Mustacchi }
90712ae924aSRobert Mustacchi
90812ae924aSRobert Mustacchi return (B_TRUE);
90912ae924aSRobert Mustacchi }
91012ae924aSRobert Mustacchi
91112ae924aSRobert Mustacchi static boolean_t
cpcgen_manual_intel_event(FILE * f,nvlist_t * nvl,const char * path,uint32_t ent)912*d573a566SRobert Mustacchi cpcgen_manual_intel_event(FILE *f, nvlist_t *nvl, const char *path,
913*d573a566SRobert Mustacchi uint32_t ent)
91412ae924aSRobert Mustacchi {
91512ae924aSRobert Mustacchi char *event, *lname, *brief = NULL, *public = NULL, *errata = NULL;
91612ae924aSRobert Mustacchi size_t i;
91712ae924aSRobert Mustacchi
91812ae924aSRobert Mustacchi if (nvlist_lookup_string(nvl, "EventName", &event) != 0) {
91912ae924aSRobert Mustacchi warnx("Found event without 'EventName' property "
92012ae924aSRobert Mustacchi "in %s, entry %u", path, ent);
92112ae924aSRobert Mustacchi return (B_FALSE);
92212ae924aSRobert Mustacchi }
92312ae924aSRobert Mustacchi
92412ae924aSRobert Mustacchi /*
92512ae924aSRobert Mustacchi * Intel uses capital names. CPC historically uses lower case names.
92612ae924aSRobert Mustacchi */
92712ae924aSRobert Mustacchi if ((lname = strdup(event)) == NULL) {
92812ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to duplicate event name %s", event);
92912ae924aSRobert Mustacchi }
93012ae924aSRobert Mustacchi for (i = 0; lname[i] != '\0'; i++) {
93112ae924aSRobert Mustacchi lname[i] = tolower(event[i]);
93212ae924aSRobert Mustacchi }
93312ae924aSRobert Mustacchi
93412ae924aSRobert Mustacchi /*
93512ae924aSRobert Mustacchi * Try to get the other event fields, but if they're not there, don't
93612ae924aSRobert Mustacchi * worry about it.
93712ae924aSRobert Mustacchi */
93812ae924aSRobert Mustacchi (void) nvlist_lookup_string(nvl, "BriefDescription", &brief);
93912ae924aSRobert Mustacchi (void) nvlist_lookup_string(nvl, "PublicDescription", &public);
94012ae924aSRobert Mustacchi (void) nvlist_lookup_string(nvl, "Errata", &errata);
94112ae924aSRobert Mustacchi if (errata != NULL && (strcmp(errata, "0") == 0 ||
94212ae924aSRobert Mustacchi strcmp(errata, "null") == 0)) {
94312ae924aSRobert Mustacchi errata = NULL;
94412ae924aSRobert Mustacchi }
94512ae924aSRobert Mustacchi
94612ae924aSRobert Mustacchi if (fprintf(f, ".It Sy %s\n", lname) == -1) {
947*d573a566SRobert Mustacchi warn("failed to write out event entry %s", event);
94812ae924aSRobert Mustacchi free(lname);
94912ae924aSRobert Mustacchi return (B_FALSE);
95012ae924aSRobert Mustacchi }
95112ae924aSRobert Mustacchi
95212ae924aSRobert Mustacchi if (public != NULL) {
95312ae924aSRobert Mustacchi if (fprintf(f, "%s\n", public) == -1) {
954*d573a566SRobert Mustacchi warn("failed to write out event entry %s", event);
95512ae924aSRobert Mustacchi free(lname);
95612ae924aSRobert Mustacchi return (B_FALSE);
95712ae924aSRobert Mustacchi }
95812ae924aSRobert Mustacchi } else if (brief != NULL) {
95912ae924aSRobert Mustacchi if (fprintf(f, "%s\n", brief) == -1) {
960*d573a566SRobert Mustacchi warn("failed to write out event entry %s", event);
96112ae924aSRobert Mustacchi free(lname);
96212ae924aSRobert Mustacchi return (B_FALSE);
96312ae924aSRobert Mustacchi }
96412ae924aSRobert Mustacchi }
96512ae924aSRobert Mustacchi
96612ae924aSRobert Mustacchi if (errata != NULL) {
96712ae924aSRobert Mustacchi if (fprintf(f, ".Pp\nThe following errata may apply to this: "
96812ae924aSRobert Mustacchi "%s\n", errata) == -1) {
96912ae924aSRobert Mustacchi
970*d573a566SRobert Mustacchi warn("failed to write out event entry %s", event);
97112ae924aSRobert Mustacchi free(lname);
97212ae924aSRobert Mustacchi return (B_FALSE);
97312ae924aSRobert Mustacchi }
97412ae924aSRobert Mustacchi }
97512ae924aSRobert Mustacchi
97612ae924aSRobert Mustacchi free(lname);
97712ae924aSRobert Mustacchi return (B_TRUE);
97812ae924aSRobert Mustacchi }
97912ae924aSRobert Mustacchi
98012ae924aSRobert Mustacchi static char *
cpcgen_cfile_intel_name(cpc_map_t * map)981*d573a566SRobert Mustacchi cpcgen_cfile_intel_name(cpc_map_t *map)
98212ae924aSRobert Mustacchi {
98312ae924aSRobert Mustacchi char *name;
98412ae924aSRobert Mustacchi
98512ae924aSRobert Mustacchi if (asprintf(&name, "core_pcbe_%s.c", map->cmap_name) == -1) {
98612ae924aSRobert Mustacchi warn("failed to assemble file name for %s", map->cmap_path);
98712ae924aSRobert Mustacchi return (NULL);
98812ae924aSRobert Mustacchi }
98912ae924aSRobert Mustacchi
99012ae924aSRobert Mustacchi return (name);
99112ae924aSRobert Mustacchi }
99212ae924aSRobert Mustacchi
99312ae924aSRobert Mustacchi static boolean_t
cpcgen_cfile_intel_before(FILE * f,cpc_map_t * map)994*d573a566SRobert Mustacchi cpcgen_cfile_intel_before(FILE *f, cpc_map_t *map)
99512ae924aSRobert Mustacchi {
996*d573a566SRobert Mustacchi if (fprintf(f, cpcgen_cfile_intel_header, map->cmap_path) == -1) {
99712ae924aSRobert Mustacchi warn("failed to write header to temporary file for %s",
99812ae924aSRobert Mustacchi map->cmap_path);
99912ae924aSRobert Mustacchi return (B_FALSE);
100012ae924aSRobert Mustacchi }
100112ae924aSRobert Mustacchi
1002*d573a566SRobert Mustacchi if (fprintf(f, cpcgen_cfile_intel_table_start, map->cmap_name) == -1) {
100312ae924aSRobert Mustacchi warn("failed to write header to temporary file for %s",
100412ae924aSRobert Mustacchi map->cmap_path);
100512ae924aSRobert Mustacchi return (B_FALSE);
100612ae924aSRobert Mustacchi }
100712ae924aSRobert Mustacchi
100812ae924aSRobert Mustacchi return (B_TRUE);
100912ae924aSRobert Mustacchi }
101012ae924aSRobert Mustacchi
101112ae924aSRobert Mustacchi static boolean_t
cpcgen_cfile_intel_after(FILE * f,cpc_map_t * map)1012*d573a566SRobert Mustacchi cpcgen_cfile_intel_after(FILE *f, cpc_map_t *map)
101312ae924aSRobert Mustacchi {
1014*d573a566SRobert Mustacchi if (fprintf(f, cpcgen_cfile_intel_table_end) == -1) {
101512ae924aSRobert Mustacchi warn("failed to write footer to temporary file for %s",
101612ae924aSRobert Mustacchi map->cmap_path);
101712ae924aSRobert Mustacchi return (B_FALSE);
101812ae924aSRobert Mustacchi }
101912ae924aSRobert Mustacchi
102012ae924aSRobert Mustacchi return (B_TRUE);
102112ae924aSRobert Mustacchi }
102212ae924aSRobert Mustacchi
102312ae924aSRobert Mustacchi static boolean_t
cpcgen_cfile_intel_event(FILE * f,nvlist_t * nvl,const char * path,uint_t ent)1024*d573a566SRobert Mustacchi cpcgen_cfile_intel_event(FILE *f, nvlist_t *nvl, const char *path, uint_t ent)
102512ae924aSRobert Mustacchi {
102612ae924aSRobert Mustacchi char *ecode, *umask, *name, *counter, *lname, *cmask;
102712ae924aSRobert Mustacchi size_t i;
102812ae924aSRobert Mustacchi
102912ae924aSRobert Mustacchi if (nvlist_lookup_string(nvl, "EventName", &name) != 0) {
103012ae924aSRobert Mustacchi warnx("Found event without 'EventName' property "
103112ae924aSRobert Mustacchi "in %s, entry %u", path, ent);
103212ae924aSRobert Mustacchi return (B_FALSE);
103312ae924aSRobert Mustacchi }
103412ae924aSRobert Mustacchi
103512ae924aSRobert Mustacchi if (nvlist_lookup_string(nvl, "EventCode", &ecode) != 0 ||
103612ae924aSRobert Mustacchi nvlist_lookup_string(nvl, "UMask", &umask) != 0 ||
103712ae924aSRobert Mustacchi nvlist_lookup_string(nvl, "Counter", &counter) != 0) {
103812ae924aSRobert Mustacchi warnx("event %s (index %u) from %s, missing "
103912ae924aSRobert Mustacchi "required properties for C file translation",
104012ae924aSRobert Mustacchi name, ent, path);
104112ae924aSRobert Mustacchi return (B_FALSE);
104212ae924aSRobert Mustacchi }
104312ae924aSRobert Mustacchi
104412ae924aSRobert Mustacchi /*
104512ae924aSRobert Mustacchi * While we could try and parse the counters manually, just do this the
104612ae924aSRobert Mustacchi * max power way for now based on all possible values.
104712ae924aSRobert Mustacchi */
104812ae924aSRobert Mustacchi if (strcmp(counter, "0") == 0 || strcmp(counter, "0,") == 0) {
104912ae924aSRobert Mustacchi cmask = "C0";
105012ae924aSRobert Mustacchi } else if (strcmp(counter, "1") == 0) {
105112ae924aSRobert Mustacchi cmask = "C1";
105212ae924aSRobert Mustacchi } else if (strcmp(counter, "2") == 0) {
105312ae924aSRobert Mustacchi cmask = "C2";
105412ae924aSRobert Mustacchi } else if (strcmp(counter, "3") == 0) {
105512ae924aSRobert Mustacchi cmask = "C3";
105612ae924aSRobert Mustacchi } else if (strcmp(counter, "0,1") == 0) {
105712ae924aSRobert Mustacchi cmask = "C0|C1";
105812ae924aSRobert Mustacchi } else if (strcmp(counter, "0,1,2") == 0) {
105912ae924aSRobert Mustacchi cmask = "C0|C1|C2";
106012ae924aSRobert Mustacchi } else if (strcmp(counter, "0,1,2,3") == 0) {
106112ae924aSRobert Mustacchi cmask = "C0|C1|C2|C3";
106212ae924aSRobert Mustacchi } else if (strcmp(counter, "0,2,3") == 0) {
106312ae924aSRobert Mustacchi cmask = "C0|C2|C3";
106412ae924aSRobert Mustacchi } else if (strcmp(counter, "1,2,3") == 0) {
106512ae924aSRobert Mustacchi cmask = "C1|C2|C3";
106612ae924aSRobert Mustacchi } else if (strcmp(counter, "2,3") == 0) {
106712ae924aSRobert Mustacchi cmask = "C2|C3";
106812ae924aSRobert Mustacchi } else {
106912ae924aSRobert Mustacchi warnx("event %s (index %u) from %s, has unknown "
107012ae924aSRobert Mustacchi "counter value \"%s\"", name, ent, path, counter);
107112ae924aSRobert Mustacchi return (B_FALSE);
107212ae924aSRobert Mustacchi }
107312ae924aSRobert Mustacchi
107412ae924aSRobert Mustacchi
107512ae924aSRobert Mustacchi /*
107612ae924aSRobert Mustacchi * Intel uses capital names. CPC historically uses lower case names.
107712ae924aSRobert Mustacchi */
107812ae924aSRobert Mustacchi if ((lname = strdup(name)) == NULL) {
107912ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to duplicate event name %s", name);
108012ae924aSRobert Mustacchi }
108112ae924aSRobert Mustacchi for (i = 0; lname[i] != '\0'; i++) {
108212ae924aSRobert Mustacchi lname[i] = tolower(name[i]);
108312ae924aSRobert Mustacchi }
108412ae924aSRobert Mustacchi
108512ae924aSRobert Mustacchi if (fprintf(f, "\t{ %s, %s, %s, \"%s\" },\n", ecode, umask, cmask,
108612ae924aSRobert Mustacchi lname) == -1) {
108712ae924aSRobert Mustacchi warn("failed to write out entry %s from %s", name, path);
108812ae924aSRobert Mustacchi free(lname);
108912ae924aSRobert Mustacchi return (B_FALSE);
109012ae924aSRobert Mustacchi }
109112ae924aSRobert Mustacchi
109212ae924aSRobert Mustacchi free(lname);
109312ae924aSRobert Mustacchi
109412ae924aSRobert Mustacchi /*
109512ae924aSRobert Mustacchi * Check if we have any PAPI aliases.
109612ae924aSRobert Mustacchi */
1097*d573a566SRobert Mustacchi for (i = 0; cpcgen_intel_papi_map[i].cpapi_intc != NULL; i++) {
1098*d573a566SRobert Mustacchi if (strcmp(name, cpcgen_intel_papi_map[i].cpapi_intc) != 0)
109912ae924aSRobert Mustacchi continue;
110012ae924aSRobert Mustacchi
110112ae924aSRobert Mustacchi if (fprintf(f, "\t{ %s, %s, %s, \"%s\" },\n", ecode, umask,
1102*d573a566SRobert Mustacchi cmask, cpcgen_intel_papi_map[i].cpapi_papi) == -1) {
110312ae924aSRobert Mustacchi warn("failed to write out entry %s from %s", name,
110412ae924aSRobert Mustacchi path);
110512ae924aSRobert Mustacchi return (B_FALSE);
110612ae924aSRobert Mustacchi }
110712ae924aSRobert Mustacchi }
110812ae924aSRobert Mustacchi
110912ae924aSRobert Mustacchi return (B_TRUE);
111012ae924aSRobert Mustacchi }
111112ae924aSRobert Mustacchi
1112fea24e13SRobert Mustacchi static boolean_t
cpcgen_generate_map(FILE * f,cpc_map_t * map,boolean_t start)1113fea24e13SRobert Mustacchi cpcgen_generate_map(FILE *f, cpc_map_t *map, boolean_t start)
1114fea24e13SRobert Mustacchi {
1115fea24e13SRobert Mustacchi cpc_proc_t *p;
1116fea24e13SRobert Mustacchi
1117fea24e13SRobert Mustacchi if (fprintf(f, "\t%sif (", start ? "" : "} else ") == -1) {
1118fea24e13SRobert Mustacchi return (B_FALSE);
1119fea24e13SRobert Mustacchi }
1120fea24e13SRobert Mustacchi
1121fea24e13SRobert Mustacchi for (p = map->cmap_procs; p != NULL; p = p->cproc_next) {
1122fea24e13SRobert Mustacchi /*
1123fea24e13SRobert Mustacchi * Make sure the line is padded so the generated C code looks
1124fea24e13SRobert Mustacchi * like reasonable C style.
1125fea24e13SRobert Mustacchi */
1126fea24e13SRobert Mustacchi if (p != map->cmap_procs) {
1127fea24e13SRobert Mustacchi if (fputs("\t ", f) == -1) {
1128fea24e13SRobert Mustacchi return (B_FALSE);
1129fea24e13SRobert Mustacchi }
1130fea24e13SRobert Mustacchi }
1131fea24e13SRobert Mustacchi
1132fea24e13SRobert Mustacchi if (p->cproc_nsteps > 0) {
1133fea24e13SRobert Mustacchi uint_t i;
1134fea24e13SRobert Mustacchi
1135fea24e13SRobert Mustacchi if (fprintf(f, "(model == 0x%x &&\n\t (",
1136fea24e13SRobert Mustacchi p->cproc_model) == -1) {
1137fea24e13SRobert Mustacchi return (B_FALSE);
1138fea24e13SRobert Mustacchi }
1139fea24e13SRobert Mustacchi
1140fea24e13SRobert Mustacchi for (i = 0; i < p->cproc_nsteps; i++) {
1141fea24e13SRobert Mustacchi if (fprintf(f, "stepping == 0x%x%s",
1142fea24e13SRobert Mustacchi p->cproc_steppings[i],
1143fea24e13SRobert Mustacchi i + 1 != p->cproc_nsteps ?
1144fea24e13SRobert Mustacchi " ||\n\t " : "") == -1) {
1145fea24e13SRobert Mustacchi return (B_FALSE);
1146fea24e13SRobert Mustacchi }
1147fea24e13SRobert Mustacchi }
1148fea24e13SRobert Mustacchi
1149fea24e13SRobert Mustacchi if (fputs("))", f) == -1) {
1150fea24e13SRobert Mustacchi return (B_FALSE);
1151fea24e13SRobert Mustacchi }
1152fea24e13SRobert Mustacchi } else if (fprintf(f, "model == 0x%x", p->cproc_model) == -1) {
1153fea24e13SRobert Mustacchi return (B_FALSE);
1154fea24e13SRobert Mustacchi }
1155fea24e13SRobert Mustacchi
1156fea24e13SRobert Mustacchi if (fprintf(f, "%s\n",
1157fea24e13SRobert Mustacchi p->cproc_next != NULL ? " ||" : ") {") == -1) {
1158fea24e13SRobert Mustacchi return (B_FALSE);
1159fea24e13SRobert Mustacchi }
1160fea24e13SRobert Mustacchi }
1161fea24e13SRobert Mustacchi
1162fea24e13SRobert Mustacchi if (fprintf(f, "\t\t\treturn (pcbe_core_events_%s);\n",
1163fea24e13SRobert Mustacchi map->cmap_name) == -1) {
1164fea24e13SRobert Mustacchi return (B_FALSE);
1165fea24e13SRobert Mustacchi }
1166fea24e13SRobert Mustacchi
1167fea24e13SRobert Mustacchi return (B_TRUE);
1168fea24e13SRobert Mustacchi }
1169fea24e13SRobert Mustacchi
117012ae924aSRobert Mustacchi /*
1171*d573a566SRobert Mustacchi * This is a wrapper around unlinkat that makes sure that we don't clobber
1172*d573a566SRobert Mustacchi * errno, which is used for properly printing out error messages below.
1173*d573a566SRobert Mustacchi */
1174*d573a566SRobert Mustacchi static void
cpcgen_remove_tmpfile(int dirfd,const char * path)1175*d573a566SRobert Mustacchi cpcgen_remove_tmpfile(int dirfd, const char *path)
1176*d573a566SRobert Mustacchi {
1177*d573a566SRobert Mustacchi int e = errno;
1178*d573a566SRobert Mustacchi (void) unlinkat(dirfd, path, 0);
1179*d573a566SRobert Mustacchi errno = e;
1180*d573a566SRobert Mustacchi }
1181*d573a566SRobert Mustacchi
1182*d573a566SRobert Mustacchi /*
118312ae924aSRobert Mustacchi * Generate a header file that declares all of these arrays and provide a map
118412ae924aSRobert Mustacchi * for models to the corresponding table to use.
118512ae924aSRobert Mustacchi */
118612ae924aSRobert Mustacchi static void
cpcgen_common_intel_files(int dirfd)1187*d573a566SRobert Mustacchi cpcgen_common_intel_files(int dirfd)
118812ae924aSRobert Mustacchi {
118912ae924aSRobert Mustacchi const char *fname = "core_pcbe_cpcgen.h";
119012ae924aSRobert Mustacchi char *tmpname;
119112ae924aSRobert Mustacchi int fd;
119212ae924aSRobert Mustacchi FILE *f;
119312ae924aSRobert Mustacchi cpc_map_t *map;
119412ae924aSRobert Mustacchi
119512ae924aSRobert Mustacchi if (asprintf(&tmpname, ".%s.%d", fname, getpid()) == -1) {
119612ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to construct temporary file name");
119712ae924aSRobert Mustacchi }
119812ae924aSRobert Mustacchi
119912ae924aSRobert Mustacchi if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0644)) < 0) {
120012ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to create temporary file %s",
120112ae924aSRobert Mustacchi tmpname);
120212ae924aSRobert Mustacchi }
120312ae924aSRobert Mustacchi
120412ae924aSRobert Mustacchi if ((f = fdopen(fd, "w")) == NULL) {
1205*d573a566SRobert Mustacchi cpcgen_remove_tmpfile(dirfd, tmpname);
120612ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to fdopen temporary file");
120712ae924aSRobert Mustacchi }
120812ae924aSRobert Mustacchi
1209*d573a566SRobert Mustacchi if (fprintf(f, cpcgen_cfile_intel_header, cpcgen_intel_mapfile) == -1) {
1210*d573a566SRobert Mustacchi cpcgen_remove_tmpfile(dirfd, tmpname);
121112ae924aSRobert Mustacchi errx(EXIT_FAILURE, "failed to write header to temporary file "
121212ae924aSRobert Mustacchi "for %s", fname);
121312ae924aSRobert Mustacchi }
121412ae924aSRobert Mustacchi
121512ae924aSRobert Mustacchi if (fprintf(f, "#ifndef _CORE_PCBE_CPCGEN_H\n"
121612ae924aSRobert Mustacchi "#define\t_CORE_PCBE_CPCGEN_H\n"
121712ae924aSRobert Mustacchi "\n"
121812ae924aSRobert Mustacchi "#ifdef __cplusplus\n"
121912ae924aSRobert Mustacchi "extern \"C\" {\n"
122012ae924aSRobert Mustacchi "#endif\n"
122112ae924aSRobert Mustacchi "\n"
1222fea24e13SRobert Mustacchi "extern const struct events_table_t *core_cpcgen_table(uint_t, "
1223fea24e13SRobert Mustacchi "uint_t);\n"
122412ae924aSRobert Mustacchi "\n") == -1) {
1225*d573a566SRobert Mustacchi cpcgen_remove_tmpfile(dirfd, tmpname);
122612ae924aSRobert Mustacchi errx(EXIT_FAILURE, "failed to write header to "
122712ae924aSRobert Mustacchi "temporary file for %s", fname);
122812ae924aSRobert Mustacchi }
122912ae924aSRobert Mustacchi
123012ae924aSRobert Mustacchi for (map = cpcgen_maps; map != NULL; map = map->cmap_next) {
123112ae924aSRobert Mustacchi if (fprintf(f, "extern const struct events_table_t "
123212ae924aSRobert Mustacchi "pcbe_core_events_%s[];\n", map->cmap_name) == -1) {
1233*d573a566SRobert Mustacchi cpcgen_remove_tmpfile(dirfd, tmpname);
123412ae924aSRobert Mustacchi errx(EXIT_FAILURE, "failed to write entry to "
123512ae924aSRobert Mustacchi "temporary file for %s", fname);
123612ae924aSRobert Mustacchi }
123712ae924aSRobert Mustacchi }
123812ae924aSRobert Mustacchi
123912ae924aSRobert Mustacchi if (fprintf(f, "\n"
124012ae924aSRobert Mustacchi "#ifdef __cplusplus\n"
124112ae924aSRobert Mustacchi "}\n"
124212ae924aSRobert Mustacchi "#endif\n"
124312ae924aSRobert Mustacchi "\n"
124412ae924aSRobert Mustacchi "#endif /* _CORE_PCBE_CPCGEN_H */\n") == -1) {
1245*d573a566SRobert Mustacchi cpcgen_remove_tmpfile(dirfd, tmpname);
124612ae924aSRobert Mustacchi errx(EXIT_FAILURE, "failed to write header to "
124712ae924aSRobert Mustacchi "temporary file for %s", fname);
124812ae924aSRobert Mustacchi }
124912ae924aSRobert Mustacchi
125012ae924aSRobert Mustacchi if (fflush(f) != 0 || fclose(f) != 0) {
1251*d573a566SRobert Mustacchi cpcgen_remove_tmpfile(dirfd, tmpname);
125212ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to flush and close temporary file");
125312ae924aSRobert Mustacchi }
125412ae924aSRobert Mustacchi
125512ae924aSRobert Mustacchi if (renameat(dirfd, tmpname, dirfd, fname) != 0) {
125612ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to rename temporary file %s",
125712ae924aSRobert Mustacchi tmpname);
125812ae924aSRobert Mustacchi }
125912ae924aSRobert Mustacchi
126012ae924aSRobert Mustacchi free(tmpname);
126112ae924aSRobert Mustacchi
126212ae924aSRobert Mustacchi /* Now again for the .c file. */
126312ae924aSRobert Mustacchi fname = "core_pcbe_cpcgen.c";
126412ae924aSRobert Mustacchi if (asprintf(&tmpname, ".%s.%d", fname, getpid()) == -1) {
126512ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to construct temporary file name");
126612ae924aSRobert Mustacchi }
126712ae924aSRobert Mustacchi
126812ae924aSRobert Mustacchi if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0644)) < 0) {
126912ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to create temporary file %s",
127012ae924aSRobert Mustacchi tmpname);
127112ae924aSRobert Mustacchi }
127212ae924aSRobert Mustacchi
127312ae924aSRobert Mustacchi if ((f = fdopen(fd, "w")) == NULL) {
1274*d573a566SRobert Mustacchi cpcgen_remove_tmpfile(dirfd, tmpname);
127512ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to fdopen temporary file");
127612ae924aSRobert Mustacchi }
127712ae924aSRobert Mustacchi
1278*d573a566SRobert Mustacchi if (fprintf(f, cpcgen_cfile_intel_header, cpcgen_intel_mapfile) == -1) {
1279*d573a566SRobert Mustacchi cpcgen_remove_tmpfile(dirfd, tmpname);
128012ae924aSRobert Mustacchi errx(EXIT_FAILURE, "failed to write header to temporary file "
128112ae924aSRobert Mustacchi "for %s", fname);
128212ae924aSRobert Mustacchi }
128312ae924aSRobert Mustacchi
128412ae924aSRobert Mustacchi if (fprintf(f, "#include <core_pcbe_table.h>\n"
128512ae924aSRobert Mustacchi "#include <sys/null.h>\n"
128612ae924aSRobert Mustacchi "#include \"core_pcbe_cpcgen.h\"\n"
128712ae924aSRobert Mustacchi "\n"
128812ae924aSRobert Mustacchi "const struct events_table_t *\n"
1289fea24e13SRobert Mustacchi "core_cpcgen_table(uint_t model, uint_t stepping)\n"
1290fea24e13SRobert Mustacchi "{\n") == -1) {
1291*d573a566SRobert Mustacchi cpcgen_remove_tmpfile(dirfd, tmpname);
129212ae924aSRobert Mustacchi errx(EXIT_FAILURE, "failed to write header to "
129312ae924aSRobert Mustacchi "temporary file for %s", fname);
129412ae924aSRobert Mustacchi }
129512ae924aSRobert Mustacchi
129612ae924aSRobert Mustacchi for (map = cpcgen_maps; map != NULL; map = map->cmap_next) {
1297fea24e13SRobert Mustacchi if (!cpcgen_generate_map(f, map, map == cpcgen_maps)) {
1298*d573a566SRobert Mustacchi cpcgen_remove_tmpfile(dirfd, tmpname);
1299fea24e13SRobert Mustacchi errx(EXIT_FAILURE, "failed to write to temporary "
1300fea24e13SRobert Mustacchi "file for %s", fname);
130112ae924aSRobert Mustacchi }
130212ae924aSRobert Mustacchi }
130312ae924aSRobert Mustacchi
1304fea24e13SRobert Mustacchi if (fprintf(f, "\t} else {\n"
130512ae924aSRobert Mustacchi "\t\t\treturn (NULL);\n"
130612ae924aSRobert Mustacchi "\t}\n"
130712ae924aSRobert Mustacchi "}\n") == -1) {
1308*d573a566SRobert Mustacchi cpcgen_remove_tmpfile(dirfd, tmpname);
130912ae924aSRobert Mustacchi errx(EXIT_FAILURE, "failed to write header to "
131012ae924aSRobert Mustacchi "temporary file for %s", fname);
131112ae924aSRobert Mustacchi }
131212ae924aSRobert Mustacchi
131312ae924aSRobert Mustacchi if (fflush(f) != 0 || fclose(f) != 0) {
1314*d573a566SRobert Mustacchi cpcgen_remove_tmpfile(dirfd, tmpname);
131512ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to flush and close temporary file");
131612ae924aSRobert Mustacchi }
131712ae924aSRobert Mustacchi
131812ae924aSRobert Mustacchi if (renameat(dirfd, tmpname, dirfd, fname) != 0) {
131912ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to rename temporary file %s",
132012ae924aSRobert Mustacchi tmpname);
132112ae924aSRobert Mustacchi }
132212ae924aSRobert Mustacchi
132312ae924aSRobert Mustacchi free(tmpname);
132412ae924aSRobert Mustacchi }
132512ae924aSRobert Mustacchi
132612ae924aSRobert Mustacchi /*
132712ae924aSRobert Mustacchi * Look at a rule to determine whether or not we should consider including it or
132812ae924aSRobert Mustacchi * not. At this point we've already filtered things such that we only get core
132912ae924aSRobert Mustacchi * events.
133012ae924aSRobert Mustacchi *
133112ae924aSRobert Mustacchi * To consider an entry, we currently apply the following criteria:
133212ae924aSRobert Mustacchi *
133312ae924aSRobert Mustacchi * - The MSRIndex and MSRValue are zero. Programming additional MSRs is no
133412ae924aSRobert Mustacchi * supported right now.
133512ae924aSRobert Mustacchi * - TakenAlone is non-zero, which means that it cannot run at the same time as
133612ae924aSRobert Mustacchi * another field.
133712ae924aSRobert Mustacchi * - Offcore is one, indicating that it is off the core and we need to figure
133812ae924aSRobert Mustacchi * out if we can support this.
133912ae924aSRobert Mustacchi * - If the counter is fixed, don't use it for now.
134012ae924aSRobert Mustacchi * - If more than one value is specified in the EventCode or UMask values
134112ae924aSRobert Mustacchi */
134212ae924aSRobert Mustacchi static boolean_t
cpcgen_skip_intel_entry(nvlist_t * nvl,const char * path,uint_t ent)1343*d573a566SRobert Mustacchi cpcgen_skip_intel_entry(nvlist_t *nvl, const char *path, uint_t ent)
134412ae924aSRobert Mustacchi {
134512ae924aSRobert Mustacchi char *event, *msridx, *msrval, *taken, *offcore, *counter;
134612ae924aSRobert Mustacchi char *ecode, *umask;
134712ae924aSRobert Mustacchi
134812ae924aSRobert Mustacchi /*
134912ae924aSRobert Mustacchi * Require EventName, it's kind of useless without that.
135012ae924aSRobert Mustacchi */
135112ae924aSRobert Mustacchi if (nvlist_lookup_string(nvl, "EventName", &event) != 0) {
135212ae924aSRobert Mustacchi errx(EXIT_FAILURE, "Found event without 'EventName' property "
135312ae924aSRobert Mustacchi "in %s, entry %u", path, ent);
135412ae924aSRobert Mustacchi }
135512ae924aSRobert Mustacchi
135612ae924aSRobert Mustacchi /*
135712ae924aSRobert Mustacchi * If we can't find an expected value, whine about it.
135812ae924aSRobert Mustacchi */
135912ae924aSRobert Mustacchi if (nvlist_lookup_string(nvl, "MSRIndex", &msridx) != 0 ||
136012ae924aSRobert Mustacchi nvlist_lookup_string(nvl, "MSRValue", &msrval) != 0 ||
136112ae924aSRobert Mustacchi nvlist_lookup_string(nvl, "Counter", &counter) != 0 ||
136212ae924aSRobert Mustacchi nvlist_lookup_string(nvl, "EventCode", &ecode) != 0 ||
136312ae924aSRobert Mustacchi nvlist_lookup_string(nvl, "UMask", &umask) != 0 ||
136412ae924aSRobert Mustacchi nvlist_lookup_string(nvl, "Offcore", &offcore) != 0) {
136512ae924aSRobert Mustacchi warnx("Skipping event %s (index %u) from %s, missing required "
136612ae924aSRobert Mustacchi "property", event, ent, path);
136712ae924aSRobert Mustacchi return (B_TRUE);
136812ae924aSRobert Mustacchi }
136912ae924aSRobert Mustacchi
137012ae924aSRobert Mustacchi /*
137112ae924aSRobert Mustacchi * MSRIndex and MSRvalue comes as either "0" or "0x00".
137212ae924aSRobert Mustacchi */
137312ae924aSRobert Mustacchi if ((strcmp(msridx, "0") != 0 && strcmp(msridx, "0x00") != 0) ||
137412ae924aSRobert Mustacchi (strcmp(msrval, "0") != 0 && strcmp(msridx, "0x00") != 0) ||
137512ae924aSRobert Mustacchi strcmp(offcore, "0") != 0 || strchr(ecode, ',') != NULL ||
137612ae924aSRobert Mustacchi strchr(umask, ',') != NULL) {
137712ae924aSRobert Mustacchi return (B_TRUE);
137812ae924aSRobert Mustacchi }
137912ae924aSRobert Mustacchi
138012ae924aSRobert Mustacchi /*
138112ae924aSRobert Mustacchi * Unfortunately, not everything actually has "TakenAlone". If it
138212ae924aSRobert Mustacchi * doesn't, we assume that it doesn't have to be.
138312ae924aSRobert Mustacchi */
138412ae924aSRobert Mustacchi if (nvlist_lookup_string(nvl, "TakenAlone", &taken) == 0 &&
138512ae924aSRobert Mustacchi strcmp(taken, "0") != 0) {
138612ae924aSRobert Mustacchi return (B_TRUE);
138712ae924aSRobert Mustacchi }
138812ae924aSRobert Mustacchi
138912ae924aSRobert Mustacchi
139012ae924aSRobert Mustacchi if (strncasecmp(counter, "fixed", strlen("fixed")) == 0)
139112ae924aSRobert Mustacchi return (B_TRUE);
139212ae924aSRobert Mustacchi
139312ae924aSRobert Mustacchi return (B_FALSE);
139412ae924aSRobert Mustacchi }
1395*d573a566SRobert Mustacchi static char *
cpcgen_manual_amd_name(cpc_map_t * map)1396*d573a566SRobert Mustacchi cpcgen_manual_amd_name(cpc_map_t *map)
1397*d573a566SRobert Mustacchi {
1398*d573a566SRobert Mustacchi char *name;
1399*d573a566SRobert Mustacchi
1400*d573a566SRobert Mustacchi if (asprintf(&name, "amd_%s_events.3cpc", map->cmap_name) == -1) {
1401*d573a566SRobert Mustacchi warn("failed to assemble file name for %s", map->cmap_path);
1402*d573a566SRobert Mustacchi return (NULL);
1403*d573a566SRobert Mustacchi }
1404*d573a566SRobert Mustacchi
1405*d573a566SRobert Mustacchi return (name);
1406*d573a566SRobert Mustacchi }
1407*d573a566SRobert Mustacchi
1408*d573a566SRobert Mustacchi static boolean_t
cpcgen_manual_amd_file_before(FILE * f,cpc_map_t * map)1409*d573a566SRobert Mustacchi cpcgen_manual_amd_file_before(FILE *f, cpc_map_t *map)
1410*d573a566SRobert Mustacchi {
1411*d573a566SRobert Mustacchi size_t i;
1412*d573a566SRobert Mustacchi char *upper;
1413*d573a566SRobert Mustacchi const char *family;
1414*d573a566SRobert Mustacchi
1415*d573a566SRobert Mustacchi if ((upper = strdup(map->cmap_name)) == NULL) {
1416*d573a566SRobert Mustacchi warn("failed to duplicate manual name for %s", map->cmap_name);
1417*d573a566SRobert Mustacchi return (B_FALSE);
1418*d573a566SRobert Mustacchi }
1419*d573a566SRobert Mustacchi
1420*d573a566SRobert Mustacchi for (i = 0; upper[i] != '\0'; i++) {
1421*d573a566SRobert Mustacchi upper[i] = toupper(upper[i]);
1422*d573a566SRobert Mustacchi }
1423*d573a566SRobert Mustacchi
1424*d573a566SRobert Mustacchi family = map->cmap_name + 1;
1425*d573a566SRobert Mustacchi
1426*d573a566SRobert Mustacchi if (fprintf(f, cpcgen_manual_amd_header, map->cmap_path, upper,
1427*d573a566SRobert Mustacchi family, family, family) == -1) {
1428*d573a566SRobert Mustacchi warn("failed to write out manual header for %s",
1429*d573a566SRobert Mustacchi map->cmap_name);
1430*d573a566SRobert Mustacchi free(upper);
1431*d573a566SRobert Mustacchi return (B_FALSE);
1432*d573a566SRobert Mustacchi }
1433*d573a566SRobert Mustacchi
1434*d573a566SRobert Mustacchi free(upper);
1435*d573a566SRobert Mustacchi return (B_TRUE);
1436*d573a566SRobert Mustacchi }
1437*d573a566SRobert Mustacchi
1438*d573a566SRobert Mustacchi static boolean_t
cpcgen_manual_amd_file_after(FILE * f,cpc_map_t * map)1439*d573a566SRobert Mustacchi cpcgen_manual_amd_file_after(FILE *f, cpc_map_t *map)
1440*d573a566SRobert Mustacchi {
1441*d573a566SRobert Mustacchi if (fprintf(f, cpcgen_manual_amd_trailer) == -1) {
1442*d573a566SRobert Mustacchi warn("failed to write out manual header for %s",
1443*d573a566SRobert Mustacchi map->cmap_name);
1444*d573a566SRobert Mustacchi return (B_FALSE);
1445*d573a566SRobert Mustacchi }
1446*d573a566SRobert Mustacchi
1447*d573a566SRobert Mustacchi return (B_TRUE);
1448*d573a566SRobert Mustacchi }
1449*d573a566SRobert Mustacchi
1450*d573a566SRobert Mustacchi static boolean_t
cpcgen_manual_amd_event(FILE * f,nvlist_t * nvl,const char * path,uint32_t ent)1451*d573a566SRobert Mustacchi cpcgen_manual_amd_event(FILE *f, nvlist_t *nvl, const char *path, uint32_t ent)
1452*d573a566SRobert Mustacchi {
1453*d573a566SRobert Mustacchi char *name, *mnemonic = NULL, *summary = NULL, *desc = NULL;
1454*d573a566SRobert Mustacchi char *umode;
1455*d573a566SRobert Mustacchi nvlist_t *units = NULL;
1456*d573a566SRobert Mustacchi uint32_t i, length;
1457*d573a566SRobert Mustacchi
1458*d573a566SRobert Mustacchi if (nvlist_lookup_string(nvl, "name", &name) != 0) {
1459*d573a566SRobert Mustacchi warnx("Found event without 'name' property in %s, entry %u",
1460*d573a566SRobert Mustacchi path, ent);
1461*d573a566SRobert Mustacchi return (B_FALSE);
1462*d573a566SRobert Mustacchi }
1463*d573a566SRobert Mustacchi
1464*d573a566SRobert Mustacchi if (nvlist_lookup_string(nvl, "mnemonic", &mnemonic) != 0 ||
1465*d573a566SRobert Mustacchi nvlist_lookup_string(nvl, "summary", &summary) != 0) {
1466*d573a566SRobert Mustacchi warnx("event %s in %s, entry %u, missing required fields",
1467*d573a566SRobert Mustacchi name, path, ent);
1468*d573a566SRobert Mustacchi return (B_FALSE);
1469*d573a566SRobert Mustacchi }
1470*d573a566SRobert Mustacchi
1471*d573a566SRobert Mustacchi /*
1472*d573a566SRobert Mustacchi * Allow the other fields to be missing.
1473*d573a566SRobert Mustacchi */
1474*d573a566SRobert Mustacchi (void) nvlist_lookup_string(nvl, "description", &desc);
1475*d573a566SRobert Mustacchi (void) nvlist_lookup_nvlist(nvl, "units", &units);
1476*d573a566SRobert Mustacchi
1477*d573a566SRobert Mustacchi if (fprintf(f, ".It Sy %s\n", name) == -1) {
1478*d573a566SRobert Mustacchi warn("failed to write out event entry %s", name);
1479*d573a566SRobert Mustacchi }
1480*d573a566SRobert Mustacchi
1481*d573a566SRobert Mustacchi if (fprintf(f, ".Sy %s -\n"
1482*d573a566SRobert Mustacchi "%s\n", mnemonic, summary) == -1) {
1483*d573a566SRobert Mustacchi warn("failed to write out event entry %s", name);
1484*d573a566SRobert Mustacchi return (B_FALSE);
1485*d573a566SRobert Mustacchi }
1486*d573a566SRobert Mustacchi
1487*d573a566SRobert Mustacchi if (desc != NULL) {
1488*d573a566SRobert Mustacchi if (fprintf(f, ".Pp\n%s\n", desc) == -1) {
1489*d573a566SRobert Mustacchi warn("failed to write out event entry %s", name);
1490*d573a566SRobert Mustacchi return (B_FALSE);
1491*d573a566SRobert Mustacchi }
1492*d573a566SRobert Mustacchi }
1493*d573a566SRobert Mustacchi
1494*d573a566SRobert Mustacchi if (units == NULL)
1495*d573a566SRobert Mustacchi return (B_TRUE);
1496*d573a566SRobert Mustacchi
1497*d573a566SRobert Mustacchi /*
1498*d573a566SRobert Mustacchi * Skip units we don't know how to handle.
1499*d573a566SRobert Mustacchi */
1500*d573a566SRobert Mustacchi if (nvlist_lookup_string(nvl, "unit_mode", &umode) == 0) {
1501*d573a566SRobert Mustacchi return (B_TRUE);
1502*d573a566SRobert Mustacchi }
1503*d573a566SRobert Mustacchi
1504*d573a566SRobert Mustacchi if (fprintf(f, ".Pp\n"
1505*d573a566SRobert Mustacchi "This event has the following units which may be used\n"
1506*d573a566SRobert Mustacchi "to modify the behavior of the event:\n"
1507*d573a566SRobert Mustacchi ".Bl -tag -width Sy\n") == -1) {
1508*d573a566SRobert Mustacchi warn("failed to write out event entry %s", name);
1509*d573a566SRobert Mustacchi return (B_FALSE);
1510*d573a566SRobert Mustacchi }
1511*d573a566SRobert Mustacchi
1512*d573a566SRobert Mustacchi if (nvlist_lookup_uint32(units, "length", &length) != 0) {
1513*d573a566SRobert Mustacchi warnx("found units array, but could not look up length "
1514*d573a566SRobert Mustacchi "property for events %s (index %u) in file %s",
1515*d573a566SRobert Mustacchi name, ent, path);
1516*d573a566SRobert Mustacchi return (B_FALSE);
1517*d573a566SRobert Mustacchi }
1518*d573a566SRobert Mustacchi
1519*d573a566SRobert Mustacchi for (i = 0; i < length; i++) {
1520*d573a566SRobert Mustacchi nvlist_t *uvl;
1521*d573a566SRobert Mustacchi char num[64];
1522*d573a566SRobert Mustacchi char *uname, *udesc = NULL;
1523*d573a566SRobert Mustacchi
1524*d573a566SRobert Mustacchi (void) snprintf(num, sizeof (num), "%u", i);
1525*d573a566SRobert Mustacchi if (nvlist_lookup_nvlist(units, num, &uvl) != 0) {
1526*d573a566SRobert Mustacchi warnx("failed to look up unit %u for event %s (index "
1527*d573a566SRobert Mustacchi "%u) in file %s", i, name, ent, path);
1528*d573a566SRobert Mustacchi return (B_FALSE);
1529*d573a566SRobert Mustacchi }
1530*d573a566SRobert Mustacchi
1531*d573a566SRobert Mustacchi if (nvlist_lookup_string(uvl, "name", &uname) != 0) {
1532*d573a566SRobert Mustacchi warnx("failed to find required members for unit array "
1533*d573a566SRobert Mustacchi "entry %u of event %s (index %u) from file %s",
1534*d573a566SRobert Mustacchi i, name, ent, path);
1535*d573a566SRobert Mustacchi return (B_FALSE);
1536*d573a566SRobert Mustacchi }
1537*d573a566SRobert Mustacchi (void) nvlist_lookup_string(uvl, "description", &udesc);
1538*d573a566SRobert Mustacchi if (fprintf(f, ".It Sy %s\n", uname) == -1) {
1539*d573a566SRobert Mustacchi warn("failed to write out event entry %s", name);
1540*d573a566SRobert Mustacchi return (B_FALSE);
1541*d573a566SRobert Mustacchi }
1542*d573a566SRobert Mustacchi
1543*d573a566SRobert Mustacchi if (udesc != NULL) {
1544*d573a566SRobert Mustacchi if (fprintf(f, "%s\n", udesc) == -1) {
1545*d573a566SRobert Mustacchi warn("failed to write out event entry %s",
1546*d573a566SRobert Mustacchi name);
1547*d573a566SRobert Mustacchi return (B_FALSE);
1548*d573a566SRobert Mustacchi }
1549*d573a566SRobert Mustacchi }
1550*d573a566SRobert Mustacchi }
1551*d573a566SRobert Mustacchi
1552*d573a566SRobert Mustacchi if (fprintf(f, ".El\n") == -1) {
1553*d573a566SRobert Mustacchi warn("failed to write out event entry %s",
1554*d573a566SRobert Mustacchi name);
1555*d573a566SRobert Mustacchi return (B_FALSE);
1556*d573a566SRobert Mustacchi }
1557*d573a566SRobert Mustacchi
1558*d573a566SRobert Mustacchi return (B_TRUE);
1559*d573a566SRobert Mustacchi }
1560*d573a566SRobert Mustacchi
1561*d573a566SRobert Mustacchi static char *
cpcgen_cfile_amd_name(cpc_map_t * map)1562*d573a566SRobert Mustacchi cpcgen_cfile_amd_name(cpc_map_t *map)
1563*d573a566SRobert Mustacchi {
1564*d573a566SRobert Mustacchi char *name;
1565*d573a566SRobert Mustacchi
1566*d573a566SRobert Mustacchi if (asprintf(&name, "opteron_pcbe_%s.c", map->cmap_name) == -1) {
1567*d573a566SRobert Mustacchi warn("failed to assemble file name for %s", map->cmap_path);
1568*d573a566SRobert Mustacchi return (NULL);
1569*d573a566SRobert Mustacchi }
1570*d573a566SRobert Mustacchi
1571*d573a566SRobert Mustacchi return (name);
1572*d573a566SRobert Mustacchi }
1573*d573a566SRobert Mustacchi
1574*d573a566SRobert Mustacchi /*
1575*d573a566SRobert Mustacchi * Generate a header file that can be used to synthesize the data events we care
1576*d573a566SRobert Mustacchi * about.
1577*d573a566SRobert Mustacchi */
1578*d573a566SRobert Mustacchi static void
cpcgen_common_amd_files(int dirfd)1579*d573a566SRobert Mustacchi cpcgen_common_amd_files(int dirfd)
1580*d573a566SRobert Mustacchi {
1581*d573a566SRobert Mustacchi const char *fname = "opteron_pcbe_cpcgen.h";
1582*d573a566SRobert Mustacchi char *tmpname;
1583*d573a566SRobert Mustacchi int fd;
1584*d573a566SRobert Mustacchi FILE *f;
1585*d573a566SRobert Mustacchi cpc_map_t *map;
1586*d573a566SRobert Mustacchi
1587*d573a566SRobert Mustacchi if (asprintf(&tmpname, ".%s.%d", fname, getpid()) == -1) {
1588*d573a566SRobert Mustacchi err(EXIT_FAILURE, "failed to construct temporary file name");
1589*d573a566SRobert Mustacchi }
1590*d573a566SRobert Mustacchi
1591*d573a566SRobert Mustacchi if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0644)) < 0) {
1592*d573a566SRobert Mustacchi err(EXIT_FAILURE, "failed to create temporary file %s",
1593*d573a566SRobert Mustacchi tmpname);
1594*d573a566SRobert Mustacchi }
1595*d573a566SRobert Mustacchi
1596*d573a566SRobert Mustacchi if ((f = fdopen(fd, "w")) == NULL) {
1597*d573a566SRobert Mustacchi cpcgen_remove_tmpfile(dirfd, tmpname);
1598*d573a566SRobert Mustacchi err(EXIT_FAILURE, "failed to fdopen temporary file");
1599*d573a566SRobert Mustacchi }
1600*d573a566SRobert Mustacchi
1601*d573a566SRobert Mustacchi if (fprintf(f, cpcgen_cfile_cddl_header) == -1) {
1602*d573a566SRobert Mustacchi cpcgen_remove_tmpfile(dirfd, tmpname);
1603*d573a566SRobert Mustacchi err(EXIT_FAILURE, "failed to write header to "
1604*d573a566SRobert Mustacchi "temporary file for %s", fname);
1605*d573a566SRobert Mustacchi }
1606*d573a566SRobert Mustacchi
1607*d573a566SRobert Mustacchi if (fprintf(f, "#ifndef _OPTERON_PCBE_CPCGEN_H\n"
1608*d573a566SRobert Mustacchi "#define\t_OPTERON_PCBE_CPCGEN_H\n"
1609*d573a566SRobert Mustacchi "\n"
1610*d573a566SRobert Mustacchi "#ifdef __cplusplus\n"
1611*d573a566SRobert Mustacchi "extern \"C\" {\n"
1612*d573a566SRobert Mustacchi "#endif\n"
1613*d573a566SRobert Mustacchi "\n") == -1) {
1614*d573a566SRobert Mustacchi cpcgen_remove_tmpfile(dirfd, tmpname);
1615*d573a566SRobert Mustacchi err(EXIT_FAILURE, "failed to write header to "
1616*d573a566SRobert Mustacchi "temporary file for %s", fname);
1617*d573a566SRobert Mustacchi }
1618*d573a566SRobert Mustacchi
1619*d573a566SRobert Mustacchi for (map = cpcgen_maps; map != NULL; map = map->cmap_next) {
1620*d573a566SRobert Mustacchi if (fprintf(f, "extern const amd_event_t "
1621*d573a566SRobert Mustacchi "opteron_pcbe_%s_events[];\n", map->cmap_name) == -1) {
1622*d573a566SRobert Mustacchi cpcgen_remove_tmpfile(dirfd, tmpname);
1623*d573a566SRobert Mustacchi err(EXIT_FAILURE, "failed to write header to "
1624*d573a566SRobert Mustacchi "temporary file for %s", fname);
1625*d573a566SRobert Mustacchi }
1626*d573a566SRobert Mustacchi }
1627*d573a566SRobert Mustacchi
1628*d573a566SRobert Mustacchi if (fprintf(f, "\n"
1629*d573a566SRobert Mustacchi "#ifdef __cplusplus\n"
1630*d573a566SRobert Mustacchi "}\n"
1631*d573a566SRobert Mustacchi "#endif\n"
1632*d573a566SRobert Mustacchi "\n"
1633*d573a566SRobert Mustacchi "#endif /* _OPTERON_PCBE_CPCGEN_H */\n") == -1) {
1634*d573a566SRobert Mustacchi cpcgen_remove_tmpfile(dirfd, tmpname);
1635*d573a566SRobert Mustacchi err(EXIT_FAILURE, "failed to write header to "
1636*d573a566SRobert Mustacchi "temporary file for %s", fname);
1637*d573a566SRobert Mustacchi }
1638*d573a566SRobert Mustacchi
1639*d573a566SRobert Mustacchi
1640*d573a566SRobert Mustacchi
1641*d573a566SRobert Mustacchi if (fflush(f) != 0 || fclose(f) != 0) {
1642*d573a566SRobert Mustacchi cpcgen_remove_tmpfile(dirfd, tmpname);
1643*d573a566SRobert Mustacchi err(EXIT_FAILURE, "failed to flush and close temporary file");
1644*d573a566SRobert Mustacchi }
1645*d573a566SRobert Mustacchi
1646*d573a566SRobert Mustacchi if (renameat(dirfd, tmpname, dirfd, fname) != 0) {
1647*d573a566SRobert Mustacchi err(EXIT_FAILURE, "failed to rename temporary file %s",
1648*d573a566SRobert Mustacchi tmpname);
1649*d573a566SRobert Mustacchi }
1650*d573a566SRobert Mustacchi
1651*d573a566SRobert Mustacchi free(tmpname);
1652*d573a566SRobert Mustacchi }
1653*d573a566SRobert Mustacchi
1654*d573a566SRobert Mustacchi static boolean_t
cpcgen_cfile_amd_before(FILE * f,cpc_map_t * map)1655*d573a566SRobert Mustacchi cpcgen_cfile_amd_before(FILE *f, cpc_map_t *map)
1656*d573a566SRobert Mustacchi {
1657*d573a566SRobert Mustacchi if (fprintf(f, cpcgen_cfile_amd_header, map->cmap_name) == -1) {
1658*d573a566SRobert Mustacchi warn("failed to write header to temporary file for %s",
1659*d573a566SRobert Mustacchi map->cmap_path);
1660*d573a566SRobert Mustacchi return (B_FALSE);
1661*d573a566SRobert Mustacchi }
1662*d573a566SRobert Mustacchi
1663*d573a566SRobert Mustacchi if (fprintf(f, cpcgen_cfile_amd_table_start, map->cmap_name) == -1) {
1664*d573a566SRobert Mustacchi warn("failed to write header to temporary file for %s",
1665*d573a566SRobert Mustacchi map->cmap_path);
1666*d573a566SRobert Mustacchi return (B_FALSE);
1667*d573a566SRobert Mustacchi }
1668*d573a566SRobert Mustacchi
1669*d573a566SRobert Mustacchi
1670*d573a566SRobert Mustacchi return (B_TRUE);
1671*d573a566SRobert Mustacchi }
1672*d573a566SRobert Mustacchi
1673*d573a566SRobert Mustacchi static boolean_t
cpcgen_cfile_amd_after(FILE * f,cpc_map_t * map)1674*d573a566SRobert Mustacchi cpcgen_cfile_amd_after(FILE *f, cpc_map_t *map)
1675*d573a566SRobert Mustacchi {
1676*d573a566SRobert Mustacchi if (fprintf(f, cpcgen_cfile_amd_table_end) == -1) {
1677*d573a566SRobert Mustacchi warn("failed to write footer to temporary file for %s",
1678*d573a566SRobert Mustacchi map->cmap_path);
1679*d573a566SRobert Mustacchi return (B_FALSE);
1680*d573a566SRobert Mustacchi }
1681*d573a566SRobert Mustacchi
1682*d573a566SRobert Mustacchi return (B_TRUE);
1683*d573a566SRobert Mustacchi }
1684*d573a566SRobert Mustacchi
1685*d573a566SRobert Mustacchi static boolean_t
cpcgen_cfile_amd_event(FILE * f,nvlist_t * nvl,const char * path,uint_t ent)1686*d573a566SRobert Mustacchi cpcgen_cfile_amd_event(FILE *f, nvlist_t *nvl, const char *path, uint_t ent)
1687*d573a566SRobert Mustacchi {
1688*d573a566SRobert Mustacchi char *name, *code, *umode;
1689*d573a566SRobert Mustacchi uint32_t i, length;
1690*d573a566SRobert Mustacchi nvlist_t *units;
1691*d573a566SRobert Mustacchi
1692*d573a566SRobert Mustacchi if (nvlist_lookup_string(nvl, "name", &name) != 0) {
1693*d573a566SRobert Mustacchi warnx("Found event without 'name' property in %s, entry %u",
1694*d573a566SRobert Mustacchi path, ent);
1695*d573a566SRobert Mustacchi return (B_FALSE);
1696*d573a566SRobert Mustacchi }
1697*d573a566SRobert Mustacchi
1698*d573a566SRobert Mustacchi if (nvlist_lookup_string(nvl, "code", &code) != 0) {
1699*d573a566SRobert Mustacchi warnx("event %s (index %u) from %s missing required properties "
1700*d573a566SRobert Mustacchi "for C translation", name, path, ent);
1701*d573a566SRobert Mustacchi return (B_FALSE);
1702*d573a566SRobert Mustacchi }
1703*d573a566SRobert Mustacchi
1704*d573a566SRobert Mustacchi if (fprintf(f, "\t{ \"%s\", %s, 0 },\n", name, code) == -1) {
1705*d573a566SRobert Mustacchi warn("failed to write out entry %s from %s", name, path);
1706*d573a566SRobert Mustacchi return (B_FALSE);
1707*d573a566SRobert Mustacchi }
1708*d573a566SRobert Mustacchi
1709*d573a566SRobert Mustacchi /*
1710*d573a566SRobert Mustacchi * The 'units' array is optional. If the rule has a specific 'unit_mode'
1711*d573a566SRobert Mustacchi * indicating how the units should be combined, skip that. We don't know
1712*d573a566SRobert Mustacchi * how to properly process that right now.
1713*d573a566SRobert Mustacchi */
1714*d573a566SRobert Mustacchi if (nvlist_lookup_nvlist(nvl, "units", &units) != 0) {
1715*d573a566SRobert Mustacchi return (B_TRUE);
1716*d573a566SRobert Mustacchi }
1717*d573a566SRobert Mustacchi
1718*d573a566SRobert Mustacchi if (nvlist_lookup_string(nvl, "unit_mode", &umode) == 0) {
1719*d573a566SRobert Mustacchi return (B_TRUE);
1720*d573a566SRobert Mustacchi }
1721*d573a566SRobert Mustacchi
1722*d573a566SRobert Mustacchi if (nvlist_lookup_uint32(units, "length", &length) != 0) {
1723*d573a566SRobert Mustacchi warnx("found units array, but could not look up length "
1724*d573a566SRobert Mustacchi "property for events %s (index %u) in file %s",
1725*d573a566SRobert Mustacchi name, ent, path);
1726*d573a566SRobert Mustacchi return (B_FALSE);
1727*d573a566SRobert Mustacchi }
1728*d573a566SRobert Mustacchi
1729*d573a566SRobert Mustacchi for (i = 0; i < length; i++) {
1730*d573a566SRobert Mustacchi nvlist_t *uvl;
1731*d573a566SRobert Mustacchi char num[64];
1732*d573a566SRobert Mustacchi char *uname, *urw;
1733*d573a566SRobert Mustacchi int32_t bit;
1734*d573a566SRobert Mustacchi
1735*d573a566SRobert Mustacchi (void) snprintf(num, sizeof (num), "%u", i);
1736*d573a566SRobert Mustacchi if (nvlist_lookup_nvlist(units, num, &uvl) != 0) {
1737*d573a566SRobert Mustacchi warnx("failed to look up unit %u for event %s (index "
1738*d573a566SRobert Mustacchi "%u) in file %s", i, name, ent, path);
1739*d573a566SRobert Mustacchi return (B_FALSE);
1740*d573a566SRobert Mustacchi }
1741*d573a566SRobert Mustacchi
1742*d573a566SRobert Mustacchi if (nvlist_lookup_string(uvl, "name", &uname) != 0 ||
1743*d573a566SRobert Mustacchi nvlist_lookup_string(uvl, "rw", &urw) != 0 ||
1744*d573a566SRobert Mustacchi nvlist_lookup_int32(uvl, "bit", &bit) != 0) {
1745*d573a566SRobert Mustacchi warnx("failed to find required members for unit array "
1746*d573a566SRobert Mustacchi "entry %u of event %s (index %u) from file %s",
1747*d573a566SRobert Mustacchi i, name, ent, path);
1748*d573a566SRobert Mustacchi dump_nvlist(uvl, 0);
1749*d573a566SRobert Mustacchi return (B_FALSE);
1750*d573a566SRobert Mustacchi }
1751*d573a566SRobert Mustacchi
1752*d573a566SRobert Mustacchi if (bit < 0 || bit > 31) {
1753*d573a566SRobert Mustacchi warnx("event %s (index %u) from file %s has invalid "
1754*d573a566SRobert Mustacchi "bit value: %d; skipping", name, ent, path, bit);
1755*d573a566SRobert Mustacchi continue;
1756*d573a566SRobert Mustacchi }
1757*d573a566SRobert Mustacchi
1758*d573a566SRobert Mustacchi if (strcasecmp(urw, "Read-write") != 0)
1759*d573a566SRobert Mustacchi continue;
1760*d573a566SRobert Mustacchi
1761*d573a566SRobert Mustacchi if (fprintf(f, "\t{ \"%s.%s\", %s, 0x%x },\n", name, uname,
1762*d573a566SRobert Mustacchi code, 1U << bit) == -1) {
1763*d573a566SRobert Mustacchi warn("failed to write out entry %s from %s", name,
1764*d573a566SRobert Mustacchi path);
1765*d573a566SRobert Mustacchi return (B_FALSE);
1766*d573a566SRobert Mustacchi }
1767*d573a566SRobert Mustacchi }
1768*d573a566SRobert Mustacchi
1769*d573a566SRobert Mustacchi return (B_TRUE);
1770*d573a566SRobert Mustacchi }
177112ae924aSRobert Mustacchi
177212ae924aSRobert Mustacchi /*
177312ae924aSRobert Mustacchi * For each processor family, generate a data file that contains all of the
177412ae924aSRobert Mustacchi * events that we support. Also generate a header that can be included that
177512ae924aSRobert Mustacchi * declares all of the tables.
177612ae924aSRobert Mustacchi */
177712ae924aSRobert Mustacchi static void
cpcgen_gen(int dirfd)177812ae924aSRobert Mustacchi cpcgen_gen(int dirfd)
177912ae924aSRobert Mustacchi {
178012ae924aSRobert Mustacchi cpc_map_t *map = cpcgen_maps;
178112ae924aSRobert Mustacchi
178212ae924aSRobert Mustacchi if (map == NULL) {
178312ae924aSRobert Mustacchi errx(EXIT_FAILURE, "no platforms found or matched");
178412ae924aSRobert Mustacchi }
178512ae924aSRobert Mustacchi
178612ae924aSRobert Mustacchi for (map = cpcgen_maps; map != NULL; map = map->cmap_next) {
178712ae924aSRobert Mustacchi int fd, ret;
178812ae924aSRobert Mustacchi FILE *f;
178912ae924aSRobert Mustacchi char *tmpname, *name;
179012ae924aSRobert Mustacchi uint32_t length, i;
179112ae924aSRobert Mustacchi
179212ae924aSRobert Mustacchi if ((name = cpcgen_ops.cgen_op_name(map)) == NULL) {
179312ae924aSRobert Mustacchi exit(EXIT_FAILURE);
179412ae924aSRobert Mustacchi }
179512ae924aSRobert Mustacchi
179612ae924aSRobert Mustacchi if (asprintf(&tmpname, ".%s.%d", name, getpid()) == -1) {
179712ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to construct temporary file "
179812ae924aSRobert Mustacchi "name");
179912ae924aSRobert Mustacchi }
180012ae924aSRobert Mustacchi
180112ae924aSRobert Mustacchi if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0444)) < 0) {
180212ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to create temporary file %s",
180312ae924aSRobert Mustacchi tmpname);
180412ae924aSRobert Mustacchi }
180512ae924aSRobert Mustacchi
180612ae924aSRobert Mustacchi if ((f = fdopen(fd, "w")) == NULL) {
1807*d573a566SRobert Mustacchi cpcgen_remove_tmpfile(dirfd, tmpname);
180812ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to fdopen temporary file");
180912ae924aSRobert Mustacchi }
181012ae924aSRobert Mustacchi
181112ae924aSRobert Mustacchi if (!cpcgen_ops.cgen_op_file_before(f, map)) {
1812*d573a566SRobert Mustacchi cpcgen_remove_tmpfile(dirfd, tmpname);
181312ae924aSRobert Mustacchi exit(EXIT_FAILURE);
181412ae924aSRobert Mustacchi }
181512ae924aSRobert Mustacchi
181612ae924aSRobert Mustacchi /*
181712ae924aSRobert Mustacchi * Iterate over array contents.
181812ae924aSRobert Mustacchi */
181912ae924aSRobert Mustacchi if ((ret = nvlist_lookup_uint32(map->cmap_data, "length",
182012ae924aSRobert Mustacchi &length)) != 0) {
182112ae924aSRobert Mustacchi errx(EXIT_FAILURE, "failed to look up length property "
182212ae924aSRobert Mustacchi "in parsed data for %s: %s", map->cmap_path,
182312ae924aSRobert Mustacchi strerror(ret));
182412ae924aSRobert Mustacchi }
182512ae924aSRobert Mustacchi
182612ae924aSRobert Mustacchi for (i = 0; i < length; i++) {
182712ae924aSRobert Mustacchi nvlist_t *nvl;
182812ae924aSRobert Mustacchi char num[64];
182912ae924aSRobert Mustacchi
183012ae924aSRobert Mustacchi (void) snprintf(num, sizeof (num), "%u", i);
183112ae924aSRobert Mustacchi if ((ret = nvlist_lookup_nvlist(map->cmap_data,
183212ae924aSRobert Mustacchi num, &nvl)) != 0) {
1833*d573a566SRobert Mustacchi cpcgen_remove_tmpfile(dirfd, tmpname);
183412ae924aSRobert Mustacchi errx(EXIT_FAILURE, "failed to look up array "
183512ae924aSRobert Mustacchi "entry %u in parsed data for %s: %s", i,
183612ae924aSRobert Mustacchi map->cmap_path, strerror(ret));
183712ae924aSRobert Mustacchi }
183812ae924aSRobert Mustacchi
1839*d573a566SRobert Mustacchi if (cpcgen_ops.cgen_op_skip != NULL &&
1840*d573a566SRobert Mustacchi cpcgen_ops.cgen_op_skip(nvl, map->cmap_path, i)) {
184112ae924aSRobert Mustacchi continue;
1842*d573a566SRobert Mustacchi }
184312ae924aSRobert Mustacchi
184412ae924aSRobert Mustacchi if (!cpcgen_ops.cgen_op_event(f, nvl, map->cmap_path,
184512ae924aSRobert Mustacchi i)) {
1846*d573a566SRobert Mustacchi cpcgen_remove_tmpfile(dirfd, tmpname);
184712ae924aSRobert Mustacchi exit(EXIT_FAILURE);
184812ae924aSRobert Mustacchi }
184912ae924aSRobert Mustacchi }
185012ae924aSRobert Mustacchi
185112ae924aSRobert Mustacchi if (!cpcgen_ops.cgen_op_file_after(f, map)) {
1852*d573a566SRobert Mustacchi cpcgen_remove_tmpfile(dirfd, tmpname);
185312ae924aSRobert Mustacchi exit(EXIT_FAILURE);
185412ae924aSRobert Mustacchi }
185512ae924aSRobert Mustacchi
185612ae924aSRobert Mustacchi if (fflush(f) != 0 || fclose(f) != 0) {
1857*d573a566SRobert Mustacchi cpcgen_remove_tmpfile(dirfd, tmpname);
185812ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to flush and close "
185912ae924aSRobert Mustacchi "temporary file");
186012ae924aSRobert Mustacchi }
186112ae924aSRobert Mustacchi
186212ae924aSRobert Mustacchi if (renameat(dirfd, tmpname, dirfd, name) != 0) {
186312ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to rename temporary file %s",
186412ae924aSRobert Mustacchi tmpname);
186512ae924aSRobert Mustacchi }
186612ae924aSRobert Mustacchi
186712ae924aSRobert Mustacchi free(name);
186812ae924aSRobert Mustacchi free(tmpname);
186912ae924aSRobert Mustacchi }
187012ae924aSRobert Mustacchi }
187112ae924aSRobert Mustacchi
187212ae924aSRobert Mustacchi static void
cpcgen_usage(const char * fmt,...)187312ae924aSRobert Mustacchi cpcgen_usage(const char *fmt, ...)
187412ae924aSRobert Mustacchi {
187512ae924aSRobert Mustacchi if (fmt != NULL) {
187612ae924aSRobert Mustacchi va_list ap;
187712ae924aSRobert Mustacchi
187812ae924aSRobert Mustacchi (void) fprintf(stderr, "%s: ", cpcgen_progname);
187912ae924aSRobert Mustacchi va_start(ap, fmt);
188012ae924aSRobert Mustacchi (void) vfprintf(stderr, fmt, ap);
188112ae924aSRobert Mustacchi va_end(ap);
188212ae924aSRobert Mustacchi }
188312ae924aSRobert Mustacchi
188412ae924aSRobert Mustacchi (void) fprintf(stderr, "Usage: %s -a|-p platform -c|-H|-m -d datadir "
188512ae924aSRobert Mustacchi "-o outdir\n"
188612ae924aSRobert Mustacchi "\n"
188712ae924aSRobert Mustacchi "\t-a generate data for all platforms\n"
188812ae924aSRobert Mustacchi "\t-c generate C file for CPC\n"
188912ae924aSRobert Mustacchi "\t-d specify the directory containt perfmon data\n"
1890*d573a566SRobert Mustacchi "\t-H generate header file and common files\n"
189112ae924aSRobert Mustacchi "\t-m generate manual pages for CPC data\n"
1892*d573a566SRobert Mustacchi "\t-o output files in directory outdir\n"
189312ae924aSRobert Mustacchi "\t-p generate data for a specified platform\n",
189412ae924aSRobert Mustacchi cpcgen_progname);
189512ae924aSRobert Mustacchi }
189612ae924aSRobert Mustacchi
189712ae924aSRobert Mustacchi int
main(int argc,char * argv[])189812ae924aSRobert Mustacchi main(int argc, char *argv[])
189912ae924aSRobert Mustacchi {
190012ae924aSRobert Mustacchi int c, outdirfd;
190112ae924aSRobert Mustacchi boolean_t do_mpage = B_FALSE, do_cfile = B_FALSE, do_header = B_FALSE,
190212ae924aSRobert Mustacchi do_all = B_FALSE;
190312ae924aSRobert Mustacchi const char *datadir = NULL, *outdir = NULL, *platform = NULL;
190412ae924aSRobert Mustacchi uint_t count = 0;
190512ae924aSRobert Mustacchi
190612ae924aSRobert Mustacchi cpcgen_progname = basename(argv[0]);
190712ae924aSRobert Mustacchi
190812ae924aSRobert Mustacchi while ((c = getopt(argc, argv, ":acd:hHmo:p:")) != -1) {
190912ae924aSRobert Mustacchi switch (c) {
191012ae924aSRobert Mustacchi case 'a':
191112ae924aSRobert Mustacchi do_all = B_TRUE;
191212ae924aSRobert Mustacchi break;
191312ae924aSRobert Mustacchi case 'c':
191412ae924aSRobert Mustacchi do_cfile = B_TRUE;
191512ae924aSRobert Mustacchi break;
191612ae924aSRobert Mustacchi case 'd':
191712ae924aSRobert Mustacchi datadir = optarg;
191812ae924aSRobert Mustacchi break;
191912ae924aSRobert Mustacchi case 'm':
192012ae924aSRobert Mustacchi do_mpage = B_TRUE;
192112ae924aSRobert Mustacchi break;
192212ae924aSRobert Mustacchi case 'H':
192312ae924aSRobert Mustacchi do_header = B_TRUE;
192412ae924aSRobert Mustacchi break;
192512ae924aSRobert Mustacchi case 'o':
192612ae924aSRobert Mustacchi outdir = optarg;
192712ae924aSRobert Mustacchi break;
192812ae924aSRobert Mustacchi case 'p':
192912ae924aSRobert Mustacchi platform = optarg;
193012ae924aSRobert Mustacchi break;
193112ae924aSRobert Mustacchi case ':':
193212ae924aSRobert Mustacchi cpcgen_usage("Option -%c requires an operand\n",
193312ae924aSRobert Mustacchi optopt);
193412ae924aSRobert Mustacchi return (2);
193512ae924aSRobert Mustacchi case '?':
193612ae924aSRobert Mustacchi cpcgen_usage("Unknown option: -%c\n", optopt);
193712ae924aSRobert Mustacchi return (2);
193812ae924aSRobert Mustacchi case 'h':
193912ae924aSRobert Mustacchi default:
194012ae924aSRobert Mustacchi cpcgen_usage(NULL);
194112ae924aSRobert Mustacchi return (2);
194212ae924aSRobert Mustacchi }
194312ae924aSRobert Mustacchi }
194412ae924aSRobert Mustacchi
194512ae924aSRobert Mustacchi count = 0;
194612ae924aSRobert Mustacchi if (do_mpage)
194712ae924aSRobert Mustacchi count++;
194812ae924aSRobert Mustacchi if (do_cfile)
194912ae924aSRobert Mustacchi count++;
195012ae924aSRobert Mustacchi if (do_header)
195112ae924aSRobert Mustacchi count++;
195212ae924aSRobert Mustacchi if (count > 1) {
195312ae924aSRobert Mustacchi cpcgen_usage("Only one of -c, -h, and -m may be specified\n");
195412ae924aSRobert Mustacchi return (2);
195512ae924aSRobert Mustacchi } else if (count == 0) {
195612ae924aSRobert Mustacchi cpcgen_usage("One of -c, -h, and -m is required\n");
195712ae924aSRobert Mustacchi return (2);
195812ae924aSRobert Mustacchi }
195912ae924aSRobert Mustacchi
196012ae924aSRobert Mustacchi count = 0;
196112ae924aSRobert Mustacchi if (do_all)
196212ae924aSRobert Mustacchi count++;
196312ae924aSRobert Mustacchi if (platform != NULL)
196412ae924aSRobert Mustacchi count++;
196512ae924aSRobert Mustacchi if (count > 1) {
196612ae924aSRobert Mustacchi cpcgen_usage("Only one of -a and -p may be specified\n");
196712ae924aSRobert Mustacchi return (2);
196812ae924aSRobert Mustacchi } else if (count == 0) {
196912ae924aSRobert Mustacchi cpcgen_usage("One of -a and -p is required\n");
197012ae924aSRobert Mustacchi return (2);
197112ae924aSRobert Mustacchi }
197212ae924aSRobert Mustacchi
197312ae924aSRobert Mustacchi if (outdir == NULL) {
197412ae924aSRobert Mustacchi cpcgen_usage("Missing required output directory (-o)\n");
197512ae924aSRobert Mustacchi return (2);
197612ae924aSRobert Mustacchi }
197712ae924aSRobert Mustacchi
197812ae924aSRobert Mustacchi if ((outdirfd = open(outdir, O_RDONLY)) < 0) {
197912ae924aSRobert Mustacchi err(EXIT_FAILURE, "failed to open output directory %s", outdir);
198012ae924aSRobert Mustacchi }
198112ae924aSRobert Mustacchi
198212ae924aSRobert Mustacchi if (datadir == NULL) {
198312ae924aSRobert Mustacchi cpcgen_usage("Missing required data directory (-d)\n");
198412ae924aSRobert Mustacchi return (2);
198512ae924aSRobert Mustacchi }
198612ae924aSRobert Mustacchi
1987*d573a566SRobert Mustacchi cpcgen_determine_vendor(datadir);
1988*d573a566SRobert Mustacchi
1989*d573a566SRobert Mustacchi switch (cpcgen_mode) {
1990*d573a566SRobert Mustacchi case CPCGEN_MODE_INTEL:
1991*d573a566SRobert Mustacchi cpcgen_ops.cgen_op_gather = cpcgen_read_intel;
1992*d573a566SRobert Mustacchi cpcgen_ops.cgen_op_common = cpcgen_common_intel_files;
1993*d573a566SRobert Mustacchi cpcgen_ops.cgen_op_skip = cpcgen_skip_intel_entry;
1994*d573a566SRobert Mustacchi if (do_mpage) {
1995*d573a566SRobert Mustacchi cpcgen_ops.cgen_op_name = cpcgen_manual_intel_name;
1996*d573a566SRobert Mustacchi cpcgen_ops.cgen_op_file_before =
1997*d573a566SRobert Mustacchi cpcgen_manual_intel_file_before;
1998*d573a566SRobert Mustacchi cpcgen_ops.cgen_op_file_after =
1999*d573a566SRobert Mustacchi cpcgen_manual_intel_file_after;
2000*d573a566SRobert Mustacchi cpcgen_ops.cgen_op_event = cpcgen_manual_intel_event;
2001*d573a566SRobert Mustacchi } else {
2002*d573a566SRobert Mustacchi cpcgen_ops.cgen_op_name = cpcgen_cfile_intel_name;
2003*d573a566SRobert Mustacchi cpcgen_ops.cgen_op_file_before =
2004*d573a566SRobert Mustacchi cpcgen_cfile_intel_before;
2005*d573a566SRobert Mustacchi cpcgen_ops.cgen_op_file_after =
2006*d573a566SRobert Mustacchi cpcgen_cfile_intel_after;
2007*d573a566SRobert Mustacchi cpcgen_ops.cgen_op_event = cpcgen_cfile_intel_event;
2008*d573a566SRobert Mustacchi }
2009*d573a566SRobert Mustacchi break;
2010*d573a566SRobert Mustacchi case CPCGEN_MODE_AMD:
2011*d573a566SRobert Mustacchi cpcgen_ops.cgen_op_gather = cpcgen_read_amd;
2012*d573a566SRobert Mustacchi cpcgen_ops.cgen_op_common = cpcgen_common_amd_files;
2013*d573a566SRobert Mustacchi cpcgen_ops.cgen_op_skip = NULL;
2014*d573a566SRobert Mustacchi if (do_mpage) {
2015*d573a566SRobert Mustacchi cpcgen_ops.cgen_op_name = cpcgen_manual_amd_name;
2016*d573a566SRobert Mustacchi cpcgen_ops.cgen_op_file_before =
2017*d573a566SRobert Mustacchi cpcgen_manual_amd_file_before;
2018*d573a566SRobert Mustacchi cpcgen_ops.cgen_op_file_after =
2019*d573a566SRobert Mustacchi cpcgen_manual_amd_file_after;
2020*d573a566SRobert Mustacchi cpcgen_ops.cgen_op_event = cpcgen_manual_amd_event;
2021*d573a566SRobert Mustacchi } else {
2022*d573a566SRobert Mustacchi cpcgen_ops.cgen_op_name = cpcgen_cfile_amd_name;
2023*d573a566SRobert Mustacchi cpcgen_ops.cgen_op_file_before =
2024*d573a566SRobert Mustacchi cpcgen_cfile_amd_before;
2025*d573a566SRobert Mustacchi cpcgen_ops.cgen_op_file_after = cpcgen_cfile_amd_after;
2026*d573a566SRobert Mustacchi cpcgen_ops.cgen_op_event = cpcgen_cfile_amd_event;
2027*d573a566SRobert Mustacchi
2028*d573a566SRobert Mustacchi }
2029*d573a566SRobert Mustacchi break;
2030*d573a566SRobert Mustacchi default:
2031*d573a566SRobert Mustacchi errx(EXIT_FAILURE, "failed to determine if operating on AMD or "
2032*d573a566SRobert Mustacchi "Intel");
2033*d573a566SRobert Mustacchi break;
2034*d573a566SRobert Mustacchi }
2035*d573a566SRobert Mustacchi
2036*d573a566SRobert Mustacchi cpcgen_ops.cgen_op_gather(datadir, platform);
203712ae924aSRobert Mustacchi
203812ae924aSRobert Mustacchi if (do_header) {
2039*d573a566SRobert Mustacchi cpcgen_ops.cgen_op_common(outdirfd);
204012ae924aSRobert Mustacchi return (0);
204112ae924aSRobert Mustacchi }
204212ae924aSRobert Mustacchi
204312ae924aSRobert Mustacchi cpcgen_gen(outdirfd);
204412ae924aSRobert Mustacchi
204512ae924aSRobert Mustacchi return (0);
204612ae924aSRobert Mustacchi }
2047