opl_pcbe.c revision c7a079a873b863c236656bd0db7b2cf390841b4d
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* This file contains preset event names from the Performance Application
* Programming Interface v3.5 which included the following notice:
*
* Copyright (c) 2005,6
* Innovative Computing Labs
* Computer Science Department,
* University of Tennessee,
* Knoxville, TN.
* All Rights Reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* * Neither the name of the University of Tennessee nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*
* This open source software license conforms to the BSD License template.
*/
/*
* SPARC64 VI & VII Performance Counter Backend
*/
#include <sys/cpc_impl.h>
#include <sys/cpc_pcbe.h>
#include <sys/machsystm.h>
#include <sys/cpu_impl.h>
static int opl_pcbe_init(void);
static uint_t opl_pcbe_ncounters(void);
static const char *opl_pcbe_impl_name(void);
static const char *opl_pcbe_cpuref(void);
static char *opl_pcbe_list_attrs(void);
static uint64_t opl_pcbe_overflow_bitmap(void);
void *token);
static void opl_pcbe_program(void *token);
static void opl_pcbe_allstop(void);
static void opl_pcbe_sample(void *token);
static void opl_pcbe_free(void *config);
extern void ultra_setpcr(uint64_t);
extern uint64_t ultra_getpcr(void);
extern void ultra_setpic(uint64_t);
extern uint64_t ultra_getpic(void);
extern uint64_t ultra_gettick(void);
};
typedef struct _opl_pcbe_config {
struct nametable {
const char *name;
};
typedef struct _opl_generic_event {
char *name;
char *event;
/*
* Performance Control Register (PCR)
*
* +----------+-----+-----+------+----+
* | 0 | OVF | 0 | OVR0 | 0 |
* +----------+-----+-----+------+----+
* 63 48 47:32 31:27 26 25
*
* +----+----+--- -+----+-----+---+-----+-----+----+----+----+
* | NC | 0 | SC | 0 | SU | 0 | SL |ULRO | UT | ST |PRIV|
* +----+----+-----+----+-----+---+-----+-----+----+----+----+
* 24:22 21 20:18 17 16:11 10 9:4 3 2 1 0
*
* ULRO and OVRO bits should be on upon accessing pcr unless
* those fields need to be updated.
* (during initialization, etc.).
*
*
* Performance Instrumentation Counter (PIC)
* Four PICs are implemented in SPARC64 VI and VII,
* each PIC is accessed using PCR.SC as a select field.
*
* +------------------------+--------------------------+
* | PICU | PICL |
* +------------------------+--------------------------+
* 63 32 31 0
*/
#define SPARC64_VI_PCR_PRIVPIC UINT64_C(0)
#define CPC_SPARC64_VI_PCR_SYS_SHIFT 1
#define CPC_SPARC64_VI_PCR_USR_SHIFT 2
#define CPC_SPARC64_VI_PCR_PICL_SHIFT 4
#define CPC_SPARC64_VI_PCR_PICU_SHIFT 11
#define CPC_SPARC64_VI_NPIC 8
#define CPC_SPARC64_VI_PCR_ULRO_SHIFT 3
#define CPC_SPARC64_VI_PCR_SC_SHIFT 18
#define CPC_SPARC64_VI_PCR_NC_SHIFT 22
#define CPC_SPARC64_VI_PCR_OVRO_SHIFT 26
#define CPC_SPARC64_VI_PCR_OVF_SHIFT 32
#define SPARC64_VI_PCR_OVF (CPC_SPARC64_VI_PCR_OVF_MASK << \
#define SPARC64_VI_NUM_PIC_PAIRS 4
pcr &= ~((CPC_SPARC64_VI_PCR_SC_MASK \
<< CPC_SPARC64_VI_PCR_SC_SHIFT)); \
\
<< CPC_SPARC64_VI_PCR_SC_SHIFT); \
}
pcr &= ~((CPC_SPARC64_VI_PCR_PIC_MASK \
<< CPC_SPARC64_VI_PCR_PICU_SHIFT)); \
\
}
}
#define NT_END 0xFF
#define SPARC64_VI_EVENTS_comm_0 \
{0x0, "cycle_counts"}, \
{0x1, "instruction_counts"}
#define SPARC64_VI_EVENTS_comm_1 \
{0x5, "op_stv_wait"}, \
{0x8, "load_store_instructions"}, \
{0x9, "branch_instructions"}, \
{0xa, "floating_instructions"}, \
{0xb, "impdep2_instructions"}, \
{0xc, "prefetch_instructions"}
#define SPARC64_VI_EVENTS_comm_2 \
{0x1a, "active_cycle_count"}
static const struct nametable SPARC64_VI_names_l0[] = {
{0x2, "only_this_thread_active"},
{0x3, "w_cse_window_empty"},
{0x4, "w_op_stv_wait_nc_pend"},
{0x12, "flush_rs"},
{0x13, "2iid_use"},
{0x15, "toq_rsbr_phantom"},
{0x16, "trap_int_vector"},
{0x18, "ts_by_sxmiss"},
{0x18, "both_threads_active"},
{0x1d, "op_stv_wait_sxmiss"},
{0x1e, "eu_comp_wait"},
{0x23, "op_l1_thrashing"},
{0x24, "swpf_fail_all"},
{0x30, "sx_miss_wait_pf"},
{0x31, "jbus_cpi_count"},
{0x36, "jbus_reqbus1_busy"},
{NT_END, ""}
};
static const struct nametable SPARC64_VI_names_u0[] = {
{0x2, "instruction_flow_counts"},
{0x3, "iwr_empty"},
{0x12, "rs1"},
{0x13, "1iid_use"},
{0x16, "trap_all"},
{0x18, "thread_switch_all"},
{0x18, "only_this_thread_active"},
{0x1b, "rsf_pmmi"},
{0x1d, "act_thread_suspend"},
{0x1e, "cse_window_empty"},
{0x1f, "inh_cmit_gpr_2write"},
{0x23, "if_l1_thrashing"},
{0x24, "swpf_success_all"},
{0x30, "sx_miss_wait_dm"},
{0x31, "jbus_bi_count"},
{0x34, "lost_softpf_pfp_full"},
{0x36, "jbus_reqbus0_busy"},
{NT_END, ""}
};
static const struct nametable SPARC64_VI_names_l1[] = {
{0x2, "single_mode_instructions"},
{0x3, "w_branch_comp_wait"},
{0x4, "w_op_stv_wait_sxmiss_ex"},
{0x13, "4iid_use"},
{0x15, "flush_rs"},
{0x16, "trap_spill"},
{0x18, "ts_by_timer"},
{0x1b, "0iid_use"},
{0x1d, "op_stv_wait_nc_pend"},
{0x1e, "0endop"},
{0x20, "write_op_uTLB"},
{0x30, "sx_miss_count_pf"},
{0x31, "jbus_cpd_count"},
{0x32, "snres_64"},
{0x36, "jbus_reqbus3_busy"},
{NT_END, ""}
};
static const struct nametable SPARC64_VI_names_u1[] = {
{0x2, "single_mode_cycle_counts"},
{0x3, "w_eu_comp_wait"},
{0x4, "w_op_stv_wait_sxmiss"},
{0x13, "3iid_use"},
{0x16, "trap_int_level"},
{0x18, "ts_by_data_arrive"},
{0x18, "both_threads_empty"},
{0x1b, "op_stv_wait_nc_pend"},
{0x1d, "op_stv_wait_sxmiss_ex"},
{0x1e, "branch_comp_wait"},
{0x20, "write_if_uTLB"},
{0x30, "sx_miss_count_dm"},
{0x31, "jbus_cpb_count"},
{0x32, "snres_256"},
{0x34, "lost_softpf_by_abort"},
{0x36, "jbus_reqbus2_busy"},
{NT_END, ""}
};
static const struct nametable SPARC64_VI_names_l2[] = {
{0x2, "d_move_wait"},
{0x3, "w_op_stv_wait"},
{0x4, "w_fl_comp_wait"},
{0x13, "sync_intlk"},
{0x16, "trap_trap_inst"},
{0x18, "ts_by_if"},
{0x1e, "fl_comp_wait"},
{0x20, "op_r_iu_req_mi_go"},
{0x30, "sx_read_count_pf"},
{0x31, "jbus_odrbus_busy"},
{0x33, "sx_miss_count_dm_if"},
{0x36, "jbus_odrbus1_busy"},
{NT_END, ""}
};
static const struct nametable SPARC64_VI_names_u2[] = {
{0x2, "instruction_flow_counts"},
{0x3, "iwr_empty"},
{0x16, "trap_fill"},
{0x18, "ts_by_intr"},
{0x1b, "flush_rs"},
{0x1d, "cse_window_empty_sp_full"},
{0x1e, "op_stv_wait_ex"},
{0x1f, "3endop"},
{0x20, "if_r_iu_req_mi_go"},
{0x24, "swpf_lbs_hit"},
{0x30, "sx_read_count_dm"},
{0x31, "jbus_reqbus_busy"},
{0x33, "sx_btc_count"},
{0x36, "jbus_odrbus0_busy"},
{NT_END, ""}
};
static const struct nametable SPARC64_VI_names_l3[] = {
{0x2, "xma_inst"},
{0x3, "w_0endop"},
{0x4, "w_op_stv_wait_ex"},
{0x16, "trap_DMMU_miss"},
{0x18, "ts_by_suspend"},
{0x19, "ts_by_other"},
{0x1b, "decall_intlk"},
{0x1e, "2endop"},
{0x1f, "op_stv_wait_sxmiss"},
{0x20, "op_wait_all"},
{0x30, "dvp_count_pf"},
{0x33, "sx_miss_count_dm_opex"},
{0x36, "jbus_odrbus3_busy"},
{NT_END, ""}
};
static const struct nametable SPARC64_VI_names_u3[] = {
{0x2, "cse_priority_wait"},
{0x3, "w_d_move"},
{0x4, "w_cse_window_empty_sp_full"},
{0x13, "regwin_intlk"},
{0x15, "rs1"},
{0x16, "trap_IMMU_miss"},
{0x1d, "both_threads_suspended"},
{0x1e, "1endop"},
{0x1f, "op_stv_wait_sxmiss_ex"},
{0x20, "if_wait_all"},
{0x30, "dvp_count_dm"},
{0x33, "sx_miss_count_dm_opsh"},
{0x36, "jbus_odrbus2_busy"},
{NT_END, ""}
};
};
{0, 0x3f, 0, 0},
{1, 0x3f, 0, 0},
{2, 0x3f, 0, 0},
{3, 0x3f, 0, 0},
{4, 0x3f, 0, 0},
{5, 0x3f, 0, 0},
{6, 0x3f, 0, 0},
{7, 0x3f, 0, 0}
};
#define SPARC64_VI_GENERIC_EVENTS_comm \
{ "PAPI_tot_cyc", "cycle_counts" }, \
{ "PAPI_tot_ins", "instruction_counts" }, \
{ "PAPI_br_tkn", "branch_instructions" }, \
{ "PAPI_fp_ops", "floating_instructions" }, \
{ "PAPI_fma_ins", "impdep2_instructions" }
static const opl_generic_event_t SPARC64_VI_generic_names_l0[] = {
};
static const opl_generic_event_t SPARC64_VI_generic_names_u0[] = {
};
static const opl_generic_event_t SPARC64_VI_generic_names_l1[] = {
};
static const opl_generic_event_t SPARC64_VI_generic_names_u1[] = {
};
static const opl_generic_event_t SPARC64_VI_generic_names_l2[] = {
{ "PAPI_l1_dcm", "op_r_iu_req_mi_go" },
};
static const opl_generic_event_t SPARC64_VI_generic_names_u2[] = {
{ "PAPI_l1_icm", "if_r_iu_req_mi_go" },
};
static const opl_generic_event_t SPARC64_VI_generic_names_l3[] = {
{ "PAPI_tlb_dm", "trap_DMMU_miss" },
};
static const opl_generic_event_t SPARC64_VI_generic_names_u3[] = {
{ "PAPI_tlb_im", "trap_IMMU_miss" },
};
static const opl_generic_event_t
};
static const opl_generic_event_t **generic_events;
static const char *opl_impl_name;
static const char *opl_cpuref;
static char *pic_events[CPC_SPARC64_VI_NPIC];
static const char *sp_6_ref = "See the \"SPARC64 VI extensions\" and "
"\"SPARC64 VII extensions\" for descriptions of these events.";
static int
opl_pcbe_init(void)
{
const struct nametable *n;
const opl_generic_event_t *gevp;
int i;
/*
* Discover type of CPU
*
* Point nametable to that CPU's table
*/
switch (ULTRA_VER_IMPL(ultra_getver())) {
case OLYMPUS_C_IMPL:
case JUPITER_IMPL:
opl_impl_name = "SPARC64 VI & VII";
break;
default:
return (-1);
}
/*
* Initialize the list of events for each PIC.
* Do two passes: one to compute the size necessary and another
* to copy the strings. Need room for event, comma, and NULL terminator.
*/
for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) {
size = 0;
*pic_events[i] = '\0';
}
}
/*
* Remove trailing comma.
*/
}
return (0);
}
static uint_t
opl_pcbe_ncounters(void)
{
return (CPC_SPARC64_VI_NPIC);
}
static const char *
opl_pcbe_impl_name(void)
{
return (opl_impl_name);
}
static const char *
opl_pcbe_cpuref(void)
{
return (opl_cpuref);
}
static char *
{
return (pic_events[picnum]);
}
static char *
opl_pcbe_list_attrs(void)
{
return ("");
}
static const opl_generic_event_t *
{
const opl_generic_event_t *gevp;
return (gevp);
return (NULL);
}
static const struct nametable *
{
const struct nametable *n;
return (n);
return (NULL);
}
static uint64_t
opl_pcbe_event_coverage(char *event)
{
int i;
for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) {
bitmap |= (1 << i);
}
return (bitmap);
}
/*
* Check if counter overflow and clear it.
*/
static uint64_t
opl_pcbe_overflow_bitmap(void)
{
pcr = ultra_getpcr();
}
/*ARGSUSED*/
static int
{
const struct nametable *n;
const opl_generic_event_t *gevp;
/*
* If we've been handed an existing configuration, we need only preset
* the counter value.
*/
return (0);
}
return (CPC_INVALID_PICNUM);
if (nattrs != 0)
return (CPC_INVALID_ATTRIBUTE);
/*
* Find other requests that will be programmed with this one, and ensure
* the flags don't conflict.
*/
return (CPC_CONFLICTING_REQS);
} else {
return (CPC_INVALID_EVENT);
}
}
return (0);
}
static void
opl_pcbe_program(void *token)
{
int i;
/* Get next pic config */
}
if (bitmap == 0)
/* Fill in unused pic config */
for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) {
if (bitmap & (1 << i))
continue;
}
/*
* For each counter pair, initialize event settings and
* counter values.
*/
pcr = allstopped;
pcr &= ~SPARC64_VI_PCR_ULRO;
for (i = 0; i < SPARC64_VI_NUM_PIC_PAIRS; i++) {
}
/*
* For each counter pair, enable the trace flags to start
* counting. Re-read the counters to sample the counter value now
* and use that as the baseline for future samples.
*/
/* Get PCR */
pcr = ultra_getpcr();
/* Set counter values */
for (i = 0; i < SPARC64_VI_NUM_PIC_PAIRS; i++) {
curpic = ultra_getpic();
}
}
static void
opl_pcbe_allstop(void)
{
}
static void
opl_pcbe_sample(void *token)
{
int i;
/* Get next pic config */
}
if (bitmap == 0)
/* Fill in unuse pic config */
for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) {
if (bitmap & (1 << i))
continue;
dummypic_data[i] = 0;
pic_data[i] = &dummypic_data[i];
}
pcr = ultra_getpcr();
pcr &= ~SPARC64_VI_PCR_OVRO;
for (i = 0; i < SPARC64_VI_NUM_PIC_PAIRS; i++) {
curpic = ultra_getpic();
}
}
}
pcr = ultra_getpcr();
}
static void
opl_pcbe_free(void *config)
{
}
"SPARC64 VI&VII Perf Cntrs",
};
static struct modlinkage modl = {
&modlpcbe,
};
int
_init(void)
{
if (opl_pcbe_init() != 0)
return (ENOTSUP);
return (mod_install(&modl));
}
int
_fini(void)
{
return (mod_remove(&modl));
}
int
{
}