1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate *
4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate * with the License.
8*7c478bd9Sstevel@tonic-gate *
9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate *
14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate *
20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate */
26*7c478bd9Sstevel@tonic-gate
27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
28*7c478bd9Sstevel@tonic-gate
29*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
30*7c478bd9Sstevel@tonic-gate #include <string.h>
31*7c478bd9Sstevel@tonic-gate #include <alloca.h>
32*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
33*7c478bd9Sstevel@tonic-gate #include <stdio.h>
34*7c478bd9Sstevel@tonic-gate #include <libintl.h>
35*7c478bd9Sstevel@tonic-gate
36*7c478bd9Sstevel@tonic-gate #include "libcpc.h"
37*7c478bd9Sstevel@tonic-gate #include "libcpc_impl.h"
38*7c478bd9Sstevel@tonic-gate
39*7c478bd9Sstevel@tonic-gate /*
40*7c478bd9Sstevel@tonic-gate * Configuration data for Pentium Pro performance counters.
41*7c478bd9Sstevel@tonic-gate *
42*7c478bd9Sstevel@tonic-gate * Definitions taken from [3]. See the reference to
43*7c478bd9Sstevel@tonic-gate * understand what any of these settings actually means.
44*7c478bd9Sstevel@tonic-gate *
45*7c478bd9Sstevel@tonic-gate * [3] "Pentium Pro Family Developer's Manual, Volume 3:
46*7c478bd9Sstevel@tonic-gate * Operating Systems Writer's Manual," January 1996
47*7c478bd9Sstevel@tonic-gate */
48*7c478bd9Sstevel@tonic-gate
49*7c478bd9Sstevel@tonic-gate #define V_P5 (1u << 0) /* specific to Pentium cpus */
50*7c478bd9Sstevel@tonic-gate #define V_P5mmx (1u << 1) /* " MMX instructions */
51*7c478bd9Sstevel@tonic-gate #define V_P6 (1u << 2) /* specific to Pentium II cpus */
52*7c478bd9Sstevel@tonic-gate #define V_P6mmx (1u << 3) /* " MMX instructions */
53*7c478bd9Sstevel@tonic-gate #define V_END 0
54*7c478bd9Sstevel@tonic-gate
55*7c478bd9Sstevel@tonic-gate /*
56*7c478bd9Sstevel@tonic-gate * map from "cpu version" to flag bits
57*7c478bd9Sstevel@tonic-gate */
58*7c478bd9Sstevel@tonic-gate static const uint_t cpuvermap[] = {
59*7c478bd9Sstevel@tonic-gate V_P5, /* CPC_PENTIUM */
60*7c478bd9Sstevel@tonic-gate V_P5 | V_P5mmx, /* CPC_PENTIUM_MMX */
61*7c478bd9Sstevel@tonic-gate V_P6, /* CPC_PENTIUM_PRO */
62*7c478bd9Sstevel@tonic-gate V_P6 | V_P6mmx, /* CPC_PENTIUM_PRO_MMX */
63*7c478bd9Sstevel@tonic-gate };
64*7c478bd9Sstevel@tonic-gate
65*7c478bd9Sstevel@tonic-gate struct nametable {
66*7c478bd9Sstevel@tonic-gate const uint_t ver;
67*7c478bd9Sstevel@tonic-gate const uint8_t bits;
68*7c478bd9Sstevel@tonic-gate const char *name;
69*7c478bd9Sstevel@tonic-gate };
70*7c478bd9Sstevel@tonic-gate
71*7c478bd9Sstevel@tonic-gate /*
72*7c478bd9Sstevel@tonic-gate * Basic Pentium events
73*7c478bd9Sstevel@tonic-gate */
74*7c478bd9Sstevel@tonic-gate #define P5_EVENTS(v) \
75*7c478bd9Sstevel@tonic-gate {v, 0x0, "data_read"}, \
76*7c478bd9Sstevel@tonic-gate {v, 0x1, "data_write"}, \
77*7c478bd9Sstevel@tonic-gate {v, 0x2, "data_tlb_miss"}, \
78*7c478bd9Sstevel@tonic-gate {v, 0x3, "data_read_miss"}, \
79*7c478bd9Sstevel@tonic-gate {v, 0x4, "data_write_miss"}, \
80*7c478bd9Sstevel@tonic-gate {v, 0x5, "write_hit_to_M_or_E"}, \
81*7c478bd9Sstevel@tonic-gate {v, 0x6, "dcache_lines_wrback"}, \
82*7c478bd9Sstevel@tonic-gate {v, 0x7, "external_snoops"}, \
83*7c478bd9Sstevel@tonic-gate {v, 0x8, "external_dcache_snoop_hits"}, \
84*7c478bd9Sstevel@tonic-gate {v, 0x9, "memory_access_in_both_pipes"}, \
85*7c478bd9Sstevel@tonic-gate {v, 0xa, "bank_conflicts"}, \
86*7c478bd9Sstevel@tonic-gate {v, 0xb, "misaligned_ref"}, \
87*7c478bd9Sstevel@tonic-gate {v, 0xc, "code_read"}, \
88*7c478bd9Sstevel@tonic-gate {v, 0xd, "code_tlb_miss"}, \
89*7c478bd9Sstevel@tonic-gate {v, 0xe, "code_cache_miss"}, \
90*7c478bd9Sstevel@tonic-gate {v, 0xf, "any_segreg_loaded"}, \
91*7c478bd9Sstevel@tonic-gate {v, 0x12, "branches"}, \
92*7c478bd9Sstevel@tonic-gate {v, 0x13, "btb_hits"}, \
93*7c478bd9Sstevel@tonic-gate {v, 0x14, "taken_or_btb_hit"}, \
94*7c478bd9Sstevel@tonic-gate {v, 0x15, "pipeline_flushes"}, \
95*7c478bd9Sstevel@tonic-gate {v, 0x16, "instr_exec"}, \
96*7c478bd9Sstevel@tonic-gate {v, 0x17, "instr_exec_V_pipe"}, \
97*7c478bd9Sstevel@tonic-gate {v, 0x18, "clks_bus_cycle"}, \
98*7c478bd9Sstevel@tonic-gate {v, 0x19, "clks_full_wbufs"}, \
99*7c478bd9Sstevel@tonic-gate {v, 0x1a, "pipe_stall_read"}, \
100*7c478bd9Sstevel@tonic-gate {v, 0x1b, "stall_on_write_ME"}, \
101*7c478bd9Sstevel@tonic-gate {v, 0x1c, "locked_bus_cycle"}, \
102*7c478bd9Sstevel@tonic-gate {v, 0x1d, "io_rw_cycles"}, \
103*7c478bd9Sstevel@tonic-gate {v, 0x1e, "reads_noncache_mem"}, \
104*7c478bd9Sstevel@tonic-gate {v, 0x1f, "pipeline_agi_stalls"}, \
105*7c478bd9Sstevel@tonic-gate {v, 0x22, "flops"}, \
106*7c478bd9Sstevel@tonic-gate {v, 0x23, "bp_match_dr0"}, \
107*7c478bd9Sstevel@tonic-gate {v, 0x24, "bp_match_dr1"}, \
108*7c478bd9Sstevel@tonic-gate {v, 0x25, "bp_match_dr2"}, \
109*7c478bd9Sstevel@tonic-gate {v, 0x26, "bp_match_dr3"}, \
110*7c478bd9Sstevel@tonic-gate {v, 0x27, "hw_intrs"}, \
111*7c478bd9Sstevel@tonic-gate {v, 0x28, "data_rw"}, \
112*7c478bd9Sstevel@tonic-gate {v, 0x29, "data_rw_miss"}
113*7c478bd9Sstevel@tonic-gate
114*7c478bd9Sstevel@tonic-gate static const struct nametable P5mmx_names0[] = {
115*7c478bd9Sstevel@tonic-gate P5_EVENTS(V_P5),
116*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x2a, "bus_ownership_latency"},
117*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x2b, "mmx_instr_upipe"},
118*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x2c, "cache_M_line_sharing"},
119*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x2d, "emms_instr"},
120*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x2e, "bus_util_processor"},
121*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x2f, "sat_mmx_instr"},
122*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x30, "clks_not_HLT"},
123*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x31, "mmx_data_read"},
124*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x32, "clks_fp_stall"},
125*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x33, "d1_starv_fifo_0"},
126*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x34, "mmx_data_write"},
127*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x35, "pipe_flush_wbp"},
128*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x36, "mmx_misalign_data_refs"},
129*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x37, "rets_pred_incorrect"},
130*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x38, "mmx_multiply_unit_interlock"},
131*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x39, "rets"},
132*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x3a, "btb_false_entries"},
133*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x3b, "clocks_stall_full_wb"},
134*7c478bd9Sstevel@tonic-gate {V_END}
135*7c478bd9Sstevel@tonic-gate };
136*7c478bd9Sstevel@tonic-gate
137*7c478bd9Sstevel@tonic-gate static const struct nametable P5mmx_names1[] = {
138*7c478bd9Sstevel@tonic-gate P5_EVENTS(V_P5),
139*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x2a, "bus_ownership_transfers"},
140*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x2b, "mmx_instr_vpipe"},
141*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x2c, "cache_lint_sharing"},
142*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x2d, "mmx_fp_transitions"},
143*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x2e, "writes_noncache_mem"},
144*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x2f, "sats_performed"},
145*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x30, "clks_dcache_tlb_miss"},
146*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x31, "mmx_data_read_miss"},
147*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x32, "taken_br"},
148*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x33, "d1_starv_fifo_1"},
149*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x34, "mmx_data_write_miss"},
150*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x35, "pipe_flush_wbp_wb"},
151*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x36, "mmx_pipe_stall_data_read"},
152*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x37, "rets_pred"},
153*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x38, "movd_movq_stall"},
154*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x39, "rsb_overflow"},
155*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x3a, "btb_mispred_nt"},
156*7c478bd9Sstevel@tonic-gate {V_P5mmx, 0x3b, "mmx_stall_write_ME"},
157*7c478bd9Sstevel@tonic-gate {V_END}
158*7c478bd9Sstevel@tonic-gate };
159*7c478bd9Sstevel@tonic-gate
160*7c478bd9Sstevel@tonic-gate static const struct nametable *P5mmx_names[2] = {
161*7c478bd9Sstevel@tonic-gate P5mmx_names0,
162*7c478bd9Sstevel@tonic-gate P5mmx_names1
163*7c478bd9Sstevel@tonic-gate };
164*7c478bd9Sstevel@tonic-gate
165*7c478bd9Sstevel@tonic-gate /*
166*7c478bd9Sstevel@tonic-gate * Pentium Pro and Pentium II events
167*7c478bd9Sstevel@tonic-gate */
168*7c478bd9Sstevel@tonic-gate static const struct nametable P6_names[] = {
169*7c478bd9Sstevel@tonic-gate /*
170*7c478bd9Sstevel@tonic-gate * Data cache unit
171*7c478bd9Sstevel@tonic-gate */
172*7c478bd9Sstevel@tonic-gate {V_P6, 0x43, "data_mem_refs"},
173*7c478bd9Sstevel@tonic-gate {V_P6, 0x45, "dcu_lines_in"},
174*7c478bd9Sstevel@tonic-gate {V_P6, 0x46, "dcu_m_lines_in"},
175*7c478bd9Sstevel@tonic-gate {V_P6, 0x47, "dcu_m_lines_out"},
176*7c478bd9Sstevel@tonic-gate {V_P6, 0x48, "dcu_miss_outstanding"},
177*7c478bd9Sstevel@tonic-gate
178*7c478bd9Sstevel@tonic-gate /*
179*7c478bd9Sstevel@tonic-gate * Instruction fetch unit
180*7c478bd9Sstevel@tonic-gate */
181*7c478bd9Sstevel@tonic-gate {V_P6, 0x80, "ifu_ifetch"},
182*7c478bd9Sstevel@tonic-gate {V_P6, 0x81, "ifu_ifetch_miss"},
183*7c478bd9Sstevel@tonic-gate {V_P6, 0x85, "itlb_miss"},
184*7c478bd9Sstevel@tonic-gate {V_P6, 0x86, "ifu_mem_stall"},
185*7c478bd9Sstevel@tonic-gate {V_P6, 0x87, "ild_stall"},
186*7c478bd9Sstevel@tonic-gate
187*7c478bd9Sstevel@tonic-gate /*
188*7c478bd9Sstevel@tonic-gate * L2 cache
189*7c478bd9Sstevel@tonic-gate */
190*7c478bd9Sstevel@tonic-gate {V_P6, 0x28, "l2_ifetch"},
191*7c478bd9Sstevel@tonic-gate {V_P6, 0x29, "l2_ld"},
192*7c478bd9Sstevel@tonic-gate {V_P6, 0x2a, "l2_st"},
193*7c478bd9Sstevel@tonic-gate {V_P6, 0x24, "l2_lines_in"},
194*7c478bd9Sstevel@tonic-gate {V_P6, 0x26, "l2_lines_out"},
195*7c478bd9Sstevel@tonic-gate {V_P6, 0x25, "l2_m_lines_inm"},
196*7c478bd9Sstevel@tonic-gate {V_P6, 0x27, "l2_m_lines_outm"},
197*7c478bd9Sstevel@tonic-gate {V_P6, 0x2e, "l2_rqsts"},
198*7c478bd9Sstevel@tonic-gate {V_P6, 0x21, "l2_ads"},
199*7c478bd9Sstevel@tonic-gate {V_P6, 0x22, "l2_dbus_busy"},
200*7c478bd9Sstevel@tonic-gate {V_P6, 0x23, "l2_dbus_busy_rd"},
201*7c478bd9Sstevel@tonic-gate
202*7c478bd9Sstevel@tonic-gate /*
203*7c478bd9Sstevel@tonic-gate * External bus logic
204*7c478bd9Sstevel@tonic-gate */
205*7c478bd9Sstevel@tonic-gate {V_P6, 0x62, "bus_drdy_clocks"},
206*7c478bd9Sstevel@tonic-gate {V_P6, 0x63, "bus_lock_clocks"},
207*7c478bd9Sstevel@tonic-gate {V_P6, 0x60, "bus_req_outstanding"},
208*7c478bd9Sstevel@tonic-gate {V_P6, 0x65, "bus_tran_brd"},
209*7c478bd9Sstevel@tonic-gate {V_P6, 0x66, "bus_tran_rfo"},
210*7c478bd9Sstevel@tonic-gate {V_P6, 0x67, "bus_trans_wb"},
211*7c478bd9Sstevel@tonic-gate {V_P6, 0x68, "bus_tran_ifetch"},
212*7c478bd9Sstevel@tonic-gate {V_P6, 0x69, "bus_tran_inval"},
213*7c478bd9Sstevel@tonic-gate {V_P6, 0x6a, "bus_tran_pwr"},
214*7c478bd9Sstevel@tonic-gate {V_P6, 0x6b, "bus_trans_p"},
215*7c478bd9Sstevel@tonic-gate {V_P6, 0x6c, "bus_trans_io"},
216*7c478bd9Sstevel@tonic-gate {V_P6, 0x6d, "bus_tran_def"},
217*7c478bd9Sstevel@tonic-gate {V_P6, 0x6e, "bus_tran_burst"},
218*7c478bd9Sstevel@tonic-gate {V_P6, 0x70, "bus_tran_any"},
219*7c478bd9Sstevel@tonic-gate {V_P6, 0x6f, "bus_tran_mem"},
220*7c478bd9Sstevel@tonic-gate {V_P6, 0x64, "bus_data_rcv"},
221*7c478bd9Sstevel@tonic-gate {V_P6, 0x61, "bus_bnr_drv"},
222*7c478bd9Sstevel@tonic-gate {V_P6, 0x7a, "bus_hit_drv"},
223*7c478bd9Sstevel@tonic-gate {V_P6, 0x7b, "bus_hitm_drv"},
224*7c478bd9Sstevel@tonic-gate {V_P6, 0x7e, "bus_snoop_stall"},
225*7c478bd9Sstevel@tonic-gate
226*7c478bd9Sstevel@tonic-gate /*
227*7c478bd9Sstevel@tonic-gate * Floating point unit
228*7c478bd9Sstevel@tonic-gate */
229*7c478bd9Sstevel@tonic-gate {V_P6, 0xc1, "flops"}, /* 0 only */
230*7c478bd9Sstevel@tonic-gate {V_P6, 0x10, "fp_comp_ops_exe"}, /* 0 only */
231*7c478bd9Sstevel@tonic-gate {V_P6, 0x11, "fp_assist"}, /* 1 only */
232*7c478bd9Sstevel@tonic-gate {V_P6, 0x12, "mul"}, /* 1 only */
233*7c478bd9Sstevel@tonic-gate {V_P6, 0x13, "div"}, /* 1 only */
234*7c478bd9Sstevel@tonic-gate {V_P6, 0x14, "cycles_div_busy"}, /* 0 only */
235*7c478bd9Sstevel@tonic-gate
236*7c478bd9Sstevel@tonic-gate /*
237*7c478bd9Sstevel@tonic-gate * Memory ordering
238*7c478bd9Sstevel@tonic-gate */
239*7c478bd9Sstevel@tonic-gate {V_P6, 0x3, "ld_blocks"},
240*7c478bd9Sstevel@tonic-gate {V_P6, 0x4, "sb_drains"},
241*7c478bd9Sstevel@tonic-gate {V_P6, 0x5, "misalign_mem_ref"},
242*7c478bd9Sstevel@tonic-gate
243*7c478bd9Sstevel@tonic-gate /*
244*7c478bd9Sstevel@tonic-gate * Instruction decoding and retirement
245*7c478bd9Sstevel@tonic-gate */
246*7c478bd9Sstevel@tonic-gate {V_P6, 0xc0, "inst_retired"},
247*7c478bd9Sstevel@tonic-gate {V_P6, 0xc2, "uops_retired"},
248*7c478bd9Sstevel@tonic-gate {V_P6, 0xd0, "inst_decoder"},
249*7c478bd9Sstevel@tonic-gate
250*7c478bd9Sstevel@tonic-gate /*
251*7c478bd9Sstevel@tonic-gate * Interrupts
252*7c478bd9Sstevel@tonic-gate */
253*7c478bd9Sstevel@tonic-gate {V_P6, 0xc8, "hw_int_rx"},
254*7c478bd9Sstevel@tonic-gate {V_P6, 0xc6, "cycles_int_masked"},
255*7c478bd9Sstevel@tonic-gate {V_P6, 0xc7, "cycles_int_pending_and_masked"},
256*7c478bd9Sstevel@tonic-gate
257*7c478bd9Sstevel@tonic-gate /*
258*7c478bd9Sstevel@tonic-gate * Branches
259*7c478bd9Sstevel@tonic-gate */
260*7c478bd9Sstevel@tonic-gate {V_P6, 0xc4, "br_inst_retired"},
261*7c478bd9Sstevel@tonic-gate {V_P6, 0xc5, "br_miss_pred_retired"},
262*7c478bd9Sstevel@tonic-gate {V_P6, 0xc9, "br_taken_retired"},
263*7c478bd9Sstevel@tonic-gate {V_P6, 0xca, "br_miss_pred_taken_ret"},
264*7c478bd9Sstevel@tonic-gate {V_P6, 0xe0, "br_inst_decoded"},
265*7c478bd9Sstevel@tonic-gate {V_P6, 0xe2, "btb_misses"},
266*7c478bd9Sstevel@tonic-gate {V_P6, 0xe4, "br_bogus"},
267*7c478bd9Sstevel@tonic-gate {V_P6, 0xe6, "baclears"},
268*7c478bd9Sstevel@tonic-gate
269*7c478bd9Sstevel@tonic-gate /*
270*7c478bd9Sstevel@tonic-gate * Stalls
271*7c478bd9Sstevel@tonic-gate */
272*7c478bd9Sstevel@tonic-gate {V_P6, 0xa2, "resource_stalls"},
273*7c478bd9Sstevel@tonic-gate {V_P6, 0xd2, "partial_rat_stalls"},
274*7c478bd9Sstevel@tonic-gate
275*7c478bd9Sstevel@tonic-gate /*
276*7c478bd9Sstevel@tonic-gate * Segment register loads
277*7c478bd9Sstevel@tonic-gate */
278*7c478bd9Sstevel@tonic-gate {V_P6, 0x6, "segment_reg_loads"},
279*7c478bd9Sstevel@tonic-gate
280*7c478bd9Sstevel@tonic-gate /*
281*7c478bd9Sstevel@tonic-gate * Clocks
282*7c478bd9Sstevel@tonic-gate */
283*7c478bd9Sstevel@tonic-gate {V_P6, 0x79, "cpu_clk_unhalted"},
284*7c478bd9Sstevel@tonic-gate
285*7c478bd9Sstevel@tonic-gate /*
286*7c478bd9Sstevel@tonic-gate * MMX
287*7c478bd9Sstevel@tonic-gate */
288*7c478bd9Sstevel@tonic-gate {V_P6mmx, 0xb0, "mmx_instr_exec"},
289*7c478bd9Sstevel@tonic-gate {V_P6mmx, 0xb1, "mmx_sat_instr_exec"},
290*7c478bd9Sstevel@tonic-gate {V_P6mmx, 0xb2, "mmx_uops_exec"},
291*7c478bd9Sstevel@tonic-gate {V_P6mmx, 0xb3, "mmx_instr_type_exec"},
292*7c478bd9Sstevel@tonic-gate {V_P6mmx, 0xcc, "fp_mmx_trans"},
293*7c478bd9Sstevel@tonic-gate {V_P6mmx, 0xcd, "mmx_assists"},
294*7c478bd9Sstevel@tonic-gate {V_P6mmx, 0xce, "mmx_instr_ret"},
295*7c478bd9Sstevel@tonic-gate {V_P6mmx, 0xd4, "seg_rename_stalls"},
296*7c478bd9Sstevel@tonic-gate {V_P6mmx, 0xd5, "seg_reg_renames"},
297*7c478bd9Sstevel@tonic-gate {V_P6mmx, 0xd6, "ret_seg_renames"},
298*7c478bd9Sstevel@tonic-gate
299*7c478bd9Sstevel@tonic-gate {V_END}
300*7c478bd9Sstevel@tonic-gate };
301*7c478bd9Sstevel@tonic-gate
302*7c478bd9Sstevel@tonic-gate #define MAPCPUVER(cpuver) (cpuvermap[(cpuver) - CPC_PENTIUM])
303*7c478bd9Sstevel@tonic-gate
304*7c478bd9Sstevel@tonic-gate static int
validargs(int cpuver,int regno)305*7c478bd9Sstevel@tonic-gate validargs(int cpuver, int regno)
306*7c478bd9Sstevel@tonic-gate {
307*7c478bd9Sstevel@tonic-gate if (regno < 0 || regno > 1)
308*7c478bd9Sstevel@tonic-gate return (0);
309*7c478bd9Sstevel@tonic-gate cpuver -= CPC_PENTIUM;
310*7c478bd9Sstevel@tonic-gate if (cpuver < 0 ||
311*7c478bd9Sstevel@tonic-gate cpuver >= sizeof (cpuvermap) / sizeof (cpuvermap[0]))
312*7c478bd9Sstevel@tonic-gate return (0);
313*7c478bd9Sstevel@tonic-gate return (1);
314*7c478bd9Sstevel@tonic-gate }
315*7c478bd9Sstevel@tonic-gate
316*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
317*7c478bd9Sstevel@tonic-gate static int
versionmatch(int cpuver,int regno,const struct nametable * n)318*7c478bd9Sstevel@tonic-gate versionmatch(int cpuver, int regno, const struct nametable *n)
319*7c478bd9Sstevel@tonic-gate {
320*7c478bd9Sstevel@tonic-gate if (!validargs(cpuver, regno) || (n->ver & MAPCPUVER(cpuver)) == 0)
321*7c478bd9Sstevel@tonic-gate return (0);
322*7c478bd9Sstevel@tonic-gate
323*7c478bd9Sstevel@tonic-gate switch (MAPCPUVER(cpuver)) {
324*7c478bd9Sstevel@tonic-gate case V_P5:
325*7c478bd9Sstevel@tonic-gate case V_P5 | V_P5mmx:
326*7c478bd9Sstevel@tonic-gate break;
327*7c478bd9Sstevel@tonic-gate case V_P6:
328*7c478bd9Sstevel@tonic-gate case V_P6 | V_P6mmx:
329*7c478bd9Sstevel@tonic-gate switch (n->bits) {
330*7c478bd9Sstevel@tonic-gate case 0xc1: /* flops */
331*7c478bd9Sstevel@tonic-gate case 0x10: /* fp_comp_ops_exe */
332*7c478bd9Sstevel@tonic-gate case 0x14: /* cycles_div_busy */
333*7c478bd9Sstevel@tonic-gate /* only reg0 counts these */
334*7c478bd9Sstevel@tonic-gate if (regno == 1)
335*7c478bd9Sstevel@tonic-gate return (0);
336*7c478bd9Sstevel@tonic-gate break;
337*7c478bd9Sstevel@tonic-gate case 0x11: /* fp_assist */
338*7c478bd9Sstevel@tonic-gate case 0x12: /* mul */
339*7c478bd9Sstevel@tonic-gate case 0x13: /* div */
340*7c478bd9Sstevel@tonic-gate /* only 1 can count these */
341*7c478bd9Sstevel@tonic-gate if (regno == 0)
342*7c478bd9Sstevel@tonic-gate return (0);
343*7c478bd9Sstevel@tonic-gate break;
344*7c478bd9Sstevel@tonic-gate default:
345*7c478bd9Sstevel@tonic-gate break;
346*7c478bd9Sstevel@tonic-gate }
347*7c478bd9Sstevel@tonic-gate break;
348*7c478bd9Sstevel@tonic-gate default:
349*7c478bd9Sstevel@tonic-gate return (0);
350*7c478bd9Sstevel@tonic-gate }
351*7c478bd9Sstevel@tonic-gate
352*7c478bd9Sstevel@tonic-gate return (1);
353*7c478bd9Sstevel@tonic-gate }
354*7c478bd9Sstevel@tonic-gate
355*7c478bd9Sstevel@tonic-gate static const struct nametable *
getnametable(int cpuver,int regno)356*7c478bd9Sstevel@tonic-gate getnametable(int cpuver, int regno)
357*7c478bd9Sstevel@tonic-gate {
358*7c478bd9Sstevel@tonic-gate const struct nametable *n;
359*7c478bd9Sstevel@tonic-gate
360*7c478bd9Sstevel@tonic-gate if (!validargs(cpuver, regno))
361*7c478bd9Sstevel@tonic-gate return (NULL);
362*7c478bd9Sstevel@tonic-gate
363*7c478bd9Sstevel@tonic-gate switch (MAPCPUVER(cpuver)) {
364*7c478bd9Sstevel@tonic-gate case V_P5:
365*7c478bd9Sstevel@tonic-gate case V_P5 | V_P5mmx:
366*7c478bd9Sstevel@tonic-gate n = P5mmx_names[regno];
367*7c478bd9Sstevel@tonic-gate break;
368*7c478bd9Sstevel@tonic-gate case V_P6:
369*7c478bd9Sstevel@tonic-gate case V_P6 | V_P6mmx:
370*7c478bd9Sstevel@tonic-gate n = P6_names;
371*7c478bd9Sstevel@tonic-gate break;
372*7c478bd9Sstevel@tonic-gate default:
373*7c478bd9Sstevel@tonic-gate n = NULL;
374*7c478bd9Sstevel@tonic-gate break;
375*7c478bd9Sstevel@tonic-gate }
376*7c478bd9Sstevel@tonic-gate
377*7c478bd9Sstevel@tonic-gate return (n);
378*7c478bd9Sstevel@tonic-gate }
379*7c478bd9Sstevel@tonic-gate
380*7c478bd9Sstevel@tonic-gate void
cpc_walk_names(int cpuver,int regno,void * arg,void (* action)(void *,int,const char *,uint8_t))381*7c478bd9Sstevel@tonic-gate cpc_walk_names(int cpuver, int regno, void *arg,
382*7c478bd9Sstevel@tonic-gate void (*action)(void *, int, const char *, uint8_t))
383*7c478bd9Sstevel@tonic-gate {
384*7c478bd9Sstevel@tonic-gate const struct nametable *n;
385*7c478bd9Sstevel@tonic-gate
386*7c478bd9Sstevel@tonic-gate if ((n = getnametable(cpuver, regno)) == NULL)
387*7c478bd9Sstevel@tonic-gate return;
388*7c478bd9Sstevel@tonic-gate for (; n->ver != V_END; n++)
389*7c478bd9Sstevel@tonic-gate if (versionmatch(cpuver, regno, n))
390*7c478bd9Sstevel@tonic-gate action(arg, regno, n->name, n->bits);
391*7c478bd9Sstevel@tonic-gate }
392*7c478bd9Sstevel@tonic-gate
393*7c478bd9Sstevel@tonic-gate const char *
__cpc_reg_to_name(int cpuver,int regno,uint8_t bits)394*7c478bd9Sstevel@tonic-gate __cpc_reg_to_name(int cpuver, int regno, uint8_t bits)
395*7c478bd9Sstevel@tonic-gate {
396*7c478bd9Sstevel@tonic-gate const struct nametable *n;
397*7c478bd9Sstevel@tonic-gate
398*7c478bd9Sstevel@tonic-gate if ((n = getnametable(cpuver, regno)) == NULL)
399*7c478bd9Sstevel@tonic-gate return (NULL);
400*7c478bd9Sstevel@tonic-gate for (; n->ver != V_END; n++)
401*7c478bd9Sstevel@tonic-gate if (bits == n->bits && versionmatch(cpuver, regno, n))
402*7c478bd9Sstevel@tonic-gate return (n->name);
403*7c478bd9Sstevel@tonic-gate return (NULL);
404*7c478bd9Sstevel@tonic-gate }
405*7c478bd9Sstevel@tonic-gate
406*7c478bd9Sstevel@tonic-gate /*
407*7c478bd9Sstevel@tonic-gate * Register names can be specified as strings or even as numbers
408*7c478bd9Sstevel@tonic-gate */
409*7c478bd9Sstevel@tonic-gate int
__cpc_name_to_reg(int cpuver,int regno,const char * name,uint8_t * bits)410*7c478bd9Sstevel@tonic-gate __cpc_name_to_reg(int cpuver, int regno, const char *name, uint8_t *bits)
411*7c478bd9Sstevel@tonic-gate {
412*7c478bd9Sstevel@tonic-gate const struct nametable *n;
413*7c478bd9Sstevel@tonic-gate char *eptr = NULL;
414*7c478bd9Sstevel@tonic-gate long value;
415*7c478bd9Sstevel@tonic-gate
416*7c478bd9Sstevel@tonic-gate if ((n = getnametable(cpuver, regno)) == NULL || name == NULL)
417*7c478bd9Sstevel@tonic-gate return (-1);
418*7c478bd9Sstevel@tonic-gate for (; n->ver != V_END; n++)
419*7c478bd9Sstevel@tonic-gate if (strcmp(name, n->name) == 0 &&
420*7c478bd9Sstevel@tonic-gate versionmatch(cpuver, regno, n)) {
421*7c478bd9Sstevel@tonic-gate *bits = n->bits;
422*7c478bd9Sstevel@tonic-gate return (0);
423*7c478bd9Sstevel@tonic-gate }
424*7c478bd9Sstevel@tonic-gate
425*7c478bd9Sstevel@tonic-gate value = strtol(name, &eptr, 0);
426*7c478bd9Sstevel@tonic-gate if (name != eptr && value >= 0 && value <= UINT8_MAX) {
427*7c478bd9Sstevel@tonic-gate *bits = (uint8_t)value;
428*7c478bd9Sstevel@tonic-gate return (0);
429*7c478bd9Sstevel@tonic-gate }
430*7c478bd9Sstevel@tonic-gate
431*7c478bd9Sstevel@tonic-gate return (-1);
432*7c478bd9Sstevel@tonic-gate }
433*7c478bd9Sstevel@tonic-gate
434*7c478bd9Sstevel@tonic-gate const char *
cpc_getcciname(int cpuver)435*7c478bd9Sstevel@tonic-gate cpc_getcciname(int cpuver)
436*7c478bd9Sstevel@tonic-gate {
437*7c478bd9Sstevel@tonic-gate if (validargs(cpuver, 0))
438*7c478bd9Sstevel@tonic-gate switch (MAPCPUVER(cpuver)) {
439*7c478bd9Sstevel@tonic-gate case V_P5:
440*7c478bd9Sstevel@tonic-gate return ("Pentium");
441*7c478bd9Sstevel@tonic-gate case V_P5 | V_P5mmx:
442*7c478bd9Sstevel@tonic-gate return ("Pentium with MMX");
443*7c478bd9Sstevel@tonic-gate case V_P6:
444*7c478bd9Sstevel@tonic-gate return ("Pentium Pro, Pentium II");
445*7c478bd9Sstevel@tonic-gate case V_P6 | V_P6mmx:
446*7c478bd9Sstevel@tonic-gate return ("Pentium Pro with MMX, Pentium II");
447*7c478bd9Sstevel@tonic-gate default:
448*7c478bd9Sstevel@tonic-gate break;
449*7c478bd9Sstevel@tonic-gate }
450*7c478bd9Sstevel@tonic-gate return (NULL);
451*7c478bd9Sstevel@tonic-gate }
452*7c478bd9Sstevel@tonic-gate
453*7c478bd9Sstevel@tonic-gate const char *
cpc_getcpuref(int cpuver)454*7c478bd9Sstevel@tonic-gate cpc_getcpuref(int cpuver)
455*7c478bd9Sstevel@tonic-gate {
456*7c478bd9Sstevel@tonic-gate if (validargs(cpuver, 0))
457*7c478bd9Sstevel@tonic-gate switch (MAPCPUVER(cpuver)) {
458*7c478bd9Sstevel@tonic-gate case V_P5:
459*7c478bd9Sstevel@tonic-gate case V_P5 | V_P5mmx:
460*7c478bd9Sstevel@tonic-gate return (gettext(
461*7c478bd9Sstevel@tonic-gate "See Appendix A.2 of the \"Intel Architecture "
462*7c478bd9Sstevel@tonic-gate "Software Developer's Manual,\" 243192, 1997"));
463*7c478bd9Sstevel@tonic-gate case V_P6:
464*7c478bd9Sstevel@tonic-gate case V_P6 | V_P6mmx:
465*7c478bd9Sstevel@tonic-gate return (gettext(
466*7c478bd9Sstevel@tonic-gate "See Appendix A.1 of the \"Intel Architecture "
467*7c478bd9Sstevel@tonic-gate "Software Developer's Manual,\" 243192, 1997"));
468*7c478bd9Sstevel@tonic-gate default:
469*7c478bd9Sstevel@tonic-gate break;
470*7c478bd9Sstevel@tonic-gate }
471*7c478bd9Sstevel@tonic-gate return (NULL);
472*7c478bd9Sstevel@tonic-gate }
473*7c478bd9Sstevel@tonic-gate
474*7c478bd9Sstevel@tonic-gate /*
475*7c478bd9Sstevel@tonic-gate * This is a functional interface to allow CPUs with fewer %pic registers
476*7c478bd9Sstevel@tonic-gate * to share the same data structure as those with more %pic registers
477*7c478bd9Sstevel@tonic-gate * within the same instruction set family.
478*7c478bd9Sstevel@tonic-gate */
479*7c478bd9Sstevel@tonic-gate uint_t
cpc_getnpic(int cpuver)480*7c478bd9Sstevel@tonic-gate cpc_getnpic(int cpuver)
481*7c478bd9Sstevel@tonic-gate {
482*7c478bd9Sstevel@tonic-gate switch (cpuver) {
483*7c478bd9Sstevel@tonic-gate case CPC_PENTIUM:
484*7c478bd9Sstevel@tonic-gate case CPC_PENTIUM_MMX:
485*7c478bd9Sstevel@tonic-gate case CPC_PENTIUM_PRO:
486*7c478bd9Sstevel@tonic-gate case CPC_PENTIUM_PRO_MMX:
487*7c478bd9Sstevel@tonic-gate #define EVENT ((cpc_event_t *)0)
488*7c478bd9Sstevel@tonic-gate return (sizeof (EVENT->ce_pic) / sizeof (EVENT->ce_pic[0]));
489*7c478bd9Sstevel@tonic-gate #undef EVENT
490*7c478bd9Sstevel@tonic-gate default:
491*7c478bd9Sstevel@tonic-gate return (0);
492*7c478bd9Sstevel@tonic-gate }
493*7c478bd9Sstevel@tonic-gate }
494*7c478bd9Sstevel@tonic-gate
495*7c478bd9Sstevel@tonic-gate #define BITS(v, u, l) \
496*7c478bd9Sstevel@tonic-gate (((v) >> (l)) & ((1 << (1 + (u) - (l))) - 1))
497*7c478bd9Sstevel@tonic-gate
498*7c478bd9Sstevel@tonic-gate #include "getcpuid.h"
499*7c478bd9Sstevel@tonic-gate
500*7c478bd9Sstevel@tonic-gate /*
501*7c478bd9Sstevel@tonic-gate * Return the version of the current processor.
502*7c478bd9Sstevel@tonic-gate *
503*7c478bd9Sstevel@tonic-gate * Version -1 is defined as 'not performance counter capable'
504*7c478bd9Sstevel@tonic-gate */
505*7c478bd9Sstevel@tonic-gate int
cpc_getcpuver(void)506*7c478bd9Sstevel@tonic-gate cpc_getcpuver(void)
507*7c478bd9Sstevel@tonic-gate {
508*7c478bd9Sstevel@tonic-gate static int ver = -1;
509*7c478bd9Sstevel@tonic-gate uint32_t maxeax;
510*7c478bd9Sstevel@tonic-gate uint32_t vbuf[4];
511*7c478bd9Sstevel@tonic-gate
512*7c478bd9Sstevel@tonic-gate if (ver != -1)
513*7c478bd9Sstevel@tonic-gate return (ver);
514*7c478bd9Sstevel@tonic-gate
515*7c478bd9Sstevel@tonic-gate maxeax = cpc_getcpuid(0, &vbuf[0], &vbuf[2], &vbuf[1]);
516*7c478bd9Sstevel@tonic-gate {
517*7c478bd9Sstevel@tonic-gate char *vendor = (char *)vbuf;
518*7c478bd9Sstevel@tonic-gate vendor[12] = '\0';
519*7c478bd9Sstevel@tonic-gate
520*7c478bd9Sstevel@tonic-gate if (strcmp(vendor, "GenuineIntel") != 0)
521*7c478bd9Sstevel@tonic-gate return (ver);
522*7c478bd9Sstevel@tonic-gate }
523*7c478bd9Sstevel@tonic-gate
524*7c478bd9Sstevel@tonic-gate if (maxeax >= 1) {
525*7c478bd9Sstevel@tonic-gate int family, model;
526*7c478bd9Sstevel@tonic-gate uint32_t eax, ebx, ecx, edx;
527*7c478bd9Sstevel@tonic-gate
528*7c478bd9Sstevel@tonic-gate eax = cpc_getcpuid(1, &ebx, &ecx, &edx);
529*7c478bd9Sstevel@tonic-gate
530*7c478bd9Sstevel@tonic-gate if ((family = BITS(eax, 11, 8)) == 0xf)
531*7c478bd9Sstevel@tonic-gate family = BITS(eax, 27, 20);
532*7c478bd9Sstevel@tonic-gate if ((model = BITS(eax, 7, 4)) == 0xf)
533*7c478bd9Sstevel@tonic-gate model = BITS(eax, 19, 16);
534*7c478bd9Sstevel@tonic-gate
535*7c478bd9Sstevel@tonic-gate /*
536*7c478bd9Sstevel@tonic-gate * map family and model into the performance
537*7c478bd9Sstevel@tonic-gate * counter architectures we currently understand.
538*7c478bd9Sstevel@tonic-gate *
539*7c478bd9Sstevel@tonic-gate * See application note AP485 (from developer.intel.com)
540*7c478bd9Sstevel@tonic-gate * for further explanation.
541*7c478bd9Sstevel@tonic-gate */
542*7c478bd9Sstevel@tonic-gate switch (family) {
543*7c478bd9Sstevel@tonic-gate case 5: /* Pentium and Pentium with MMX */
544*7c478bd9Sstevel@tonic-gate ver = model < 4 ?
545*7c478bd9Sstevel@tonic-gate CPC_PENTIUM : CPC_PENTIUM_MMX;
546*7c478bd9Sstevel@tonic-gate break;
547*7c478bd9Sstevel@tonic-gate case 6: /* Pentium Pro and Pentium II and III */
548*7c478bd9Sstevel@tonic-gate ver = BITS(edx, 23, 23) ? /* mmx check */
549*7c478bd9Sstevel@tonic-gate CPC_PENTIUM_PRO_MMX : CPC_PENTIUM_PRO;
550*7c478bd9Sstevel@tonic-gate break;
551*7c478bd9Sstevel@tonic-gate default:
552*7c478bd9Sstevel@tonic-gate case 0xf: /* Pentium IV */
553*7c478bd9Sstevel@tonic-gate break;
554*7c478bd9Sstevel@tonic-gate }
555*7c478bd9Sstevel@tonic-gate }
556*7c478bd9Sstevel@tonic-gate
557*7c478bd9Sstevel@tonic-gate return (ver);
558*7c478bd9Sstevel@tonic-gate }
559