1 /* $NetBSD: pmc.c,v 1.16 2007/12/15 19:44:52 perry Exp $ */
4 * Copyright 2000 Wasabi Systems, Inc.
7 * Written by Frank van der Linden for Wasabi Systems, Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
37 #include <sys/cdefs.h>
40 __RCSID("$NetBSD: pmc.c,v 1.16 2007/12/15 19:44:52 perry Exp $");
43 #include <sys/types.h>
44 #include <machine/sysarch.h>
45 #include <machine/specialreg.h>
61 static const struct pmc_name2val i586_names
[] = {
62 { "tlb-data-miss", PMC5_DATA_TLB_MISS
, 0 },
63 { "tlb-ins-miss", PMC5_INST_TLB_MISS
, 0 },
64 { "l1cache-ins-miss", PMC5_INST_CACHE_MISS
, 0 },
65 { "l1cache-data-miss", PMC5_DATA_RW_MISS
, 0 },
66 { "l1cache-data-miss-read", PMC5_DATA_READ_MISS
, 0 },
67 { "l1cache-data-miss-write", PMC5_DATA_WRITE_MISS
, 0 },
68 { "l1cache-writeback", PMC5_DATA_LINES_WBACK
, 0 },
69 { "l1cache-writeback-hit", PMC5_WRITE_M_E
, 0 },
70 { "l2cache-data-snoop", PMC5_DATA_CACHE_SNOOP
, 0 },
71 { "l2cache-data-snoop-hit", PMC5_DATA_CACHE_SNOOP_HIT
, 0 },
72 { "mem-read", PMC5_DATA_READ
, 0 },
73 { "mem-write", PMC5_DATA_WRITE
, 0 },
74 { "mem-access", PMC5_DATA_RW
, 0 },
75 { "mem-access-both-pipes", PMC5_MEM_ACCESS_BOTH_PIPES
, 0 },
76 { "mem-bank-conflicts", PMC5_BANK_CONFLICTS
, 0 },
77 { "mem-misalign-ref", PMC5_MISALIGNED_DATA
, 0 },
78 { "mem-uncached-read", PMC5_NONCACHE_MEM_READ
, 0 },
79 { "seg-load-any", PMC5_SEGMENT_REG_LOAD
, 0 },
80 { "branch", PMC5_BRANCHES
, 0 },
81 { "branch-btb-hit", PMC5_BTB_HITS
, 0 },
82 { "branch-taken", PMC5_BRANCH_TAKEN
, 0 },
83 { "ins-read", PMC5_INST_READ
, 0 },
84 { "ins-pipeline-flush", PMC5_PIPELINE_FLUSH
, 0 },
85 { "ins-executed", PMC5_INST_EXECUTED
, 0 },
86 { "ins-executed-vpipe", PMC5_INST_EXECUTED_V_PIPE
, 0 },
87 { "ins-stall-agi", PMC5_AGI_STALL
, 0 },
88 { "ins-stall-write", PMC5_WRITE_BACKUP_STALL
, 0 },
89 { "ins-stall-data", PMC5_DATA_READ_STALL
, 0 },
90 { "ins-stall-writeline", PMC5_WRITE_E_M_STALL
, 0 },
91 { "bus-utilization", PMC5_BUS_UTILIZATION
, 0 },
92 { "bus-locked", PMC5_LOCKED_BUS
, 0 },
93 { "bus-io-cycle", PMC5_IO_CYCLE
, 0 },
94 { "fpu-flops", PMC5_FLOPS
, 0 },
95 { "int-hw", PMC5_HARDWARE_INTR
, 0 },
96 { "break-match0", PMC5_BP0_MATCH
, 0 },
97 { "break-match1", PMC5_BP1_MATCH
, 0 },
98 { "break-match2", PMC5_BP2_MATCH
, 0 },
99 { "break-match3", PMC5_BP3_MATCH
, 0 },
102 static const struct pmc_name2val i686_names
[] = {
103 { "mem-refs", PMC6_DATA_MEM_REFS
, 0 },
104 { "l1cache-lines", PMC6_DCU_LINES_IN
, 0 },
105 { "l1cache-mlines", PMC6_DCU_M_LINES_IN
, 0 },
106 { "l1cache-mlines-evict", PMC6_DCU_M_LINES_OUT
, 0 },
107 { "l1cache-miss-wait", PMC6_DCU_MISS_OUTSTANDING
, 0 },
108 { "ins-fetch", PMC6_IFU_IFETCH
, 0 },
109 { "ins-fetch-misses", PMC6_IFU_IFETCH_MISS
, 0 },
110 { "itlb-misses", PMC6_IFU_IFETCH_MISS
, 0 },
111 { "insfetch-mem-stall", PMC6_IFU_MEM_STALL
, 0 },
112 { "insfetch-decode-stall", PMC6_ILD_STALL
, 0 },
113 { "l2cache-insfetch", PMC6_L2_IFETCH
, 0x0f },
114 { "l2cache-data-loads", PMC6_L2_LD
, 0x0f },
115 { "l2cache-data-stores", PMC6_L2_ST
, 0x0f },
116 { "l2cache-lines", PMC6_L2_LINES_IN
, 0 },
117 { "l2cache-lines-evict", PMC6_L2_LINES_OUT
, 0 },
118 { "l2cache-mlines", PMC6_L2_M_LINES_INM
, 0 },
119 { "l2cache-mlines-evict", PMC6_L2_M_LINES_OUTM
, 0x0f },
120 { "l2cache-reqs", PMC6_L2_RQSTS
, 0 },
121 { "l2cache-addr-strobes", PMC6_L2_ADS
, 0 },
122 { "l2cache-data-busy", PMC6_L2_DBUS_BUSY
, 0 },
123 { "l2cache-data-busy-read", PMC6_L2_DBUS_BUSY_RD
, 0 },
124 { "bus-drdy-clocks-self", PMC6_BUS_DRDY_CLOCKS
, 0x00 },
125 { "bus-drdy-clocks-any", PMC6_BUS_DRDY_CLOCKS
, 0x20 },
126 { "bus-lock-clocks-self", PMC6_BUS_LOCK_CLOCKS
, 0x00 },
127 { "bus-lock-clocks-any", PMC6_BUS_LOCK_CLOCKS
, 0x20 },
128 { "bus-req-outstanding-self", PMC6_BUS_REQ_OUTSTANDING
, 0x00 },
129 { "bus-req-outstanding-any", PMC6_BUS_REQ_OUTSTANDING
, 0x20 },
130 { "bus-burst-reads-self", PMC6_BUS_TRAN_BRD
, 0x00 },
131 { "bus-burst-reads-any", PMC6_BUS_TRAN_BRD
, 0x20 },
132 { "bus-read-for-ownership-self",PMC6_BUS_TRAN_RFO
, 0x00 },
133 { "bus-read-for-ownership-any", PMC6_BUS_TRAN_RFO
, 0x20 },
134 { "bus-write-back-self", PMC6_BUS_TRANS_WB
, 0x00 },
135 { "bus-write-back-any", PMC6_BUS_TRANS_WB
, 0x20 },
136 { "bus-ins-fetches-self", PMC6_BUS_TRAN_IFETCH
, 0x00 },
137 { "bus-ins-fetches-any", PMC6_BUS_TRAN_IFETCH
, 0x20 },
138 { "bus-invalidates-self", PMC6_BUS_TRAN_INVAL
, 0x00 },
139 { "bus-invalidates-any", PMC6_BUS_TRAN_INVAL
, 0x20 },
140 { "bus-partial-writes-self", PMC6_BUS_TRAN_PWR
, 0x00 },
141 { "bus-partial-writes-any", PMC6_BUS_TRAN_PWR
, 0x20 },
142 { "bus-partial-trans-self", PMC6_BUS_TRANS_P
, 0x00 },
143 { "bus-partial-trans-any", PMC6_BUS_TRANS_P
, 0x20 },
144 { "bus-io-trans-self", PMC6_BUS_TRANS_IO
, 0x00 },
145 { "bus-io-trans-any", PMC6_BUS_TRANS_IO
, 0x20 },
146 { "bus-deferred-trans-self", PMC6_BUS_TRAN_DEF
, 0x00 },
147 { "bus-deferred-trans-any", PMC6_BUS_TRAN_DEF
, 0x20 },
148 { "bus-burst-trans-self", PMC6_BUS_TRAN_BURST
, 0x00 },
149 { "bus-burst-trans-any", PMC6_BUS_TRAN_BURST
, 0x20 },
150 { "bus-total-trans-self", PMC6_BUS_TRAN_ANY
, 0x00 },
151 { "bus-total-trans-any", PMC6_BUS_TRAN_ANY
, 0x20 },
152 { "bus-mem-trans-self", PMC6_BUS_TRAN_MEM
, 0x00 },
153 { "bus-mem-trans-any", PMC6_BUS_TRAN_MEM
, 0x20 },
154 { "bus-recv-cycles", PMC6_BUS_DATA_RCV
, 0 },
155 { "bus-bnr-cycles", PMC6_BUS_BNR_DRV
, 0 },
156 { "bus-hit-cycles", PMC6_BUS_HIT_DRV
, 0 },
157 { "bus-hitm-cycles", PMC6_BUS_HITM_DRDV
, 0 },
158 { "bus-snoop-stall", PMC6_BUS_SNOOP_STALL
, 0 },
159 { "fpu-flops", PMC6_FLOPS
, 0 },
160 { "fpu-comp-ops", PMC6_FP_COMP_OPS_EXE
, 0 },
161 { "fpu-except-assist", PMC6_FP_ASSIST
, 0 },
162 { "fpu-mul", PMC6_MUL
, 0 },
163 { "fpu-div", PMC6_DIV
, 0 },
164 { "fpu-div-busy", PMC6_CYCLES_DIV_BUSY
, 0 },
165 { "mem-sb-blocks", PMC6_LD_BLOCKS
, 0 },
166 { "mem-sb-drains", PMC6_SB_DRAINS
, 0 },
167 { "mem-misalign-ref", PMC6_MISALIGN_MEM_REF
, 0 },
168 { "ins-pref-dispatch-nta", PMC6_EMON_KNI_PREF_DISPATCHED
, 0x01 },
169 { "ins-pref-dispatch-t1", PMC6_EMON_KNI_PREF_DISPATCHED
, 0x01 },
170 { "ins-pref-dispatch-t2", PMC6_EMON_KNI_PREF_DISPATCHED
, 0x02 },
171 { "ins-pref-dispatch-weak", PMC6_EMON_KNI_PREF_DISPATCHED
, 0x03 },
172 { "ins-pref-miss-nta", PMC6_EMON_KNI_PREF_MISS
, 0x01 },
173 { "ins-pref-miss-t1", PMC6_EMON_KNI_PREF_MISS
, 0x01 },
174 { "ins-pref-miss-t2", PMC6_EMON_KNI_PREF_MISS
, 0x02 },
175 { "ins-pref-miss-weak", PMC6_EMON_KNI_PREF_MISS
, 0x03 },
176 { "ins-retired", PMC6_INST_RETIRED
, 0 },
177 { "uops-retired", PMC6_UOPS_RETIRED
, 0 },
178 { "ins-decoded", PMC6_INST_DECODED
, 0 },
179 { "ins-stream-retired-packed-scalar",
180 PMC6_EMON_KNI_INST_RETIRED
, 0x00 },
181 { "ins-stream-retired-scalar",
182 PMC6_EMON_KNI_INST_RETIRED
, 0x01 },
183 { "ins-stream-comp-retired-packed-scalar",
184 PMC6_EMON_KNI_COMP_INST_RET
, 0x00 },
185 { "ins-stream-comp-retired--scalar",
186 PMC6_EMON_KNI_COMP_INST_RET
, 0x01 },
187 { "int-hw", PMC6_HW_INT_RX
, 0 },
188 { "int-cycles-masked", PMC6_CYCLES_INT_MASKED
, 0 },
189 { "int-cycles-masked-pending",
190 PMC6_CYCLES_INT_PENDING_AND_MASKED
, 0 },
191 { "branch-retired", PMC6_BR_INST_RETIRED
, 0 },
192 { "branch-miss-retired", PMC6_BR_MISS_PRED_RETIRED
, 0 },
193 { "branch-taken-retired", PMC6_BR_TAKEN_RETIRED
, 0 },
194 { "branch-taken-mispred-retired", PMC6_BR_MISS_PRED_TAKEN_RET
, 0 },
195 { "branch-decoded", PMC6_BR_INST_DECODED
, 0 },
196 { "branch-btb-miss", PMC6_BTB_MISSES
, 0 },
197 { "branch-bogus", PMC6_BR_BOGUS
, 0 },
198 { "branch-baclear", PMC6_BACLEARS
, 0 },
199 { "stall-resource", PMC6_RESOURCE_STALLS
, 0 },
200 { "stall-partial", PMC6_PARTIAL_RAT_STALLS
, 0 },
201 { "seg-loads", PMC6_SEGMENT_REG_LOADS
, 0 },
202 { "unhalted-cycles", PMC6_CPU_CLK_UNHALTED
, 0 },
203 { "mmx-exec", PMC6_MMX_INSTR_EXEC
, 0 },
204 { "mmx-sat-exec", PMC6_MMX_SAT_INSTR_EXEC
, 0 },
205 { "mmx-uops-exec", PMC6_MMX_UOPS_EXEC
, 0x0f },
206 { "mmx-exec-packed-mul", PMC6_MMX_INSTR_TYPE_EXEC
, 0x01 },
207 { "mmx-exec-packed-shift", PMC6_MMX_INSTR_TYPE_EXEC
, 0x02 },
208 { "mmx-exec-pack-ops", PMC6_MMX_INSTR_TYPE_EXEC
, 0x04 },
209 { "mmx-exec-unpack-ops", PMC6_MMX_INSTR_TYPE_EXEC
, 0x08 },
210 { "mmx-exec-packed-logical", PMC6_MMX_INSTR_TYPE_EXEC
, 0x10 },
211 { "mmx-exec-packed-arith", PMC6_MMX_INSTR_TYPE_EXEC
, 0x20 },
212 { "mmx-trans-mmx-float", PMC6_FP_MMX_TRANS
, 0x00 },
213 { "mmx-trans-float-mmx", PMC6_FP_MMX_TRANS
, 0x01 },
214 { "mmx-assist", PMC6_MMX_ASSIST
, 0 },
215 { "mmx-retire", PMC6_MMX_INSTR_RET
, 0 },
216 { "seg-rename-stalls-es", PMC6_SEG_RENAME_STALLS
, 0x01 },
217 { "seg-rename-stalls-ds", PMC6_SEG_RENAME_STALLS
, 0x02 },
218 { "seg-rename-stalls-fs", PMC6_SEG_RENAME_STALLS
, 0x04 },
219 { "seg-rename-stalls-gs", PMC6_SEG_RENAME_STALLS
, 0x08 },
220 { "seg-rename-stalls-all", PMC6_SEG_RENAME_STALLS
, 0x0f },
221 { "seg-rename-es", PMC6_SEG_REG_RENAMES
, 0x01 },
222 { "seg-rename-ds", PMC6_SEG_REG_RENAMES
, 0x02 },
223 { "seg-rename-fs", PMC6_SEG_REG_RENAMES
, 0x04 },
224 { "seg-rename-gs", PMC6_SEG_REG_RENAMES
, 0x08 },
225 { "seg-rename-all", PMC6_SEG_REG_RENAMES
, 0x0f },
226 { "seg-rename-retire", PMC6_RET_SEG_RENAMES
, 0 },
229 static const struct pmc_name2val k7_names
[] = {
230 { "seg-load-all", K7_SEGMENT_REG_LOADS
, 0x7f },
231 { "seg-load-es", K7_SEGMENT_REG_LOADS
, 0x01 },
232 { "seg-load-cs", K7_SEGMENT_REG_LOADS
, 0x02 },
233 { "seg-load-ss", K7_SEGMENT_REG_LOADS
, 0x04 },
234 { "seg-load-ds", K7_SEGMENT_REG_LOADS
, 0x08 },
235 { "seg-load-fs", K7_SEGMENT_REG_LOADS
, 0x10 },
236 { "seg-load-gs", K7_SEGMENT_REG_LOADS
, 0x20 },
237 { "seg-load-hs", K7_SEGMENT_REG_LOADS
, 0x40 },
238 { "seg-load-stall", K7_SEGMENT_LOAD_STALL
, 0 },
239 { "l1cache-access", K7_DATA_CACHE_ACCESS
, 0 },
240 { "l1cache-miss", K7_DATA_CACHE_MISS
, 0 },
241 { "l1cache-refill", K7_DATA_CACHE_REFILL
, 0x1f },
242 { "l1cache-refill-invalid", K7_DATA_CACHE_REFILL
, 0x01 },
243 { "l1cache-refill-shared", K7_DATA_CACHE_REFILL
, 0x02 },
244 { "l1cache-refill-exclusive", K7_DATA_CACHE_REFILL
, 0x04 },
245 { "l1cache-refill-owner", K7_DATA_CACHE_REFILL
, 0x08 },
246 { "l1cache-refill-modified", K7_DATA_CACHE_REFILL
, 0x10 },
247 { "l1cache-load", K7_DATA_CACHE_REFILL_SYSTEM
, 0x1f },
248 { "l1cache-load-invalid", K7_DATA_CACHE_REFILL_SYSTEM
, 0x01 },
249 { "l1cache-load-shared", K7_DATA_CACHE_REFILL_SYSTEM
, 0x02 },
250 { "l1cache-load-exclusive", K7_DATA_CACHE_REFILL_SYSTEM
, 0x04 },
251 { "l1cache-load-owner", K7_DATA_CACHE_REFILL_SYSTEM
, 0x08 },
252 { "l1cache-load-modified", K7_DATA_CACHE_REFILL_SYSTEM
, 0x10 },
253 { "l1cache-writeback", K7_DATA_CACHE_WBACK
, 0x1f },
254 { "l1cache-writeback-invalid", K7_DATA_CACHE_WBACK
, 0x01 },
255 { "l1cache-writeback-shared", K7_DATA_CACHE_WBACK
, 0x02 },
256 { "l1cache-writeback-exclusive",K7_DATA_CACHE_WBACK
, 0x04 },
257 { "l1cache-writeback-owner", K7_DATA_CACHE_WBACK
, 0x08 },
258 { "l1cache-writeback-modified", K7_DATA_CACHE_WBACK
, 0x10 },
259 { "l2cache-access", K7_L2_REQUEST
, 0xff },
260 { "l2cache-tag-read", K7_L2_REQUEST
, 0x01 },
261 { "l2cache-tag-write", K7_L2_REQUEST
, 0x02 },
262 { "l2cache-inst-read", K7_L2_REQUEST
, 0x04 },
263 { "l2cache-inst-load", K7_L2_REQUEST
, 0x08 },
264 { "l2cache-data-store", K7_L2_REQUEST
, 0x10 },
265 { "l2cache-data-loadmem", K7_L2_REQUEST
, 0x20 },
266 { "l2cache-data-write", K7_L2_REQUEST
, 0x40 },
267 { "l2cache-data-move", K7_L2_REQUEST
, 0x80 },
268 { "l2cache-access-busy", K7_L2_REQUEST_BUSY
, 0 },
269 { "l2cache-hit", K7_L2_DTLB_HIT
, 0 },
270 { "l2cache-miss", K7_L2_DTLB_MISS
, 0 },
271 { "mem-misalign-ref", K7_MISALIGNED_DATA_REF
, 0 },
272 { "mem-access", K7_SYSTEM_REQUEST
, 0 },
273 { "mem-access-uc", K7_SYSTEM_REQUEST_TYPE
, 0x01 },
274 { "mem-access-wc", K7_SYSTEM_REQUEST_TYPE
, 0x04 },
275 { "mem-access-wt", K7_SYSTEM_REQUEST_TYPE
, 0x10 },
276 { "mem-access-wp", K7_SYSTEM_REQUEST_TYPE
, 0x20 },
277 { "mem-access-wb", K7_SYSTEM_REQUEST_TYPE
, 0x40 },
278 { "ins-fetch", K7_IFU_IFETCH
, 0 },
279 { "ins-fetch-miss", K7_IFU_IFETCH_MISS
, 0 },
280 { "ins-refill-l2", K7_IFU_REFILL_FROM_L2
, 0 },
281 { "ins-refill-mem", K7_IFU_REFILL_FROM_SYSTEM
, 0 },
282 { "ins-fetch-stall", K7_IFU_STALL
, 0 },
283 { "ins-retired", K7_RETIRED_INST
, 0 },
284 { "ins-empty", K7_INSTRUCTION_DECODER_EMPTY
, 0 },
285 { "itlb-miss-l1", K7_ITLB_L1_MISS
, 0 },
286 { "itlb-miss-l2", K7_ITLB_L2_MISS
, 0 },
287 { "ops-retired", K7_RETIRED_OPS
, 0 },
288 { "branch-retired", K7_RETIRED_BRANCHES
, 0 },
289 { "branch-miss-retired", K7_RETIRED_BRANCH_MISPREDICTED
, 0 },
290 { "branch-taken-retired", K7_RETIRED_TAKEN_BRANCH
, 0 },
291 { "branch-taked-miss-retired",
292 K7_RETIRED_TAKEN_BRANCH_MISPREDICTED
, 0 },
293 { "branch-far-retired",
294 K7_RETIRED_FAR_CONTROL_TRANSFER
, 0 },
295 { "branch-resync-retired", K7_RETIRED_RESYNC_BRANCH
, 0 },
296 { "branch-near-retired", K7_RETIRED_NEAR_RETURNS
, 0 },
297 { "branch-near-miss-retired",
298 K7_RETIRED_NEAR_RETURNS_MISPREDICTED
, 0 },
299 { "branch-indirect-miss-retired",
300 K7_RETIRED_INDIRECT_MISPREDICTED
, 0 },
301 { "int-hw", K7_HW_INTR_RECV
, 0 },
302 { "int-cycles-masked", K7_CYCLES_INT_MASKED
, 0 },
303 { "int-cycles-masked-pending",
304 K7_CYCLES_INT_PENDING_AND_MASKED
, 0 },
305 { "break-match0", K7_BP0_MATCH
, 0 },
306 { "break-match1", K7_BP1_MATCH
, 0 },
307 { "break-match2", K7_BP2_MATCH
, 0 },
308 { "break-match3", K7_BP3_MATCH
, 0 },
311 static struct pmc_name2val_cpus
{
313 const struct pmc_name2val
*pmc_names
;
316 { PMC_TYPE_I586
, i586_names
,
317 sizeof(i586_names
)/sizeof(struct pmc_name2val
) },
318 { PMC_TYPE_I686
, i686_names
,
319 sizeof(i686_names
)/sizeof(struct pmc_name2val
) },
320 { PMC_TYPE_K7
, k7_names
,
321 sizeof(k7_names
)/sizeof(struct pmc_name2val
) },
325 static const struct pmc_name2val_cpus
*
326 pmc_lookup_cpu(int type
)
330 for (i
= 0; i
< sizeof(pmc_cpus
)/sizeof(struct pmc_name2val_cpus
);
332 if (pmc_cpus
[i
].type
== type
)
333 return (&pmc_cpus
[i
]);
339 static const struct pmc_name2val
*
340 find_pmc_name(const struct pmc_name2val_cpus
*pncp
, const char *name
)
343 const struct pmc_name2val
*pnp
= NULL
;
345 for (i
= 0; i
< pncp
->size
; i
++) {
346 if (strcmp(pncp
->pmc_names
[i
].name
, name
) == 0) {
347 pnp
= &pncp
->pmc_names
[i
];
356 list_pmc_names(const struct pmc_name2val_cpus
*pncp
)
358 int i
, n
, left
, pairs
;
360 (void)printf("Supported performance counter events:\n");
365 for (i
= 0; i
< pairs
; i
++)
366 (void)printf(" %37s %37s\n", pncp
->pmc_names
[i
* 2].name
,
367 pncp
->pmc_names
[i
* 2 + 1].name
);
369 (void)printf("\t%37s\n", pncp
->pmc_names
[n
- 1].name
);
372 static void usage(void) __dead
;
373 static void usage(void)
376 (void)fprintf(stderr
, "usage: %s -h\n"
378 " %s -c <event> command [options] ...\n",
379 getprogname(), getprogname(), getprogname());
384 main(int argc
, char **argv
)
386 int c
, status
, ret0
, ret1
, errn0
, errn1
;
387 const char * volatile event
= "unknown";
388 const struct pmc_name2val_cpus
*pncp
;
389 const struct pmc_name2val
*pnp
;
390 struct i386_pmc_info_args pi
;
391 struct i386_pmc_startstop_args pss0
, pss1
;
392 struct i386_pmc_read_args pr0
, pr1
;
395 setprogname(argv
[0]);
398 if (i386_pmc_info(&pi
) < 0)
399 errx(2, "PMC support is not compiled into the kernel");
401 pncp
= pmc_lookup_cpu(pi
.type
);
403 errx(3, "PMC counters are not supported for your CPU (0x%x)",
407 while ((c
= getopt(argc
, argv
, "Cc:h")) != -1) {
413 * Just clear both counters. Useful if
414 * a previous run got killed and did not
417 (void)memset(&pss0
, 0, sizeof pss0
);
418 (void)i386_pmc_startstop(&pss0
);
420 (void)i386_pmc_startstop(&pss0
);
424 pnp
= find_pmc_name(pncp
, event
);
429 list_pmc_names(pncp
);
436 if (pnp
== NULL
|| argc
<= optind
)
439 (void)memset(&pss0
, 0, sizeof pss0
);
440 (void)memset(&pss1
, 0, sizeof pss1
);
441 pss0
.event
= pss1
.event
= pnp
->val
;
442 pss0
.unit
= pss1
.unit
= pnp
->unit
;
443 pss0
.flags
= PMC_SETUP_USER
;
445 pss1
.flags
= PMC_SETUP_KERNEL
;
449 * XXX should catch signals and tidy up in the parent.
451 if (i386_pmc_startstop(&pss0
) < 0)
452 err(4, "pmc_start user");
454 if (i386_pmc_startstop(&pss1
) < 0)
455 err(5, "pmc_start kernel");
464 (void)execvp(argv
[optind
], &argv
[optind
]);
468 (void)signal(SIGINT
, SIG_IGN
);
469 (void)signal(SIGQUIT
, SIG_IGN
);
471 if (waitpid(pid
, &status
, 0) == -1)
473 if (!WIFEXITED(status
))
477 * Do not immediately exit on errors below. The counters
478 * must be stopped first, or subsequent runs will get
482 ret0
= i386_pmc_read(&pr0
);
486 ret1
= i386_pmc_read(&pr1
);
490 if (i386_pmc_startstop(&pss0
) < 0)
491 warn("pmc_stop user");
492 if (i386_pmc_startstop(&pss1
) < 0)
493 warn("pmc_stop kernel");
504 (void)printf("%s: user %llu kernel %llu\n", event
, pr0
.val
, pr1
.val
);