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

perf cs-etm: Print auxtrace info even if OpenCSD isn't linked

Printing the info doesn't have any dependency on OpenCSD, and neither
does recording Coresight data. Because it's sometimes useful to look at
the info for debugging, it makes sense to be able to see it on the same
platform that the recording was made on.

So pull the auxtrace info printing parts into a new file that is always
compiled into Perf.

Signed-off-by: James Clark <james.clark@arm.com>
Cc: Al Grant <Al.Grant@arm.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.g.garry@oracle.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Mike Leach <mike.leach@linaro.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Suzuki Poulouse <suzuki.poulose@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: coresight@lists.linaro.org
Cc: linux-arm-kernel@lists.infradead.org
Link: https://lore.kernel.org/r/20221212155513.2259623-6-james.clark@arm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

James Clark and committed by
Arnaldo Carvalho de Melo
55c1de99 fd63091f

+191 -166
+1
tools/perf/util/Build
··· 126 126 perf-$(CONFIG_AUXTRACE) += cs-etm.o 127 127 perf-$(CONFIG_AUXTRACE) += cs-etm-decoder/ 128 128 endif 129 + perf-$(CONFIG_AUXTRACE) += cs-etm-base.o 129 130 130 131 perf-y += parse-branch-options.o 131 132 perf-y += dump-insn.o
+174
tools/perf/util/cs-etm-base.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * File for any parts of the Coresight decoding that don't require 4 + * OpenCSD. 5 + */ 6 + 7 + #include <errno.h> 8 + #include <inttypes.h> 9 + 10 + #include "cs-etm.h" 11 + 12 + static const char * const cs_etm_global_header_fmts[] = { 13 + [CS_HEADER_VERSION] = " Header version %llx\n", 14 + [CS_PMU_TYPE_CPUS] = " PMU type/num cpus %llx\n", 15 + [CS_ETM_SNAPSHOT] = " Snapshot %llx\n", 16 + }; 17 + 18 + static const char * const cs_etm_priv_fmts[] = { 19 + [CS_ETM_MAGIC] = " Magic number %llx\n", 20 + [CS_ETM_CPU] = " CPU %lld\n", 21 + [CS_ETM_NR_TRC_PARAMS] = " NR_TRC_PARAMS %llx\n", 22 + [CS_ETM_ETMCR] = " ETMCR %llx\n", 23 + [CS_ETM_ETMTRACEIDR] = " ETMTRACEIDR %llx\n", 24 + [CS_ETM_ETMCCER] = " ETMCCER %llx\n", 25 + [CS_ETM_ETMIDR] = " ETMIDR %llx\n", 26 + }; 27 + 28 + static const char * const cs_etmv4_priv_fmts[] = { 29 + [CS_ETM_MAGIC] = " Magic number %llx\n", 30 + [CS_ETM_CPU] = " CPU %lld\n", 31 + [CS_ETM_NR_TRC_PARAMS] = " NR_TRC_PARAMS %llx\n", 32 + [CS_ETMV4_TRCCONFIGR] = " TRCCONFIGR %llx\n", 33 + [CS_ETMV4_TRCTRACEIDR] = " TRCTRACEIDR %llx\n", 34 + [CS_ETMV4_TRCIDR0] = " TRCIDR0 %llx\n", 35 + [CS_ETMV4_TRCIDR1] = " TRCIDR1 %llx\n", 36 + [CS_ETMV4_TRCIDR2] = " TRCIDR2 %llx\n", 37 + [CS_ETMV4_TRCIDR8] = " TRCIDR8 %llx\n", 38 + [CS_ETMV4_TRCAUTHSTATUS] = " TRCAUTHSTATUS %llx\n", 39 + [CS_ETE_TRCDEVARCH] = " TRCDEVARCH %llx\n" 40 + }; 41 + 42 + static const char * const param_unk_fmt = 43 + " Unknown parameter [%d] %"PRIx64"\n"; 44 + static const char * const magic_unk_fmt = 45 + " Magic number Unknown %"PRIx64"\n"; 46 + 47 + static int cs_etm__print_cpu_metadata_v0(u64 *val, int *offset) 48 + { 49 + int i = *offset, j, nr_params = 0, fmt_offset; 50 + u64 magic; 51 + 52 + /* check magic value */ 53 + magic = val[i + CS_ETM_MAGIC]; 54 + if ((magic != __perf_cs_etmv3_magic) && 55 + (magic != __perf_cs_etmv4_magic)) { 56 + /* failure - note bad magic value */ 57 + fprintf(stdout, magic_unk_fmt, magic); 58 + return -EINVAL; 59 + } 60 + 61 + /* print common header block */ 62 + fprintf(stdout, cs_etm_priv_fmts[CS_ETM_MAGIC], val[i++]); 63 + fprintf(stdout, cs_etm_priv_fmts[CS_ETM_CPU], val[i++]); 64 + 65 + if (magic == __perf_cs_etmv3_magic) { 66 + nr_params = CS_ETM_NR_TRC_PARAMS_V0; 67 + fmt_offset = CS_ETM_ETMCR; 68 + /* after common block, offset format index past NR_PARAMS */ 69 + for (j = fmt_offset; j < nr_params + fmt_offset; j++, i++) 70 + fprintf(stdout, cs_etm_priv_fmts[j], val[i]); 71 + } else if (magic == __perf_cs_etmv4_magic) { 72 + nr_params = CS_ETMV4_NR_TRC_PARAMS_V0; 73 + fmt_offset = CS_ETMV4_TRCCONFIGR; 74 + /* after common block, offset format index past NR_PARAMS */ 75 + for (j = fmt_offset; j < nr_params + fmt_offset; j++, i++) 76 + fprintf(stdout, cs_etmv4_priv_fmts[j], val[i]); 77 + } 78 + *offset = i; 79 + return 0; 80 + } 81 + 82 + static int cs_etm__print_cpu_metadata_v1(u64 *val, int *offset) 83 + { 84 + int i = *offset, j, total_params = 0; 85 + u64 magic; 86 + 87 + magic = val[i + CS_ETM_MAGIC]; 88 + /* total params to print is NR_PARAMS + common block size for v1 */ 89 + total_params = val[i + CS_ETM_NR_TRC_PARAMS] + CS_ETM_COMMON_BLK_MAX_V1; 90 + 91 + if (magic == __perf_cs_etmv3_magic) { 92 + for (j = 0; j < total_params; j++, i++) { 93 + /* if newer record - could be excess params */ 94 + if (j >= CS_ETM_PRIV_MAX) 95 + fprintf(stdout, param_unk_fmt, j, val[i]); 96 + else 97 + fprintf(stdout, cs_etm_priv_fmts[j], val[i]); 98 + } 99 + } else if (magic == __perf_cs_etmv4_magic || magic == __perf_cs_ete_magic) { 100 + /* 101 + * ETE and ETMv4 can be printed in the same block because the number of parameters 102 + * is saved and they share the list of parameter names. ETE is also only supported 103 + * in V1 files. 104 + */ 105 + for (j = 0; j < total_params; j++, i++) { 106 + /* if newer record - could be excess params */ 107 + if (j >= CS_ETE_PRIV_MAX) 108 + fprintf(stdout, param_unk_fmt, j, val[i]); 109 + else 110 + fprintf(stdout, cs_etmv4_priv_fmts[j], val[i]); 111 + } 112 + } else { 113 + /* failure - note bad magic value and error out */ 114 + fprintf(stdout, magic_unk_fmt, magic); 115 + return -EINVAL; 116 + } 117 + *offset = i; 118 + return 0; 119 + } 120 + 121 + static void cs_etm__print_auxtrace_info(u64 *val, int num) 122 + { 123 + int i, cpu = 0, version, err; 124 + 125 + version = val[0]; 126 + 127 + for (i = 0; i < CS_HEADER_VERSION_MAX; i++) 128 + fprintf(stdout, cs_etm_global_header_fmts[i], val[i]); 129 + 130 + for (i = CS_HEADER_VERSION_MAX; cpu < num; cpu++) { 131 + if (version == 0) 132 + err = cs_etm__print_cpu_metadata_v0(val, &i); 133 + else if (version == 1) 134 + err = cs_etm__print_cpu_metadata_v1(val, &i); 135 + if (err) 136 + return; 137 + } 138 + } 139 + 140 + /* 141 + * Do some basic checks and print the auxtrace info header before calling 142 + * into cs_etm__process_auxtrace_info_full() which requires OpenCSD to be 143 + * linked in. This allows some basic debugging if OpenCSD is missing. 144 + */ 145 + int cs_etm__process_auxtrace_info(union perf_event *event, 146 + struct perf_session *session) 147 + { 148 + struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info; 149 + int event_header_size = sizeof(struct perf_event_header); 150 + int num_cpu; 151 + u64 *ptr = NULL; 152 + u64 hdr_version; 153 + 154 + if (auxtrace_info->header.size < (event_header_size + INFO_HEADER_SIZE)) 155 + return -EINVAL; 156 + 157 + /* First the global part */ 158 + ptr = (u64 *) auxtrace_info->priv; 159 + 160 + /* Look for version of the header */ 161 + hdr_version = ptr[0]; 162 + if (hdr_version > CS_HEADER_CURRENT_VERSION) { 163 + pr_err("\nCS ETM Trace: Unknown Header Version = %#" PRIx64, hdr_version); 164 + pr_err(", version supported <= %x\n", CS_HEADER_CURRENT_VERSION); 165 + return -EINVAL; 166 + } 167 + 168 + if (dump_trace) { 169 + num_cpu = ptr[CS_PMU_TYPE_CPUS] & 0xffffffff; 170 + cs_etm__print_auxtrace_info(ptr, num_cpu); 171 + } 172 + 173 + return cs_etm__process_auxtrace_info_full(event, session); 174 + }
+7 -163
tools/perf/util/cs-etm.c
··· 2510 2510 return timeless_decoding; 2511 2511 } 2512 2512 2513 - static const char * const cs_etm_global_header_fmts[] = { 2514 - [CS_HEADER_VERSION] = " Header version %llx\n", 2515 - [CS_PMU_TYPE_CPUS] = " PMU type/num cpus %llx\n", 2516 - [CS_ETM_SNAPSHOT] = " Snapshot %llx\n", 2517 - }; 2518 - 2519 - static const char * const cs_etm_priv_fmts[] = { 2520 - [CS_ETM_MAGIC] = " Magic number %llx\n", 2521 - [CS_ETM_CPU] = " CPU %lld\n", 2522 - [CS_ETM_NR_TRC_PARAMS] = " NR_TRC_PARAMS %llx\n", 2523 - [CS_ETM_ETMCR] = " ETMCR %llx\n", 2524 - [CS_ETM_ETMTRACEIDR] = " ETMTRACEIDR %llx\n", 2525 - [CS_ETM_ETMCCER] = " ETMCCER %llx\n", 2526 - [CS_ETM_ETMIDR] = " ETMIDR %llx\n", 2527 - }; 2528 - 2529 - static const char * const cs_etmv4_priv_fmts[] = { 2530 - [CS_ETM_MAGIC] = " Magic number %llx\n", 2531 - [CS_ETM_CPU] = " CPU %lld\n", 2532 - [CS_ETM_NR_TRC_PARAMS] = " NR_TRC_PARAMS %llx\n", 2533 - [CS_ETMV4_TRCCONFIGR] = " TRCCONFIGR %llx\n", 2534 - [CS_ETMV4_TRCTRACEIDR] = " TRCTRACEIDR %llx\n", 2535 - [CS_ETMV4_TRCIDR0] = " TRCIDR0 %llx\n", 2536 - [CS_ETMV4_TRCIDR1] = " TRCIDR1 %llx\n", 2537 - [CS_ETMV4_TRCIDR2] = " TRCIDR2 %llx\n", 2538 - [CS_ETMV4_TRCIDR8] = " TRCIDR8 %llx\n", 2539 - [CS_ETMV4_TRCAUTHSTATUS] = " TRCAUTHSTATUS %llx\n", 2540 - [CS_ETE_TRCDEVARCH] = " TRCDEVARCH %llx\n" 2541 - }; 2542 - 2543 - static const char * const param_unk_fmt = 2544 - " Unknown parameter [%d] %"PRIx64"\n"; 2545 - static const char * const magic_unk_fmt = 2546 - " Magic number Unknown %"PRIx64"\n"; 2547 - 2548 - static int cs_etm__print_cpu_metadata_v0(u64 *val, int *offset) 2549 - { 2550 - int i = *offset, j, nr_params = 0, fmt_offset; 2551 - u64 magic; 2552 - 2553 - /* check magic value */ 2554 - magic = val[i + CS_ETM_MAGIC]; 2555 - if ((magic != __perf_cs_etmv3_magic) && 2556 - (magic != __perf_cs_etmv4_magic)) { 2557 - /* failure - note bad magic value */ 2558 - fprintf(stdout, magic_unk_fmt, magic); 2559 - return -EINVAL; 2560 - } 2561 - 2562 - /* print common header block */ 2563 - fprintf(stdout, cs_etm_priv_fmts[CS_ETM_MAGIC], val[i++]); 2564 - fprintf(stdout, cs_etm_priv_fmts[CS_ETM_CPU], val[i++]); 2565 - 2566 - if (magic == __perf_cs_etmv3_magic) { 2567 - nr_params = CS_ETM_NR_TRC_PARAMS_V0; 2568 - fmt_offset = CS_ETM_ETMCR; 2569 - /* after common block, offset format index past NR_PARAMS */ 2570 - for (j = fmt_offset; j < nr_params + fmt_offset; j++, i++) 2571 - fprintf(stdout, cs_etm_priv_fmts[j], val[i]); 2572 - } else if (magic == __perf_cs_etmv4_magic) { 2573 - nr_params = CS_ETMV4_NR_TRC_PARAMS_V0; 2574 - fmt_offset = CS_ETMV4_TRCCONFIGR; 2575 - /* after common block, offset format index past NR_PARAMS */ 2576 - for (j = fmt_offset; j < nr_params + fmt_offset; j++, i++) 2577 - fprintf(stdout, cs_etmv4_priv_fmts[j], val[i]); 2578 - } 2579 - *offset = i; 2580 - return 0; 2581 - } 2582 - 2583 - static int cs_etm__print_cpu_metadata_v1(u64 *val, int *offset) 2584 - { 2585 - int i = *offset, j, total_params = 0; 2586 - u64 magic; 2587 - 2588 - magic = val[i + CS_ETM_MAGIC]; 2589 - /* total params to print is NR_PARAMS + common block size for v1 */ 2590 - total_params = val[i + CS_ETM_NR_TRC_PARAMS] + CS_ETM_COMMON_BLK_MAX_V1; 2591 - 2592 - if (magic == __perf_cs_etmv3_magic) { 2593 - for (j = 0; j < total_params; j++, i++) { 2594 - /* if newer record - could be excess params */ 2595 - if (j >= CS_ETM_PRIV_MAX) 2596 - fprintf(stdout, param_unk_fmt, j, val[i]); 2597 - else 2598 - fprintf(stdout, cs_etm_priv_fmts[j], val[i]); 2599 - } 2600 - } else if (magic == __perf_cs_etmv4_magic || magic == __perf_cs_ete_magic) { 2601 - /* 2602 - * ETE and ETMv4 can be printed in the same block because the number of parameters 2603 - * is saved and they share the list of parameter names. ETE is also only supported 2604 - * in V1 files. 2605 - */ 2606 - for (j = 0; j < total_params; j++, i++) { 2607 - /* if newer record - could be excess params */ 2608 - if (j >= CS_ETE_PRIV_MAX) 2609 - fprintf(stdout, param_unk_fmt, j, val[i]); 2610 - else 2611 - fprintf(stdout, cs_etmv4_priv_fmts[j], val[i]); 2612 - } 2613 - } else { 2614 - /* failure - note bad magic value and error out */ 2615 - fprintf(stdout, magic_unk_fmt, magic); 2616 - return -EINVAL; 2617 - } 2618 - *offset = i; 2619 - return 0; 2620 - } 2621 - 2622 - static void cs_etm__print_auxtrace_info(u64 *val, int num) 2623 - { 2624 - int i, cpu = 0, version, err; 2625 - 2626 - version = val[0]; 2627 - 2628 - for (i = 0; i < CS_HEADER_VERSION_MAX; i++) 2629 - fprintf(stdout, cs_etm_global_header_fmts[i], val[i]); 2630 - 2631 - for (i = CS_HEADER_VERSION_MAX; cpu < num; cpu++) { 2632 - if (version == 0) 2633 - err = cs_etm__print_cpu_metadata_v0(val, &i); 2634 - else if (version == 1) 2635 - err = cs_etm__print_cpu_metadata_v1(val, &i); 2636 - if (err) 2637 - return; 2638 - } 2639 - } 2640 - 2641 2513 /* 2642 2514 * Read a single cpu parameter block from the auxtrace_info priv block. 2643 2515 * ··· 2746 2874 return 0; 2747 2875 } 2748 2876 2749 - int cs_etm__process_auxtrace_info(union perf_event *event, 2750 - struct perf_session *session) 2877 + int cs_etm__process_auxtrace_info_full(union perf_event *event, 2878 + struct perf_session *session) 2751 2879 { 2752 2880 struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info; 2753 2881 struct cs_etm_auxtrace *etm = NULL; 2754 2882 struct int_node *inode; 2755 - unsigned int pmu_type; 2756 2883 int event_header_size = sizeof(struct perf_event_header); 2757 - int info_header_size; 2758 2884 int total_size = auxtrace_info->header.size; 2759 2885 int priv_size = 0; 2760 2886 int num_cpu, trcidr_idx; ··· 2760 2890 int i, j; 2761 2891 u64 *ptr = NULL; 2762 2892 u64 **metadata = NULL; 2763 - u64 hdr_version; 2764 - 2765 - /* 2766 - * sizeof(auxtrace_info_event::type) + 2767 - * sizeof(auxtrace_info_event::reserved) == 8 2768 - */ 2769 - info_header_size = 8; 2770 - 2771 - if (total_size < (event_header_size + info_header_size)) 2772 - return -EINVAL; 2773 - 2774 - priv_size = total_size - event_header_size - info_header_size; 2775 - 2776 - /* First the global part */ 2777 - ptr = (u64 *) auxtrace_info->priv; 2778 - 2779 - /* Look for version of the header */ 2780 - hdr_version = ptr[0]; 2781 - if (hdr_version > CS_HEADER_CURRENT_VERSION) { 2782 - pr_err("\nCS ETM Trace: Unknown Header Version = %#" PRIx64, hdr_version); 2783 - pr_err(", version supported <= %x\n", CS_HEADER_CURRENT_VERSION); 2784 - return -EINVAL; 2785 - } 2786 - 2787 - num_cpu = ptr[CS_PMU_TYPE_CPUS] & 0xffffffff; 2788 - pmu_type = (unsigned int) ((ptr[CS_PMU_TYPE_CPUS] >> 32) & 2789 - 0xffffffff); 2790 - 2791 - if (dump_trace) 2792 - cs_etm__print_auxtrace_info(ptr, num_cpu); 2793 2893 2794 2894 /* 2795 2895 * Create an RB tree for traceID-metadata tuple. Since the conversion ··· 2770 2930 if (!traceid_list) 2771 2931 return -ENOMEM; 2772 2932 2933 + /* First the global part */ 2934 + ptr = (u64 *) auxtrace_info->priv; 2935 + num_cpu = ptr[CS_PMU_TYPE_CPUS] & 0xffffffff; 2773 2936 metadata = zalloc(sizeof(*metadata) * num_cpu); 2774 2937 if (!metadata) { 2775 2938 err = -ENOMEM; ··· 2851 3008 * The following tests if the correct number of double words was 2852 3009 * present in the auxtrace info section. 2853 3010 */ 3011 + priv_size = total_size - event_header_size - INFO_HEADER_SIZE; 2854 3012 if (i * 8 != priv_size) { 2855 3013 err = -EINVAL; 2856 3014 goto err_free_metadata; ··· 2880 3036 etm->machine = &session->machines.host; 2881 3037 2882 3038 etm->num_cpu = num_cpu; 2883 - etm->pmu_type = pmu_type; 3039 + etm->pmu_type = (unsigned int) ((ptr[CS_PMU_TYPE_CPUS] >> 32) & 0xffffffff); 2884 3040 etm->snapshot_mode = (ptr[CS_ETM_SNAPSHOT] != 0); 2885 3041 etm->metadata = metadata; 2886 3042 etm->auxtrace_type = auxtrace_info->type;
+9 -3
tools/perf/util/cs-etm.h
··· 202 202 #define CS_ETMV4_PRIV_SIZE (CS_ETMV4_PRIV_MAX * sizeof(u64)) 203 203 #define CS_ETE_PRIV_SIZE (CS_ETE_PRIV_MAX * sizeof(u64)) 204 204 205 - #ifdef HAVE_CSTRACE_SUPPORT 205 + #define INFO_HEADER_SIZE (sizeof(((struct perf_record_auxtrace_info *)0)->type) + \ 206 + sizeof(((struct perf_record_auxtrace_info *)0)->reserved__)) 207 + 206 208 int cs_etm__process_auxtrace_info(union perf_event *event, 207 209 struct perf_session *session); 210 + 211 + #ifdef HAVE_CSTRACE_SUPPORT 208 212 int cs_etm__get_cpu(u8 trace_chan_id, int *cpu); 209 213 int cs_etm__get_pid_fmt(u8 trace_chan_id, u64 *pid_fmt); 210 214 int cs_etm__etmq_set_tid(struct cs_etm_queue *etmq, ··· 218 214 u8 trace_chan_id); 219 215 struct cs_etm_packet_queue 220 216 *cs_etm__etmq_get_packet_queue(struct cs_etm_queue *etmq, u8 trace_chan_id); 217 + int cs_etm__process_auxtrace_info_full(union perf_event *event __maybe_unused, 218 + struct perf_session *session __maybe_unused); 221 219 #else 222 220 static inline int 223 - cs_etm__process_auxtrace_info(union perf_event *event __maybe_unused, 224 - struct perf_session *session __maybe_unused) 221 + cs_etm__process_auxtrace_info_full(union perf_event *event __maybe_unused, 222 + struct perf_session *session __maybe_unused) 225 223 { 226 224 pr_err("\nCS ETM Trace: OpenCSD is not linked in, please recompile with CORESIGHT=1\n"); 227 225 return -1;