perf intel-pt: decoder: Add CFE (Control Flow Event) and EVD (Event Data) processing
As of Intel SDM (https://www.intel.com/sdm) version 076, there is a new Intel PT feature called Event Trace which requires 2 new packets CFE (Control Flow Event) and EVD (Event Data). Each Event Trace event is represented by a CFE packet that is preceded by zero or more EVD packets. It may be bound to a following FUP (Flow Update) packet that provides the IP. Event Trace exposes details about asynchronous events. The CFE packet contains a type field to identify one of the following: 1 INTR interrupt, fault, exception, NMI 2 IRET interrupt return 3 SMI system management interrupt 4 RSM resume from system management mode 5 SIPI startup interprocessor interrupt 6 INIT INIT signal 7 VMENTRY VM-Entry 8 VMEXIT VM-Entry 9 VMEXIT_INTR VM-Exit due to interrupt 10 SHUTDOWN Shutdown For more details, refer to the Intel SDM, Intel Processor Trace chapter. Add processing to the decoder for the new packets. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Jiri Olsa <jolsa@redhat.com> Link: https://lore.kernel.org/r/20220124084201.2699795-8-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Родитель
68ff3cba17
Коммит
3733a98bd2
|
@ -213,6 +213,8 @@ struct intel_pt_decoder {
|
|||
bool set_fup_pwre;
|
||||
bool set_fup_exstop;
|
||||
bool set_fup_bep;
|
||||
bool set_fup_cfe_ip;
|
||||
bool set_fup_cfe;
|
||||
bool sample_cyc;
|
||||
unsigned int fup_tx_flags;
|
||||
unsigned int tx_flags;
|
||||
|
@ -223,6 +225,7 @@ struct intel_pt_decoder {
|
|||
uint64_t timestamp_insn_cnt;
|
||||
uint64_t sample_insn_cnt;
|
||||
uint64_t stuck_ip;
|
||||
struct intel_pt_pkt fup_cfe_pkt;
|
||||
int max_loops;
|
||||
int no_progress;
|
||||
int stuck_ip_prd;
|
||||
|
@ -231,6 +234,8 @@ struct intel_pt_decoder {
|
|||
const unsigned char *next_buf;
|
||||
size_t next_len;
|
||||
unsigned char temp_buf[INTEL_PT_PKT_MAX_SZ];
|
||||
int evd_cnt;
|
||||
struct intel_pt_evd evd[INTEL_PT_MAX_EVDS];
|
||||
};
|
||||
|
||||
static uint64_t intel_pt_lower_power_of_2(uint64_t x)
|
||||
|
@ -1214,6 +1219,9 @@ static void intel_pt_clear_fup_event(struct intel_pt_decoder *decoder)
|
|||
decoder->set_fup_pwre = false;
|
||||
decoder->set_fup_exstop = false;
|
||||
decoder->set_fup_bep = false;
|
||||
decoder->set_fup_cfe_ip = false;
|
||||
decoder->set_fup_cfe = false;
|
||||
decoder->evd_cnt = 0;
|
||||
}
|
||||
|
||||
static bool intel_pt_fup_event(struct intel_pt_decoder *decoder)
|
||||
|
@ -1223,6 +1231,23 @@ static bool intel_pt_fup_event(struct intel_pt_decoder *decoder)
|
|||
|
||||
decoder->state.type &= ~INTEL_PT_BRANCH;
|
||||
|
||||
if (decoder->set_fup_cfe_ip || decoder->set_fup_cfe) {
|
||||
bool ip = decoder->set_fup_cfe_ip;
|
||||
|
||||
decoder->set_fup_cfe_ip = false;
|
||||
decoder->set_fup_cfe = false;
|
||||
decoder->state.type |= INTEL_PT_EVT;
|
||||
if (!ip && decoder->pge)
|
||||
decoder->state.type |= INTEL_PT_BRANCH;
|
||||
decoder->state.cfe_type = decoder->fup_cfe_pkt.count;
|
||||
decoder->state.cfe_vector = decoder->fup_cfe_pkt.payload;
|
||||
decoder->state.evd_cnt = decoder->evd_cnt;
|
||||
decoder->state.evd = decoder->evd;
|
||||
decoder->evd_cnt = 0;
|
||||
if (ip || decoder->pge)
|
||||
decoder->state.flags |= INTEL_PT_FUP_IP;
|
||||
ret = true;
|
||||
}
|
||||
if (decoder->set_fup_tx_flags) {
|
||||
decoder->set_fup_tx_flags = false;
|
||||
decoder->tx_flags = decoder->fup_tx_flags;
|
||||
|
@ -1540,6 +1565,19 @@ static int intel_pt_mode_tsx(struct intel_pt_decoder *decoder, bool *no_tip)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int intel_pt_evd(struct intel_pt_decoder *decoder)
|
||||
{
|
||||
if (decoder->evd_cnt >= INTEL_PT_MAX_EVDS) {
|
||||
intel_pt_log_at("ERROR: Too many EVD packets", decoder->pos);
|
||||
return -ENOSYS;
|
||||
}
|
||||
decoder->evd[decoder->evd_cnt++] = (struct intel_pt_evd){
|
||||
.type = decoder->packet.count,
|
||||
.payload = decoder->packet.payload,
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t intel_pt_8b_tsc(uint64_t timestamp, uint64_t ref_timestamp)
|
||||
{
|
||||
timestamp |= (ref_timestamp & (0xffULL << 56));
|
||||
|
@ -3250,8 +3288,32 @@ next:
|
|||
goto next;
|
||||
|
||||
case INTEL_PT_CFE:
|
||||
decoder->fup_cfe_pkt = decoder->packet;
|
||||
decoder->set_fup_cfe = true;
|
||||
if (!decoder->pge) {
|
||||
intel_pt_fup_event(decoder);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case INTEL_PT_CFE_IP:
|
||||
decoder->fup_cfe_pkt = decoder->packet;
|
||||
err = intel_pt_get_next_packet(decoder);
|
||||
if (err)
|
||||
return err;
|
||||
if (decoder->packet.type == INTEL_PT_FUP) {
|
||||
decoder->set_fup_cfe_ip = true;
|
||||
no_tip = true;
|
||||
} else {
|
||||
intel_pt_log_at("ERROR: Missing FUP after CFE",
|
||||
decoder->pos);
|
||||
}
|
||||
goto next;
|
||||
|
||||
case INTEL_PT_EVD:
|
||||
err = intel_pt_evd(decoder);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -35,6 +35,7 @@ enum intel_pt_sample_type {
|
|||
INTEL_PT_TRACE_END = 1 << 10,
|
||||
INTEL_PT_BLK_ITEMS = 1 << 11,
|
||||
INTEL_PT_PSB_EVT = 1 << 12,
|
||||
INTEL_PT_EVT = 1 << 13,
|
||||
};
|
||||
|
||||
enum intel_pt_period_type {
|
||||
|
@ -209,6 +210,18 @@ struct intel_pt_vmcs_info {
|
|||
bool error_printed;
|
||||
};
|
||||
|
||||
/*
|
||||
* Maximum number of event trace data in one go, assuming at most 1 per type
|
||||
* and 6-bits of type in the EVD packet.
|
||||
*/
|
||||
#define INTEL_PT_MAX_EVDS 64
|
||||
|
||||
/* Event trace data from EVD packet */
|
||||
struct intel_pt_evd {
|
||||
int type;
|
||||
uint64_t payload;
|
||||
};
|
||||
|
||||
struct intel_pt_state {
|
||||
enum intel_pt_sample_type type;
|
||||
bool from_nr;
|
||||
|
@ -234,6 +247,10 @@ struct intel_pt_state {
|
|||
int insn_len;
|
||||
char insn[INTEL_PT_INSN_BUF_SZ];
|
||||
struct intel_pt_blk_items items;
|
||||
int cfe_type;
|
||||
int cfe_vector;
|
||||
int evd_cnt;
|
||||
struct intel_pt_evd *evd;
|
||||
};
|
||||
|
||||
struct intel_pt_insn;
|
||||
|
|
Загрузка…
Ссылка в новой задаче