1 /* $NetBSD: tprof_x86.c,v 1.4 2018/07/14 07:54:04 maxv Exp $ */ 2 3 /* 4 * Copyright (c) 2018 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Maxime Villard. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <stdbool.h> 36 #include <string.h> 37 #include <unistd.h> 38 #include <err.h> 39 #include <machine/specialreg.h> 40 #include <dev/tprof/tprof_ioctl.h> 41 #include "../tprof.h" 42 43 int tprof_event_init(uint32_t); 44 void tprof_event_list(void); 45 void tprof_event_lookup(const char *, struct tprof_param *); 46 47 struct name_to_event { 48 const char *name; 49 uint64_t event; 50 uint64_t unit; 51 bool enabled; 52 }; 53 54 struct event_table { 55 const char *tablename; 56 struct name_to_event *names; 57 size_t nevents; 58 struct event_table *next; 59 }; 60 61 static struct event_table *cpuevents = NULL; 62 63 static void x86_cpuid(unsigned int *eax, unsigned int *ebx, 64 unsigned int *ecx, unsigned int *edx) 65 { 66 asm volatile("cpuid" 67 : "=a" (*eax), 68 "=b" (*ebx), 69 "=c" (*ecx), 70 "=d" (*edx) 71 : "0" (*eax), "2" (*ecx)); 72 } 73 74 /* -------------------------------------------------------------------------- */ 75 76 /* 77 * Intel Architectural Version 1. 78 */ 79 static struct name_to_event intel_arch1_names[] = { 80 /* Event Name - Event Select - UMask */ 81 { "unhalted-core-cycles", 0x3C, 0x00, true }, 82 { "instruction-retired", 0xC0, 0x00, true }, 83 { "unhalted-reference-cycles", 0x3C, 0x01, true }, 84 { "llc-reference", 0x2E, 0x4F, true }, 85 { "llc-misses", 0x2E, 0x41, true }, 86 { "branch-instruction-retired", 0xC4, 0x00, true }, 87 { "branch-misses-retired", 0xC5, 0x00, true }, 88 }; 89 90 static struct event_table intel_arch1 = { 91 .tablename = "Intel Architectural Version 1", 92 .names = intel_arch1_names, 93 .nevents = sizeof(intel_arch1_names) / 94 sizeof(struct name_to_event), 95 .next = NULL 96 }; 97 98 static struct event_table * 99 init_intel_arch1(void) 100 { 101 unsigned int eax, ebx, ecx, edx; 102 struct event_table *table; 103 size_t i; 104 105 eax = 0x0A; 106 ebx = 0; 107 ecx = 0; 108 edx = 0; 109 x86_cpuid(&eax, &ebx, &ecx, &edx); 110 111 table = &intel_arch1; 112 for (i = 0; i < table->nevents; i++) { 113 /* Disable the unsupported events. */ 114 if ((ebx & (i << 1)) != 0) 115 table->names[i].enabled = false; 116 } 117 118 return table; 119 } 120 121 /* 122 * Intel Skylake/Kabylake. 123 * 124 * The events that are not listed, because they are of little interest or 125 * require extra configuration: 126 * TX_* 127 * FRONTEND_RETIRED.* 128 * FP_ARITH_INST_RETIRED.* 129 * HLE_RETIRED.* 130 * RTM_RETIRED.* 131 * MEM_TRANS_RETIRED.* 132 * UOPS_DISPATCHED_PORT.* 133 */ 134 static struct name_to_event intel_skylake_kabylake_names[] = { 135 /* Event Name - Event Select - UMask */ 136 { "LD_BLOCKS.STORE_FORWARD", 0x03, 0x02, true }, 137 { "LD_BLOCKS.NO_SR", 0x03, 0x08, true }, 138 { "LD_BLOCKS_PARTIAL.ADDRESS_ALIAS", 0x07, 0x01, true }, 139 { "DTLB_LOAD_MISSES.MISS_CAUSES_A_WALK", 0x08, 0x01, true }, 140 { "DTLB_LOAD_MISSES.WALK_COMPLETED_4K", 0x08, 0x02, true }, 141 { "DTLB_LOAD_MISSES.WALK_COMPLETED_2M_4M", 0x08, 0x04, true }, 142 { "DTLB_LOAD_MISSES.WALK_COMPLETED_1G", 0x08, 0x08, true }, 143 { "DTLB_LOAD_MISSES.WALK_COMPLETED", 0x08, 0x0E, true }, 144 { "DTLB_LOAD_MISSES.WALK_PENDING", 0x08, 0x10, true }, 145 { "DTLB_LOAD_MISSES.STLB_HIT", 0x08, 0x20, true }, 146 { "INT_MISC.RECOVERY_CYCLES", 0x0D, 0x01, true }, 147 { "INT_MISC.CLEAR_RESTEER_CYCLES", 0x0D, 0x80, true }, 148 { "UOPS_ISSUED.ANY", 0x0E, 0x01, true }, 149 { "UOPS_ISSUED.VECTOR_WIDTH_MISMATCH", 0x0E, 0x02, true }, 150 { "UOPS_ISSUED.SLOW_LEA", 0x0E, 0x20, true }, 151 { "L2_RQSTS.DEMAND_DATA_RD_MISS", 0x24, 0x21, true }, 152 { "L2_RQSTS.RFO_MISS", 0x24, 0x22, true }, 153 { "L2_RQSTS.CODE_RD_MISS", 0x24, 0x24, true }, 154 { "L2_RQSTS.ALL_DEMAND_MISS", 0x24, 0x27, true }, 155 { "L2_RQSTS.PF_MISS", 0x24, 0x38, true }, 156 { "L2_RQSTS.MISS", 0x24, 0x3F, true }, 157 { "L2_RQSTS.DEMAND_DATA_RD_HIT", 0x24, 0x41, true }, 158 { "L2_RQSTS.RFO_HIT", 0x24, 0x42, true }, 159 { "L2_RQSTS.CODE_RD_HIT", 0x24, 0x44, true }, 160 { "L2_RQSTS.PF_HIT", 0x24, 0xD8, true }, 161 { "L2_RQSTS.ALL_DEMAND_DATA_RD", 0x24, 0xE1, true }, 162 { "L2_RQSTS.ALL_RFO", 0x24, 0xE2, true }, 163 { "L2_RQSTS.ALL_CODE_RD", 0x24, 0xE4, true }, 164 { "L2_RQSTS.ALL_DEMAND_REFERENCES", 0x24, 0xE7, true }, 165 { "L2_RQSTS.ALL_PF", 0x24, 0xF8, true }, 166 { "L2_RQSTS.REFERENCES", 0x24, 0xFF, true }, 167 { "SW_PREFETCH_ACCESS.NTA", 0x32, 0x01, true }, 168 { "SW_PREFETCH_ACCESS.T0", 0x32, 0x02, true }, 169 { "SW_PREFETCH_ACCESS.T1_T2", 0x32, 0x04, true }, 170 { "SW_PREFETCH_ACCESS.PREFETCHW", 0x32, 0x08, true }, 171 { "CPU_CLK_THREAD_UNHALTED.ONE_THREAD_ACTIVE", 0x3C, 0x02, true }, 172 { "CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE", 0x3C, 0x02, true }, 173 { "L1D_PEND_MISS.PENDING", 0x48, 0x01, true }, 174 { "L1D_PEND_MISS.FB_FULL", 0x48, 0x02, true }, 175 { "DTLB_STORE_MISSES.MISS_CAUSES_A_WALK", 0x49, 0x01, true }, 176 { "DTLB_STORE_MISSES.WALK_COMPLETED_4K", 0x49, 0x02, true }, 177 { "DTLB_STORE_MISSES.WALK_COMPLETED_2M_4M", 0x49, 0x04, true }, 178 { "DTLB_STORE_MISSES.WALK_COMPLETED_1G", 0x49, 0x08, true }, 179 { "DTLB_STORE_MISSES.WALK_COMPLETED", 0x49, 0x0E, true }, 180 { "DTLB_STORE_MISSES.WALK_PENDING", 0x49, 0x10, true }, 181 { "DTLB_STORE_MISSES.STLB_HIT", 0x49, 0x20, true }, 182 { "LOAD_HIT_PRE.SW_PF", 0x4C, 0x01, true }, 183 { "EPT.WALK_PENDING", 0x4F, 0x10, true }, 184 { "L1D.REPLACEMENT", 0x51, 0x01, true }, 185 { "RS_EVENTS.EMPTY_CYCLES", 0x5E, 0x01, true }, 186 { "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD", 0x60, 0x01, true }, 187 { "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_CODE_RD", 0x60, 0x02, true }, 188 { "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_RFO", 0x60, 0x04, true }, 189 { "OFFCORE_REQUESTS_OUTSTANDING.ALL_DATA_RD", 0x60, 0x08, true }, 190 { "OFFCORE_REQUESTS_OUTSTANDING.L3_MISS_DEMAND_DATA_RD", 0x60, 0x10, true }, 191 { "IDQ.MITE_UOPS", 0x79, 0x04, true }, 192 { "IDQ.DSB_UOPS", 0x79, 0x08, true }, 193 { "IDQ.MS_MITE_UOPS", 0x79, 0x20, true }, 194 { "IDQ.MS_UOPS", 0x79, 0x30, true }, 195 { "ICACHE_16B.IFDATA_STALL", 0x80, 0x04, true }, 196 { "ICACHE_64B.IFTAG_HIT", 0x83, 0x01, true }, 197 { "ICACHE_64B.IFTAG_MISS", 0x83, 0x02, true }, 198 { "ICACHE_64B.IFTAG_STALL", 0x83, 0x04, true }, 199 { "ITLB_MISSES.MISS_CAUSES_A_WALK", 0x85, 0x01, true }, 200 { "ITLB_MISSES.WALK_COMPLETED_4K", 0x85, 0x02, true }, 201 { "ITLB_MISSES.WALK_COMPLETED_2M_4M", 0x85, 0x04, true }, 202 { "ITLB_MISSES.WALK_COMPLETED_1G", 0x85, 0x08, true }, 203 { "ITLB_MISSES.WALK_COMPLETED", 0x85, 0x0E, true }, 204 { "ITLB_MISSES.WALK_PENDING", 0x85, 0x10, true }, 205 { "ITLB_MISSES.STLB_HIT", 0x85, 0x20, true }, 206 { "ILD_STALL.LCP", 0x87, 0x01, true }, 207 { "IDQ_UOPS_NOT_DELIVERED.CORE", 0x9C, 0x01, true }, 208 { "RESOURCE_STALLS.ANY", 0xA2, 0x01, true }, 209 { "RESOURCE_STALLS.SB", 0xA2, 0x08, true }, 210 { "EXE_ACTIVITY.EXE_BOUND_0_PORTS", 0xA6, 0x01, true }, 211 { "EXE_ACTIVITY.1_PORTS_UTIL", 0xA6, 0x02, true }, 212 { "EXE_ACTIVITY.2_PORTS_UTIL", 0xA6, 0x04, true }, 213 { "EXE_ACTIVITY.3_PORTS_UTIL", 0xA6, 0x08, true }, 214 { "EXE_ACTIVITY.4_PORTS_UTIL", 0xA6, 0x10, true }, 215 { "EXE_ACTIVITY.BOUND_ON_STORES", 0xA6, 0x40, true }, 216 { "LSD.UOPS", 0xA8, 0x01, true }, 217 { "DSB2MITE_SWITCHES.PENALTY_CYCLES", 0xAB, 0x02, true }, 218 { "ITLB.ITLB_FLUSH", 0xAE, 0x01, true }, 219 { "OFFCORE_REQUESTS.DEMAND_DATA_RD", 0xB0, 0x01, true }, 220 { "OFFCORE_REQUESTS.DEMAND_CODE_RD", 0xB0, 0x02, true }, 221 { "OFFCORE_REQUESTS.DEMAND_RFO", 0xB0, 0x04, true }, 222 { "OFFCORE_REQUESTS.ALL_DATA_RD", 0xB0, 0x08, true }, 223 { "OFFCORE_REQUESTS.L3_MISS_DEMAND_DATA_RD", 0xB0, 0x10, true }, 224 { "OFFCORE_REQUESTS.ALL_REQUESTS", 0xB0, 0x80, true }, 225 { "UOPS_EXECUTED.THREAD", 0xB1, 0x01, true }, 226 { "UOPS_EXECUTED.CORE", 0xB1, 0x02, true }, 227 { "UOPS_EXECUTED.X87", 0xB1, 0x10, true }, 228 { "OFFCORE_REQUESTS_BUFFER.SQ_FULL", 0xB2, 0x01, true }, 229 { "TLB_FLUSH.DTLB_THREAD", 0xBD, 0x01, true }, 230 { "TLB_FLUSH.STLB_ANY", 0xBD, 0x20, true }, 231 { "INST_RETIRED.PREC_DIST", 0xC0, 0x01, true }, 232 { "OTHER_ASSISTS.ANY", 0xC1, 0x3F, true }, 233 { "UOPS_RETIRED.RETIRE_SLOTS", 0xC2, 0x02, true }, 234 { "MACHINE_CLEARS.MEMORY_ORDERING", 0xC3, 0x02, true }, 235 { "MACHINE_CLEARS.SMC", 0xC3, 0x04, true }, 236 { "BR_INST_RETIRED.CONDITIONAL", 0xC4, 0x01, true }, 237 { "BR_INST_RETIRED.NEAR_CALL", 0xC4, 0x02, true }, 238 { "BR_INST_RETIRED.NEAR_RETURN", 0xC4, 0x08, true }, 239 { "BR_INST_RETIRED.NOT_TAKEN", 0xC4, 0x10, true }, 240 { "BR_INST_RETIRED.NEAR_TAKEN", 0xC4, 0x20, true }, 241 { "BR_INST_RETIRED.FAR_BRANCH", 0xC4, 0x40, true }, 242 { "BR_MISP_RETIRED.CONDITIONAL", 0xC5, 0x01, true }, 243 { "BR_MISP_RETIRED.NEAR_CALL", 0xC5, 0x02, true }, 244 { "BR_MISP_RETIRED.NEAR_TAKEN", 0xC5, 0x20, true }, 245 { "HW_INTERRUPTS.RECEIVED", 0xCB, 0x01, true }, 246 { "MEM_INST_RETIRED.STLB_MISS_LOADS", 0xD0, 0x11, true }, 247 { "MEM_INST_RETIRED.STLB_MISS_STORES", 0xD0, 0x12, true }, 248 { "MEM_INST_RETIRED.LOCK_LOADS", 0xD0, 0x21, true }, 249 { "MEM_INST_RETIRED.SPLIT_LOADS", 0xD0, 0x41, true }, 250 { "MEM_INST_RETIRED.SPLIT_STORES", 0xD0, 0x42, true }, 251 { "MEM_INST_RETIRED.ALL_LOADS", 0xD0, 0x81, true }, 252 { "MEM_INST_RETIRED.ALL_STORES", 0xD0, 0x82, true }, 253 { "MEM_LOAD_RETIRED.L1_HIT", 0xD1, 0x01, true }, 254 { "MEM_LOAD_RETIRED.L2_HIT", 0xD1, 0x02, true }, 255 { "MEM_LOAD_RETIRED.L3_HIT", 0xD1, 0x04, true }, 256 { "MEM_LOAD_RETIRED.L1_MISS", 0xD1, 0x08, true }, 257 { "MEM_LOAD_RETIRED.L2_MISS", 0xD1, 0x10, true }, 258 { "MEM_LOAD_RETIRED.L3_MISS", 0xD1, 0x20, true }, 259 { "MEM_LOAD_RETIRED.FB_HIT", 0xD1, 0x40, true }, 260 { "MEM_LOAD_L3_HIT_RETIRED.XSNP_MISS", 0xD2, 0x01, true }, 261 { "MEM_LOAD_L3_HIT_RETIRED.XSNP_HIT", 0xD2, 0x02, true }, 262 { "MEM_LOAD_L3_HIT_RETIRED.XSNP_HITM", 0xD2, 0x04, true }, 263 { "MEM_LOAD_L3_HIT_RETIRED.XSNP_NONE", 0xD2, 0x08, true }, 264 { "MEM_LOAD_MISC_RETIRED.UC", 0xD4, 0x04, true }, 265 { "BACLEARS.ANY", 0xE6, 0x01, true }, 266 { "L2_TRANS.L2_WB", 0xF0, 0x40, true }, 267 { "L2_LINES_IN.ALL", 0xF1, 0x1F, true }, 268 { "L2_LINES_OUT.SILENT", 0xF2, 0x01, true }, 269 { "L2_LINES_OUT.NON_SILENT", 0xF2, 0x02, true }, 270 { "L2_LINES_OUT.USELESS_HWPF", 0xF2, 0x04, true }, 271 { "SQ_MISC.SPLIT_LOCK", 0xF4, 0x10, true }, 272 }; 273 274 static struct event_table intel_skylake_kabylake = { 275 .tablename = "Intel Skylake/Kabylake", 276 .names = intel_skylake_kabylake_names, 277 .nevents = sizeof(intel_skylake_kabylake_names) / 278 sizeof(struct name_to_event), 279 .next = NULL 280 }; 281 282 static struct event_table * 283 init_intel_skylake_kabylake(void) 284 { 285 return &intel_skylake_kabylake; 286 } 287 288 static struct event_table * 289 init_intel_generic(void) 290 { 291 unsigned int eax, ebx, ecx, edx; 292 struct event_table *table; 293 294 /* 295 * The kernel made sure the Architectural Version 1 PMCs were 296 * present. 297 */ 298 table = init_intel_arch1(); 299 300 /* 301 * Now query the additional (non-architectural) events. They 302 * depend on the CPU model. 303 */ 304 eax = 0x01; 305 ebx = 0; 306 ecx = 0; 307 edx = 0; 308 x86_cpuid(&eax, &ebx, &ecx, &edx); 309 310 if (CPUID_TO_FAMILY(eax) == 6) { 311 switch (CPUID_TO_MODEL(eax)) { 312 case 0x4E: /* Skylake */ 313 case 0x5E: /* Skylake */ 314 case 0x8E: /* Kabylake */ 315 case 0x9E: /* Kabylake */ 316 table->next = init_intel_skylake_kabylake(); 317 break; 318 } 319 } 320 321 return table; 322 } 323 324 /* -------------------------------------------------------------------------- */ 325 326 /* 327 * AMD Family 10h 328 */ 329 static struct name_to_event amd_f10h_names[] = { 330 { "seg-load-all", 0x20, 0x7f, true }, 331 { "seg-load-es", 0x20, 0x01, true }, 332 { "seg-load-cs", 0x20, 0x02, true }, 333 { "seg-load-ss", 0x20, 0x04, true }, 334 { "seg-load-ds", 0x20, 0x08, true }, 335 { "seg-load-fs", 0x20, 0x10, true }, 336 { "seg-load-gs", 0x20, 0x20, true }, 337 { "seg-load-hs", 0x20, 0x40, true }, 338 { "l1cache-access", 0x40, 0x00, true }, 339 { "l1cache-miss", 0x41, 0x00, true }, 340 { "l1cache-refill", 0x42, 0x1f, true }, 341 { "l1cache-refill-invalid", 0x42, 0x01, true }, 342 { "l1cache-refill-shared", 0x42, 0x02, true }, 343 { "l1cache-refill-exclusive", 0x42, 0x04, true }, 344 { "l1cache-refill-owner", 0x42, 0x08, true }, 345 { "l1cache-refill-modified", 0x42, 0x10, true }, 346 { "l1cache-load", 0x43, 0x1f, true }, 347 { "l1cache-load-invalid", 0x43, 0x01, true }, 348 { "l1cache-load-shared", 0x43, 0x02, true }, 349 { "l1cache-load-exclusive", 0x43, 0x04, true }, 350 { "l1cache-load-owner", 0x43, 0x08, true }, 351 { "l1cache-load-modified", 0x43, 0x10, true }, 352 { "l1cache-writeback", 0x44, 0x1f, true }, 353 { "l1cache-writeback-invalid", 0x44, 0x01, true }, 354 { "l1cache-writeback-shared", 0x44, 0x02, true }, 355 { "l1cache-writeback-exclusive",0x44, 0x04, true }, 356 { "l1cache-writeback-owner", 0x44, 0x08, true }, 357 { "l1cache-writeback-modified", 0x44, 0x10, true }, 358 { "l1DTLB-hit-all", 0x4D, 0x07, true }, 359 { "l1DTLB-hit-4Kpage", 0x4D, 0x01, true }, 360 { "l1DTLB-hit-2Mpage", 0x4D, 0x02, true }, 361 { "l1DTLB-hit-1Gpage", 0x4D, 0x04, true }, 362 { "l1DTLB-miss-all", 0x45, 0x07, true }, 363 { "l1DTLB-miss-4Kpage", 0x45, 0x01, true }, 364 { "l1DTLB-miss-2Mpage", 0x45, 0x02, true }, 365 { "l1DTLB-miss-1Gpage", 0x45, 0x04, true }, 366 { "l2DTLB-miss-all", 0x46, 0x03, true }, 367 { "l2DTLB-miss-4Kpage", 0x46, 0x01, true }, 368 { "l2DTLB-miss-2Mpage", 0x46, 0x02, true }, 369 /* l2DTLB-miss-1Gpage: reserved on some revisions, so disabled */ 370 { "l1ITLB-miss", 0x84, 0x00, true }, 371 { "l2ITLB-miss-all", 0x85, 0x03, true }, 372 { "l2ITLB-miss-4Kpage", 0x85, 0x01, true }, 373 { "l2ITLB-miss-2Mpage", 0x85, 0x02, true }, 374 { "mem-misalign-ref", 0x47, 0x00, true }, 375 { "ins-fetch", 0x80, 0x00, true }, 376 { "ins-fetch-miss", 0x81, 0x00, true }, 377 { "ins-refill-l2", 0x82, 0x00, true }, 378 { "ins-refill-sys", 0x83, 0x00, true }, 379 { "ins-fetch-stall", 0x87, 0x00, true }, 380 { "ins-retired", 0xC0, 0x00, true }, 381 { "ins-empty", 0xD0, 0x00, true }, 382 { "ops-retired", 0xC1, 0x00, true }, 383 { "branch-retired", 0xC2, 0x00, true }, 384 { "branch-miss-retired", 0xC3, 0x00, true }, 385 { "branch-taken-retired", 0xC4, 0x00, true }, 386 { "branch-taken-miss-retired", 0xC5, 0x00, true }, 387 { "branch-far-retired", 0xC6, 0x00, true }, 388 { "branch-resync-retired", 0xC7, 0x00, true }, 389 { "branch-near-retired", 0xC8, 0x00, true }, 390 { "branch-near-miss-retired", 0xC9, 0x00, true }, 391 { "branch-indirect-miss-retired", 0xCA, 0x00, true }, 392 { "int-hw", 0xCF, 0x00, true }, 393 { "int-cycles-masked", 0xCD, 0x00, true }, 394 { "int-cycles-masked-pending", 0xCE, 0x00, true }, 395 { "fpu-exceptions", 0xDB, 0x00, true }, 396 { "break-match0", 0xDC, 0x00, true }, 397 { "break-match1", 0xDD, 0x00, true }, 398 { "break-match2", 0xDE, 0x00, true }, 399 { "break-match3", 0xDF, 0x00, true }, 400 }; 401 402 static struct event_table amd_f10h = { 403 .tablename = "AMD Family 10h", 404 .names = amd_f10h_names, 405 .nevents = sizeof(amd_f10h_names) / 406 sizeof(struct name_to_event), 407 .next = NULL 408 }; 409 410 static struct event_table * 411 init_amd_f10h(void) 412 { 413 return &amd_f10h; 414 } 415 416 static struct event_table * 417 init_amd_generic(void) 418 { 419 unsigned int eax, ebx, ecx, edx; 420 421 eax = 0x01; 422 ebx = 0; 423 ecx = 0; 424 edx = 0; 425 x86_cpuid(&eax, &ebx, &ecx, &edx); 426 427 switch (CPUID_TO_FAMILY(eax)) { 428 case 0x10: 429 return init_amd_f10h(); 430 } 431 432 return NULL; 433 } 434 435 /* -------------------------------------------------------------------------- */ 436 437 int 438 tprof_event_init(uint32_t ident) 439 { 440 switch (ident) { 441 case TPROF_IDENT_NONE: 442 return -1; 443 case TPROF_IDENT_INTEL_GENERIC: 444 cpuevents = init_intel_generic(); 445 break; 446 case TPROF_IDENT_AMD_GENERIC: 447 cpuevents = init_amd_generic(); 448 break; 449 } 450 return (cpuevents == NULL) ? -1 : 0; 451 } 452 453 static void 454 recursive_event_list(struct event_table *table) 455 { 456 size_t i; 457 458 printf("%s:\n", table->tablename); 459 for (i = 0; i < table->nevents; i++) { 460 if (!table->names[i].enabled) 461 continue; 462 printf("\t%s\n", table->names[i].name); 463 } 464 465 if (table->next != NULL) { 466 recursive_event_list(table->next); 467 } 468 } 469 470 void 471 tprof_event_list(void) 472 { 473 recursive_event_list(cpuevents); 474 } 475 476 static void 477 recursive_event_lookup(struct event_table *table, const char *name, 478 struct tprof_param *param) 479 { 480 size_t i; 481 482 for (i = 0; i < table->nevents; i++) { 483 if (!table->names[i].enabled) 484 continue; 485 if (!strcmp(table->names[i].name, name)) { 486 param->p_event = table->names[i].event; 487 param->p_unit = table->names[i].unit; 488 return; 489 } 490 } 491 492 if (table->next != NULL) { 493 recursive_event_lookup(table->next, name, param); 494 } else { 495 errx(EXIT_FAILURE, "event '%s' unknown", name); 496 } 497 } 498 499 void 500 tprof_event_lookup(const char *name, struct tprof_param *param) 501 { 502 recursive_event_lookup(cpuevents, name, param); 503 } 504