Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf tools: Add decoder mechanic to support dumping trace data

This patch adds the required interface to the openCSD library to support
dumping CoreSight trace packet using the "report --dump" command. The
information conveyed is related to the type of packets gathered by a
trace session rather than full decoding.

Co-authored-by: Tor Jeremiassen <tor@ti.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Kim Phillips <kim.phillips@arm.com>
Cc: Mike Leach <mike.leach@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Suzuki Poulouse <suzuki.poulose@arm.com>
Cc: linux-arm-kernel@lists.infradead.org
Link: http://lkml.kernel.org/r/1516211539-5166-5-git-send-email-mathieu.poirier@linaro.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Mathieu Poirier
Tor Jeremiassen
and committed by
Arnaldo Carvalho de Melo
68ffe390 cd8bfd8c

+536 -4
+1
tools/perf/util/Build
··· 91 91 92 92 ifdef CONFIG_LIBOPENCSD 93 93 libperf-$(CONFIG_AUXTRACE) += cs-etm.o 94 + libperf-$(CONFIG_AUXTRACE) += cs-etm-decoder/ 94 95 endif 95 96 96 97 libperf-y += parse-branch-options.o
+1
tools/perf/util/cs-etm-decoder/Build
··· 1 + libperf-$(CONFIG_AUXTRACE) += cs-etm-decoder.o
+334
tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
··· 1 + /* 2 + * SPDX-License-Identifier: GPL-2.0 3 + * 4 + * Copyright(C) 2015-2018 Linaro Limited. 5 + * 6 + * Author: Tor Jeremiassen <tor@ti.com> 7 + * Author: Mathieu Poirier <mathieu.poirier@linaro.org> 8 + */ 9 + 10 + #include <linux/err.h> 11 + #include <linux/list.h> 12 + #include <stdlib.h> 13 + #include <opencsd/c_api/opencsd_c_api.h> 14 + #include <opencsd/etmv4/trc_pkt_types_etmv4.h> 15 + #include <opencsd/ocsd_if_types.h> 16 + 17 + #include "cs-etm.h" 18 + #include "cs-etm-decoder.h" 19 + #include "intlist.h" 20 + #include "util.h" 21 + 22 + #define MAX_BUFFER 1024 23 + 24 + /* use raw logging */ 25 + #ifdef CS_DEBUG_RAW 26 + #define CS_LOG_RAW_FRAMES 27 + #ifdef CS_RAW_PACKED 28 + #define CS_RAW_DEBUG_FLAGS (OCSD_DFRMTR_UNPACKED_RAW_OUT | \ 29 + OCSD_DFRMTR_PACKED_RAW_OUT) 30 + #else 31 + #define CS_RAW_DEBUG_FLAGS (OCSD_DFRMTR_UNPACKED_RAW_OUT) 32 + #endif 33 + #endif 34 + 35 + struct cs_etm_decoder { 36 + void *data; 37 + void (*packet_printer)(const char *msg); 38 + bool trace_on; 39 + dcd_tree_handle_t dcd_tree; 40 + cs_etm_mem_cb_type mem_access; 41 + ocsd_datapath_resp_t prev_return; 42 + u32 packet_count; 43 + u32 head; 44 + u32 tail; 45 + struct cs_etm_packet packet_buffer[MAX_BUFFER]; 46 + }; 47 + 48 + static void cs_etm_decoder__gen_etmv4_config(struct cs_etm_trace_params *params, 49 + ocsd_etmv4_cfg *config) 50 + { 51 + config->reg_configr = params->etmv4.reg_configr; 52 + config->reg_traceidr = params->etmv4.reg_traceidr; 53 + config->reg_idr0 = params->etmv4.reg_idr0; 54 + config->reg_idr1 = params->etmv4.reg_idr1; 55 + config->reg_idr2 = params->etmv4.reg_idr2; 56 + config->reg_idr8 = params->etmv4.reg_idr8; 57 + config->reg_idr9 = 0; 58 + config->reg_idr10 = 0; 59 + config->reg_idr11 = 0; 60 + config->reg_idr12 = 0; 61 + config->reg_idr13 = 0; 62 + config->arch_ver = ARCH_V8; 63 + config->core_prof = profile_CortexA; 64 + } 65 + 66 + static void cs_etm_decoder__print_str_cb(const void *p_context, 67 + const char *msg, 68 + const int str_len) 69 + { 70 + if (p_context && str_len) 71 + ((struct cs_etm_decoder *)p_context)->packet_printer(msg); 72 + } 73 + 74 + static int 75 + cs_etm_decoder__init_def_logger_printing(struct cs_etm_decoder_params *d_params, 76 + struct cs_etm_decoder *decoder) 77 + { 78 + int ret = 0; 79 + 80 + if (d_params->packet_printer == NULL) 81 + return -1; 82 + 83 + decoder->packet_printer = d_params->packet_printer; 84 + 85 + /* 86 + * Set up a library default logger to process any printers 87 + * (packet/raw frame) we add later. 88 + */ 89 + ret = ocsd_def_errlog_init(OCSD_ERR_SEV_ERROR, 1); 90 + if (ret != 0) 91 + return -1; 92 + 93 + /* no stdout / err / file output */ 94 + ret = ocsd_def_errlog_config_output(C_API_MSGLOGOUT_FLG_NONE, NULL); 95 + if (ret != 0) 96 + return -1; 97 + 98 + /* 99 + * Set the string CB for the default logger, passes strings to 100 + * perf print logger. 101 + */ 102 + ret = ocsd_def_errlog_set_strprint_cb(decoder->dcd_tree, 103 + (void *)decoder, 104 + cs_etm_decoder__print_str_cb); 105 + if (ret != 0) 106 + ret = -1; 107 + 108 + return 0; 109 + } 110 + 111 + #ifdef CS_LOG_RAW_FRAMES 112 + static void 113 + cs_etm_decoder__init_raw_frame_logging(struct cs_etm_decoder_params *d_params, 114 + struct cs_etm_decoder *decoder) 115 + { 116 + /* Only log these during a --dump operation */ 117 + if (d_params->operation == CS_ETM_OPERATION_PRINT) { 118 + /* set up a library default logger to process the 119 + * raw frame printer we add later 120 + */ 121 + ocsd_def_errlog_init(OCSD_ERR_SEV_ERROR, 1); 122 + 123 + /* no stdout / err / file output */ 124 + ocsd_def_errlog_config_output(C_API_MSGLOGOUT_FLG_NONE, NULL); 125 + 126 + /* set the string CB for the default logger, 127 + * passes strings to perf print logger. 128 + */ 129 + ocsd_def_errlog_set_strprint_cb(decoder->dcd_tree, 130 + (void *)decoder, 131 + cs_etm_decoder__print_str_cb); 132 + 133 + /* use the built in library printer for the raw frames */ 134 + ocsd_dt_set_raw_frame_printer(decoder->dcd_tree, 135 + CS_RAW_DEBUG_FLAGS); 136 + } 137 + } 138 + #else 139 + static void 140 + cs_etm_decoder__init_raw_frame_logging( 141 + struct cs_etm_decoder_params *d_params __maybe_unused, 142 + struct cs_etm_decoder *decoder __maybe_unused) 143 + { 144 + } 145 + #endif 146 + 147 + static int cs_etm_decoder__create_packet_printer(struct cs_etm_decoder *decoder, 148 + const char *decoder_name, 149 + void *trace_config) 150 + { 151 + u8 csid; 152 + 153 + if (ocsd_dt_create_decoder(decoder->dcd_tree, decoder_name, 154 + OCSD_CREATE_FLG_PACKET_PROC, 155 + trace_config, &csid)) 156 + return -1; 157 + 158 + if (ocsd_dt_set_pkt_protocol_printer(decoder->dcd_tree, csid, 0)) 159 + return -1; 160 + 161 + return 0; 162 + } 163 + 164 + static int 165 + cs_etm_decoder__create_etm_packet_printer(struct cs_etm_trace_params *t_params, 166 + struct cs_etm_decoder *decoder) 167 + { 168 + const char *decoder_name; 169 + ocsd_etmv4_cfg trace_config_etmv4; 170 + void *trace_config; 171 + 172 + switch (t_params->protocol) { 173 + case CS_ETM_PROTO_ETMV4i: 174 + cs_etm_decoder__gen_etmv4_config(t_params, &trace_config_etmv4); 175 + decoder_name = OCSD_BUILTIN_DCD_ETMV4I; 176 + trace_config = &trace_config_etmv4; 177 + break; 178 + default: 179 + return -1; 180 + } 181 + 182 + return cs_etm_decoder__create_packet_printer(decoder, 183 + decoder_name, 184 + trace_config); 185 + } 186 + 187 + static void cs_etm_decoder__clear_buffer(struct cs_etm_decoder *decoder) 188 + { 189 + int i; 190 + 191 + decoder->head = 0; 192 + decoder->tail = 0; 193 + decoder->packet_count = 0; 194 + for (i = 0; i < MAX_BUFFER; i++) { 195 + decoder->packet_buffer[i].start_addr = 0xdeadbeefdeadbeefUL; 196 + decoder->packet_buffer[i].end_addr = 0xdeadbeefdeadbeefUL; 197 + decoder->packet_buffer[i].exc = false; 198 + decoder->packet_buffer[i].exc_ret = false; 199 + decoder->packet_buffer[i].cpu = INT_MIN; 200 + } 201 + } 202 + 203 + static int 204 + cs_etm_decoder__create_etm_decoder(struct cs_etm_decoder_params *d_params, 205 + struct cs_etm_trace_params *t_params, 206 + struct cs_etm_decoder *decoder) 207 + { 208 + if (d_params->operation == CS_ETM_OPERATION_PRINT) 209 + return cs_etm_decoder__create_etm_packet_printer(t_params, 210 + decoder); 211 + return -1; 212 + } 213 + 214 + struct cs_etm_decoder * 215 + cs_etm_decoder__new(int num_cpu, struct cs_etm_decoder_params *d_params, 216 + struct cs_etm_trace_params t_params[]) 217 + { 218 + struct cs_etm_decoder *decoder; 219 + ocsd_dcd_tree_src_t format; 220 + u32 flags; 221 + int i, ret; 222 + 223 + if ((!t_params) || (!d_params)) 224 + return NULL; 225 + 226 + decoder = zalloc(sizeof(*decoder)); 227 + 228 + if (!decoder) 229 + return NULL; 230 + 231 + decoder->data = d_params->data; 232 + decoder->prev_return = OCSD_RESP_CONT; 233 + cs_etm_decoder__clear_buffer(decoder); 234 + format = (d_params->formatted ? OCSD_TRC_SRC_FRAME_FORMATTED : 235 + OCSD_TRC_SRC_SINGLE); 236 + flags = 0; 237 + flags |= (d_params->fsyncs ? OCSD_DFRMTR_HAS_FSYNCS : 0); 238 + flags |= (d_params->hsyncs ? OCSD_DFRMTR_HAS_HSYNCS : 0); 239 + flags |= (d_params->frame_aligned ? OCSD_DFRMTR_FRAME_MEM_ALIGN : 0); 240 + 241 + /* 242 + * Drivers may add barrier frames when used with perf, set up to 243 + * handle this. Barriers const of FSYNC packet repeated 4 times. 244 + */ 245 + flags |= OCSD_DFRMTR_RESET_ON_4X_FSYNC; 246 + 247 + /* Create decode tree for the data source */ 248 + decoder->dcd_tree = ocsd_create_dcd_tree(format, flags); 249 + 250 + if (decoder->dcd_tree == 0) 251 + goto err_free_decoder; 252 + 253 + /* init library print logging support */ 254 + ret = cs_etm_decoder__init_def_logger_printing(d_params, decoder); 255 + if (ret != 0) 256 + goto err_free_decoder_tree; 257 + 258 + /* init raw frame logging if required */ 259 + cs_etm_decoder__init_raw_frame_logging(d_params, decoder); 260 + 261 + for (i = 0; i < num_cpu; i++) { 262 + ret = cs_etm_decoder__create_etm_decoder(d_params, 263 + &t_params[i], 264 + decoder); 265 + if (ret != 0) 266 + goto err_free_decoder_tree; 267 + } 268 + 269 + return decoder; 270 + 271 + err_free_decoder_tree: 272 + ocsd_destroy_dcd_tree(decoder->dcd_tree); 273 + err_free_decoder: 274 + free(decoder); 275 + return NULL; 276 + } 277 + 278 + int cs_etm_decoder__process_data_block(struct cs_etm_decoder *decoder, 279 + u64 indx, const u8 *buf, 280 + size_t len, size_t *consumed) 281 + { 282 + int ret = 0; 283 + ocsd_datapath_resp_t cur = OCSD_RESP_CONT; 284 + ocsd_datapath_resp_t prev_return = decoder->prev_return; 285 + size_t processed = 0; 286 + u32 count; 287 + 288 + while (processed < len) { 289 + if (OCSD_DATA_RESP_IS_WAIT(prev_return)) { 290 + cur = ocsd_dt_process_data(decoder->dcd_tree, 291 + OCSD_OP_FLUSH, 292 + 0, 293 + 0, 294 + NULL, 295 + NULL); 296 + } else if (OCSD_DATA_RESP_IS_CONT(prev_return)) { 297 + cur = ocsd_dt_process_data(decoder->dcd_tree, 298 + OCSD_OP_DATA, 299 + indx + processed, 300 + len - processed, 301 + &buf[processed], 302 + &count); 303 + processed += count; 304 + } else { 305 + ret = -EINVAL; 306 + break; 307 + } 308 + 309 + /* 310 + * Return to the input code if the packet buffer is full. 311 + * Flushing will get done once the packet buffer has been 312 + * processed. 313 + */ 314 + if (OCSD_DATA_RESP_IS_WAIT(cur)) 315 + break; 316 + 317 + prev_return = cur; 318 + } 319 + 320 + decoder->prev_return = cur; 321 + *consumed = processed; 322 + 323 + return ret; 324 + } 325 + 326 + void cs_etm_decoder__free(struct cs_etm_decoder *decoder) 327 + { 328 + if (!decoder) 329 + return; 330 + 331 + ocsd_destroy_dcd_tree(decoder->dcd_tree); 332 + decoder->dcd_tree = NULL; 333 + free(decoder); 334 + }
+96
tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
··· 1 + /* 2 + * SPDX-License-Identifier: GPL-2.0 3 + * 4 + * Copyright(C) 2015-2018 Linaro Limited. 5 + * 6 + * Author: Tor Jeremiassen <tor@ti.com> 7 + * Author: Mathieu Poirier <mathieu.poirier@linaro.org> 8 + */ 9 + 10 + #ifndef INCLUDE__CS_ETM_DECODER_H__ 11 + #define INCLUDE__CS_ETM_DECODER_H__ 12 + 13 + #include <linux/types.h> 14 + #include <stdio.h> 15 + 16 + struct cs_etm_decoder; 17 + 18 + struct cs_etm_buffer { 19 + const unsigned char *buf; 20 + size_t len; 21 + u64 offset; 22 + u64 ref_timestamp; 23 + }; 24 + 25 + enum cs_etm_sample_type { 26 + CS_ETM_RANGE = 1 << 0, 27 + }; 28 + 29 + struct cs_etm_packet { 30 + enum cs_etm_sample_type sample_type; 31 + u64 start_addr; 32 + u64 end_addr; 33 + u8 exc; 34 + u8 exc_ret; 35 + int cpu; 36 + }; 37 + 38 + struct cs_etm_queue; 39 + 40 + typedef u32 (*cs_etm_mem_cb_type)(struct cs_etm_queue *, u64, 41 + size_t, u8 *); 42 + 43 + struct cs_etmv4_trace_params { 44 + u32 reg_idr0; 45 + u32 reg_idr1; 46 + u32 reg_idr2; 47 + u32 reg_idr8; 48 + u32 reg_configr; 49 + u32 reg_traceidr; 50 + }; 51 + 52 + struct cs_etm_trace_params { 53 + int protocol; 54 + union { 55 + struct cs_etmv4_trace_params etmv4; 56 + }; 57 + }; 58 + 59 + struct cs_etm_decoder_params { 60 + int operation; 61 + void (*packet_printer)(const char *msg); 62 + cs_etm_mem_cb_type mem_acc_cb; 63 + u8 formatted; 64 + u8 fsyncs; 65 + u8 hsyncs; 66 + u8 frame_aligned; 67 + void *data; 68 + }; 69 + 70 + /* 71 + * The following enums are indexed starting with 1 to align with the 72 + * open source coresight trace decoder library. 73 + */ 74 + enum { 75 + CS_ETM_PROTO_ETMV3 = 1, 76 + CS_ETM_PROTO_ETMV4i, 77 + CS_ETM_PROTO_ETMV4d, 78 + }; 79 + 80 + enum { 81 + CS_ETM_OPERATION_PRINT = 1, 82 + CS_ETM_OPERATION_DECODE, 83 + }; 84 + 85 + int cs_etm_decoder__process_data_block(struct cs_etm_decoder *decoder, 86 + u64 indx, const u8 *buf, 87 + size_t len, size_t *consumed); 88 + 89 + struct cs_etm_decoder * 90 + cs_etm_decoder__new(int num_cpu, 91 + struct cs_etm_decoder_params *d_params, 92 + struct cs_etm_trace_params t_params[]); 93 + 94 + void cs_etm_decoder__free(struct cs_etm_decoder *decoder); 95 + 96 + #endif /* INCLUDE__CS_ETM_DECODER_H__ */
+104 -4
tools/perf/util/cs-etm.c
··· 18 18 #include "auxtrace.h" 19 19 #include "color.h" 20 20 #include "cs-etm.h" 21 + #include "cs-etm-decoder/cs-etm-decoder.h" 21 22 #include "debug.h" 22 23 #include "evlist.h" 23 24 #include "intlist.h" ··· 69 68 u64 timestamp; 70 69 u64 offset; 71 70 }; 71 + 72 + static void cs_etm__packet_dump(const char *pkt_string) 73 + { 74 + const char *color = PERF_COLOR_BLUE; 75 + int len = strlen(pkt_string); 76 + 77 + if (len && (pkt_string[len-1] == '\n')) 78 + color_fprintf(stdout, color, " %s", pkt_string); 79 + else 80 + color_fprintf(stdout, color, " %s\n", pkt_string); 81 + 82 + fflush(stdout); 83 + } 84 + 85 + static void cs_etm__dump_event(struct cs_etm_auxtrace *etm, 86 + struct auxtrace_buffer *buffer) 87 + { 88 + int i, ret; 89 + const char *color = PERF_COLOR_BLUE; 90 + struct cs_etm_decoder_params d_params; 91 + struct cs_etm_trace_params *t_params; 92 + struct cs_etm_decoder *decoder; 93 + size_t buffer_used = 0; 94 + 95 + fprintf(stdout, "\n"); 96 + color_fprintf(stdout, color, 97 + ". ... CoreSight ETM Trace data: size %zu bytes\n", 98 + buffer->size); 99 + 100 + /* Use metadata to fill in trace parameters for trace decoder */ 101 + t_params = zalloc(sizeof(*t_params) * etm->num_cpu); 102 + for (i = 0; i < etm->num_cpu; i++) { 103 + t_params[i].protocol = CS_ETM_PROTO_ETMV4i; 104 + t_params[i].etmv4.reg_idr0 = etm->metadata[i][CS_ETMV4_TRCIDR0]; 105 + t_params[i].etmv4.reg_idr1 = etm->metadata[i][CS_ETMV4_TRCIDR1]; 106 + t_params[i].etmv4.reg_idr2 = etm->metadata[i][CS_ETMV4_TRCIDR2]; 107 + t_params[i].etmv4.reg_idr8 = etm->metadata[i][CS_ETMV4_TRCIDR8]; 108 + t_params[i].etmv4.reg_configr = 109 + etm->metadata[i][CS_ETMV4_TRCCONFIGR]; 110 + t_params[i].etmv4.reg_traceidr = 111 + etm->metadata[i][CS_ETMV4_TRCTRACEIDR]; 112 + } 113 + 114 + /* Set decoder parameters to simply print the trace packets */ 115 + d_params.packet_printer = cs_etm__packet_dump; 116 + d_params.operation = CS_ETM_OPERATION_PRINT; 117 + d_params.formatted = true; 118 + d_params.fsyncs = false; 119 + d_params.hsyncs = false; 120 + d_params.frame_aligned = true; 121 + 122 + decoder = cs_etm_decoder__new(etm->num_cpu, &d_params, t_params); 123 + 124 + zfree(&t_params); 125 + 126 + if (!decoder) 127 + return; 128 + do { 129 + size_t consumed; 130 + 131 + ret = cs_etm_decoder__process_data_block( 132 + decoder, buffer->offset, 133 + &((u8 *)buffer->data)[buffer_used], 134 + buffer->size - buffer_used, &consumed); 135 + if (ret) 136 + break; 137 + 138 + buffer_used += consumed; 139 + } while (buffer_used < buffer->size); 140 + 141 + cs_etm_decoder__free(decoder); 142 + } 72 143 73 144 static int cs_etm__flush_events(struct perf_session *session, 74 145 struct perf_tool *tool) ··· 210 137 211 138 static int cs_etm__process_auxtrace_event(struct perf_session *session, 212 139 union perf_event *event, 213 - struct perf_tool *tool) 140 + struct perf_tool *tool __maybe_unused) 214 141 { 215 - (void) session; 216 - (void) event; 217 - (void) tool; 142 + struct cs_etm_auxtrace *etm = container_of(session->auxtrace, 143 + struct cs_etm_auxtrace, 144 + auxtrace); 145 + if (!etm->data_queued) { 146 + struct auxtrace_buffer *buffer; 147 + off_t data_offset; 148 + int fd = perf_data__fd(session->data); 149 + bool is_pipe = perf_data__is_pipe(session->data); 150 + int err; 151 + 152 + if (is_pipe) 153 + data_offset = 0; 154 + else { 155 + data_offset = lseek(fd, 0, SEEK_CUR); 156 + if (data_offset == -1) 157 + return -errno; 158 + } 159 + 160 + err = auxtrace_queues__add_event(&etm->queues, session, 161 + event, data_offset, &buffer); 162 + if (err) 163 + return err; 164 + 165 + if (dump_trace) 166 + if (auxtrace_buffer__get_data(buffer, fd)) { 167 + cs_etm__dump_event(etm, buffer); 168 + auxtrace_buffer__put_data(buffer); 169 + } 170 + } 171 + 218 172 return 0; 219 173 } 220 174