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

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.com


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 68ff3cba
Loading
Loading
Loading
Loading
+62 −0
Original line number Diff line number Diff line
@@ -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 @@ static int intel_pt_walk_trace(struct intel_pt_decoder *decoder)
			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:
+17 −0
Original line number Diff line number Diff line
@@ -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;