perf intel-pt: decoder: Add CFE (Control Flow Event) and EVD (Event Data) processing
authorAdrian Hunter <adrian.hunter@intel.com>
Mon, 24 Jan 2022 08:41:43 +0000 (10:41 +0200)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Tue, 15 Feb 2022 20:07:23 +0000 (17:07 -0300)
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>
tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
tools/perf/util/intel-pt-decoder/intel-pt-decoder.h

index 5792d536b4586ab49c3af7b724ab39621dd2596e..1a39119706d68ca1e6bf32614456ca81ee91e20f 100644 (file)
@@ -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:
index 8fd68f7a0963732fcd44661e2c890a4c59087ff0..59ef4b41ec674884244ed3873b96135d917cccda 100644 (file)
@@ -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;