Commit 3733a98b authored by Adrian Hunter's avatar Adrian Hunter Committed by Arnaldo Carvalho de Melo

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: default avatarAdrian 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.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 68ff3cba
...@@ -213,6 +213,8 @@ struct intel_pt_decoder { ...@@ -213,6 +213,8 @@ struct intel_pt_decoder {
bool set_fup_pwre; bool set_fup_pwre;
bool set_fup_exstop; bool set_fup_exstop;
bool set_fup_bep; bool set_fup_bep;
bool set_fup_cfe_ip;
bool set_fup_cfe;
bool sample_cyc; bool sample_cyc;
unsigned int fup_tx_flags; unsigned int fup_tx_flags;
unsigned int tx_flags; unsigned int tx_flags;
...@@ -223,6 +225,7 @@ struct intel_pt_decoder { ...@@ -223,6 +225,7 @@ struct intel_pt_decoder {
uint64_t timestamp_insn_cnt; uint64_t timestamp_insn_cnt;
uint64_t sample_insn_cnt; uint64_t sample_insn_cnt;
uint64_t stuck_ip; uint64_t stuck_ip;
struct intel_pt_pkt fup_cfe_pkt;
int max_loops; int max_loops;
int no_progress; int no_progress;
int stuck_ip_prd; int stuck_ip_prd;
...@@ -231,6 +234,8 @@ struct intel_pt_decoder { ...@@ -231,6 +234,8 @@ struct intel_pt_decoder {
const unsigned char *next_buf; const unsigned char *next_buf;
size_t next_len; size_t next_len;
unsigned char temp_buf[INTEL_PT_PKT_MAX_SZ]; 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) 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) ...@@ -1214,6 +1219,9 @@ static void intel_pt_clear_fup_event(struct intel_pt_decoder *decoder)
decoder->set_fup_pwre = false; decoder->set_fup_pwre = false;
decoder->set_fup_exstop = false; decoder->set_fup_exstop = false;
decoder->set_fup_bep = 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) 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) ...@@ -1223,6 +1231,23 @@ static bool intel_pt_fup_event(struct intel_pt_decoder *decoder)
decoder->state.type &= ~INTEL_PT_BRANCH; 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) { if (decoder->set_fup_tx_flags) {
decoder->set_fup_tx_flags = false; decoder->set_fup_tx_flags = false;
decoder->tx_flags = decoder->fup_tx_flags; 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) ...@@ -1540,6 +1565,19 @@ static int intel_pt_mode_tsx(struct intel_pt_decoder *decoder, bool *no_tip)
return 0; 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) static uint64_t intel_pt_8b_tsc(uint64_t timestamp, uint64_t ref_timestamp)
{ {
timestamp |= (ref_timestamp & (0xffULL << 56)); timestamp |= (ref_timestamp & (0xffULL << 56));
...@@ -3250,8 +3288,32 @@ static int intel_pt_walk_trace(struct intel_pt_decoder *decoder) ...@@ -3250,8 +3288,32 @@ static int intel_pt_walk_trace(struct intel_pt_decoder *decoder)
goto next; goto next;
case INTEL_PT_CFE: 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: 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: case INTEL_PT_EVD:
err = intel_pt_evd(decoder);
if (err)
return err;
break; break;
default: default:
......
...@@ -35,6 +35,7 @@ enum intel_pt_sample_type { ...@@ -35,6 +35,7 @@ enum intel_pt_sample_type {
INTEL_PT_TRACE_END = 1 << 10, INTEL_PT_TRACE_END = 1 << 10,
INTEL_PT_BLK_ITEMS = 1 << 11, INTEL_PT_BLK_ITEMS = 1 << 11,
INTEL_PT_PSB_EVT = 1 << 12, INTEL_PT_PSB_EVT = 1 << 12,
INTEL_PT_EVT = 1 << 13,
}; };
enum intel_pt_period_type { enum intel_pt_period_type {
...@@ -209,6 +210,18 @@ struct intel_pt_vmcs_info { ...@@ -209,6 +210,18 @@ struct intel_pt_vmcs_info {
bool error_printed; 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 { struct intel_pt_state {
enum intel_pt_sample_type type; enum intel_pt_sample_type type;
bool from_nr; bool from_nr;
...@@ -234,6 +247,10 @@ struct intel_pt_state { ...@@ -234,6 +247,10 @@ struct intel_pt_state {
int insn_len; int insn_len;
char insn[INTEL_PT_INSN_BUF_SZ]; char insn[INTEL_PT_INSN_BUF_SZ];
struct intel_pt_blk_items items; struct intel_pt_blk_items items;
int cfe_type;
int cfe_vector;
int evd_cnt;
struct intel_pt_evd *evd;
}; };
struct intel_pt_insn; struct intel_pt_insn;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment