From 3733a98bd209a4bc7c312ee9909182371e9e9982 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 24 Jan 2022 10:41:43 +0200 Subject: 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 Cc: Alexander Shishkin Cc: Andi Kleen Cc: Jiri Olsa Link: https://lore.kernel.org/r/20220124084201.2699795-8-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- .../perf/util/intel-pt-decoder/intel-pt-decoder.c | 62 ++++++++++++++++++++++ .../perf/util/intel-pt-decoder/intel-pt-decoder.h | 17 ++++++ 2 files changed, 79 insertions(+) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index 5792d536b458..1a39119706d6 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -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: diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h index 8fd68f7a0963..59ef4b41ec67 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h @@ -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; -- cgit v1.2.3-59-g8ed1b