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:
Adrian Hunter 2022-01-24 10:41:43 +02:00 коммит произвёл Arnaldo Carvalho de Melo
Родитель 68ff3cba17
Коммит 3733a98bd2
2 изменённых файлов: 79 добавлений и 0 удалений

Просмотреть файл

@ -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;