未验证 提交 baa5f88e 编写于 作者: O openeuler-ci-bot 提交者: Gitee

!282 Synchronize the code of mainline perf tool and support the parsing of TRBE trace data

Merge Pull Request from: @hejunhao3 
 

```shell
Synchronize the code of mainline perf tool and support the parsing of TRBE trace data.

[test log]
estuary:/$ perf record -e /cs_etm/@trbe3/ -C 3 -o trace.data taskset -c 3 uname -a
Linux (none) 5.10.0+ #7 SMP PREEMPT Thu Nov 24 11:26:48 CST 2022 aarch64 GNU/Linux
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.851 MB trace.data ]
/estuary:/$ perf report --stdio -i trace.data -D > report.txt
estuary:/$ grep -rn "ETE" report.txt
5835:. ... CoreSight ETE Trace data: size 0xd0d00 bytes
estuary:/$ grep -rn "I_ASYNC : Alignment Synchronisation." report.txt | tail -n 5
497159:	Idx:816712; ID:7;	I_ASYNC : Alignment Synchronisation.
499987:	Idx:820816; ID:7;	I_ASYNC : Alignment Synchronisation.
502722:	Idx:824928; ID:7;	I_ASYNC : Alignment Synchronisation.
505083:	Idx:829040; ID:7;	I_ASYNC : Alignment Synchronisation.
507427:	Idx:833132; ID:7;	I_ASYNC : Alignment Synchronisation.
estuary:/$   
estuary:/$ perf record -e /cs_etm/@tmc_etr0/ -C 2 -o trace.data taskset -c 2 uname -a
Linux (none) 5.10.0+ #7 SMP PREEMPT Thu Nov 24 11:26:48 CST 2022 aarch64 GNU/Linux
[82501.067549] coresight tmc_etr0: timeout while waiting for completion of Manual Flush
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.690 MB trace.data ]
/estuary:/$ perf report --stdio -i trace.data -D > report.txt
estuary:/$ grep -rn "ETE" report.txt
8528:. ... CoreSight ETE Trace data: size 0xa40d0 bytes
estuary:/$ grep -rn "I_ASYNC : Alignment Synchronisation." report.txt | tail -n 5
349615:	Idx:633382; ID:5;	I_ASYNC : Alignment Synchronisation.
350304:	Idx:634786; ID:5;	I_ASYNC : Alignment Synchronisation.
352589:	Idx:639200; ID:5;	I_ASYNC : Alignment Synchronisation.
354957:	Idx:643604; ID:5;	I_ASYNC : Alignment Synchronisation.
357246:	Idx:648003; ID:5;	I_ASYNC : Alignment Synchronisation.
estuary:/$   
estuary:/$ perf record -C 0 -e arm_spe_0/branch_filter=1/ -o branch.data  sleep 3s
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.663 MB branch.data ]
estuary:/$ perf report -D -i branch.data > branch.log
estuary:/$ grep -rn "B COND" branch.log  | tail -=n 5 
133506:.  000996d4:  4a 01                                           B COND
133517:.  0009970c:  4a 01                                           B COND
133539:.  0009977c:  4a 01                                           B COND
133572:.  00099824:  4a 01                                           B COND
133671:.  00099a1c:  4a 01                                           B COND
estuary:/$ perf -v
perf version 5.10.gede0fc40b9bf
``` 
 
Link:https://gitee.com/openeuler/kernel/pulls/282 
Reviewed-by: Zheng Zengkai <zhengzengkai@huawei.com> 
Reviewed-by: Ling Mingqiang <lingmingqiang@huawei.com> 
Signed-off-by: Zheng Zengkai <zhengzengkai@huawei.com> 
...@@ -4,9 +4,9 @@ ...@@ -4,9 +4,9 @@
/* /*
* Check OpenCSD library version is sufficient to provide required features * Check OpenCSD library version is sufficient to provide required features
*/ */
#define OCSD_MIN_VER ((1 << 16) | (0 << 8) | (0)) #define OCSD_MIN_VER ((1 << 16) | (1 << 8) | (1))
#if !defined(OCSD_VER_NUM) || (OCSD_VER_NUM < OCSD_MIN_VER) #if !defined(OCSD_VER_NUM) || (OCSD_VER_NUM < OCSD_MIN_VER)
#error "OpenCSD >= 1.0.0 is required" #error "OpenCSD >= 1.1.1 is required"
#endif #endif
int main(void) int main(void)
......
...@@ -12,16 +12,21 @@ ...@@ -12,16 +12,21 @@
#define CORESIGHT_ETM_CSID_MAX 0x70 #define CORESIGHT_ETM_CSID_MAX 0x70
/* ETMv3.5/PTM's ETMCR config bit */ /* ETMv3.5/PTM's ETMCR config bit */
#define ETM_OPT_BRANCH_BROADCAST 8
#define ETM_OPT_CYCACC 12 #define ETM_OPT_CYCACC 12
#define ETM_OPT_CTXTID 14 #define ETM_OPT_CTXTID 14
#define ETM_OPT_CTXTID2 15
#define ETM_OPT_TS 28 #define ETM_OPT_TS 28
#define ETM_OPT_RETSTK 29 #define ETM_OPT_RETSTK 29
/* ETMv4 CONFIGR programming bits for the ETM OPTs */ /* ETMv4 CONFIGR programming bits for the ETM OPTs */
#define ETM4_CFG_BIT_BB 3
#define ETM4_CFG_BIT_CYCACC 4 #define ETM4_CFG_BIT_CYCACC 4
#define ETM4_CFG_BIT_CTXTID 6 #define ETM4_CFG_BIT_CTXTID 6
#define ETM4_CFG_BIT_VMID 7
#define ETM4_CFG_BIT_TS 11 #define ETM4_CFG_BIT_TS 11
#define ETM4_CFG_BIT_RETSTK 12 #define ETM4_CFG_BIT_RETSTK 12
#define ETM4_CFG_BIT_VMID_OPT 15
static inline int coresight_get_trace_id(int cpu) static inline int coresight_get_trace_id(int cpu)
{ {
......
...@@ -143,12 +143,16 @@ enum perf_event_sample_format { ...@@ -143,12 +143,16 @@ enum perf_event_sample_format {
PERF_SAMPLE_PHYS_ADDR = 1U << 19, PERF_SAMPLE_PHYS_ADDR = 1U << 19,
PERF_SAMPLE_AUX = 1U << 20, PERF_SAMPLE_AUX = 1U << 20,
PERF_SAMPLE_CGROUP = 1U << 21, PERF_SAMPLE_CGROUP = 1U << 21,
PERF_SAMPLE_DATA_PAGE_SIZE = 1U << 22,
PERF_SAMPLE_CODE_PAGE_SIZE = 1U << 23,
PERF_SAMPLE_WEIGHT_STRUCT = 1U << 24,
PERF_SAMPLE_MAX = 1U << 22, /* non-ABI */ PERF_SAMPLE_MAX = 1U << 25, /* non-ABI */
__PERF_SAMPLE_CALLCHAIN_EARLY = 1ULL << 63, /* non-ABI; internal use */ __PERF_SAMPLE_CALLCHAIN_EARLY = 1ULL << 63, /* non-ABI; internal use */
}; };
#define PERF_SAMPLE_WEIGHT_TYPE (PERF_SAMPLE_WEIGHT | PERF_SAMPLE_WEIGHT_STRUCT)
/* /*
* values to program into branch_sample_type when PERF_SAMPLE_BRANCH is set * values to program into branch_sample_type when PERF_SAMPLE_BRANCH is set
* *
...@@ -307,6 +311,7 @@ enum perf_event_read_format { ...@@ -307,6 +311,7 @@ enum perf_event_read_format {
#define PERF_ATTR_SIZE_VER4 104 /* add: sample_regs_intr */ #define PERF_ATTR_SIZE_VER4 104 /* add: sample_regs_intr */
#define PERF_ATTR_SIZE_VER5 112 /* add: aux_watermark */ #define PERF_ATTR_SIZE_VER5 112 /* add: aux_watermark */
#define PERF_ATTR_SIZE_VER6 120 /* add: aux_sample_size */ #define PERF_ATTR_SIZE_VER6 120 /* add: aux_sample_size */
#define PERF_ATTR_SIZE_VER7 128 /* add: sig_data */
/* /*
* Hardware event_id to monitor via a performance monitoring event: * Hardware event_id to monitor via a performance monitoring event:
...@@ -888,7 +893,24 @@ enum perf_event_type { ...@@ -888,7 +893,24 @@ enum perf_event_type {
* char data[size]; * char data[size];
* u64 dyn_size; } && PERF_SAMPLE_STACK_USER * u64 dyn_size; } && PERF_SAMPLE_STACK_USER
* *
* { u64 weight; } && PERF_SAMPLE_WEIGHT * { union perf_sample_weight
* {
* u64 full; && PERF_SAMPLE_WEIGHT
* #if defined(__LITTLE_ENDIAN_BITFIELD)
* struct {
* u32 var1_dw;
* u16 var2_w;
* u16 var3_w;
* } && PERF_SAMPLE_WEIGHT_STRUCT
* #elif defined(__BIG_ENDIAN_BITFIELD)
* struct {
* u16 var3_w;
* u16 var2_w;
* u32 var1_dw;
* } && PERF_SAMPLE_WEIGHT_STRUCT
* #endif
* }
* }
* { u64 data_src; } && PERF_SAMPLE_DATA_SRC * { u64 data_src; } && PERF_SAMPLE_DATA_SRC
* { u64 transaction; } && PERF_SAMPLE_TRANSACTION * { u64 transaction; } && PERF_SAMPLE_TRANSACTION
* { u64 abi; # enum perf_sample_regs_abi * { u64 abi; # enum perf_sample_regs_abi
...@@ -1101,10 +1123,15 @@ enum perf_callchain_context { ...@@ -1101,10 +1123,15 @@ enum perf_callchain_context {
/** /**
* PERF_RECORD_AUX::flags bits * PERF_RECORD_AUX::flags bits
*/ */
#define PERF_AUX_FLAG_TRUNCATED 0x01 /* record was truncated to fit */ #define PERF_AUX_FLAG_TRUNCATED 0x01 /* record was truncated to fit */
#define PERF_AUX_FLAG_OVERWRITE 0x02 /* snapshot from overwrite mode */ #define PERF_AUX_FLAG_OVERWRITE 0x02 /* snapshot from overwrite mode */
#define PERF_AUX_FLAG_PARTIAL 0x04 /* record contains gaps */ #define PERF_AUX_FLAG_PARTIAL 0x04 /* record contains gaps */
#define PERF_AUX_FLAG_COLLISION 0x08 /* sample collided with another */ #define PERF_AUX_FLAG_COLLISION 0x08 /* sample collided with another */
#define PERF_AUX_FLAG_PMU_FORMAT_TYPE_MASK 0xff00 /* PMU specific trace format type */
/* CoreSight PMU AUX buffer formats */
#define PERF_AUX_FLAG_CORESIGHT_FORMAT_CORESIGHT 0x0000 /* Default for backward compatibility */
#define PERF_AUX_FLAG_CORESIGHT_FORMAT_RAW 0x0100 /* Raw format of the source */
#define PERF_FLAG_FD_NO_GROUP (1UL << 0) #define PERF_FLAG_FD_NO_GROUP (1UL << 0)
#define PERF_FLAG_FD_OUTPUT (1UL << 1) #define PERF_FLAG_FD_OUTPUT (1UL << 1)
...@@ -1123,14 +1150,24 @@ union perf_mem_data_src { ...@@ -1123,14 +1150,24 @@ union perf_mem_data_src {
mem_lvl_num:4, /* memory hierarchy level number */ mem_lvl_num:4, /* memory hierarchy level number */
mem_remote:1, /* remote */ mem_remote:1, /* remote */
mem_snoopx:2, /* snoop mode, ext */ mem_snoopx:2, /* snoop mode, ext */
#ifdef __GENKSYMS__
mem_rsvd:24; mem_rsvd:24;
#else
mem_blk:3, /* access blocked */
mem_rsvd:21;
#endif
}; };
}; };
#elif defined(__BIG_ENDIAN_BITFIELD) #elif defined(__BIG_ENDIAN_BITFIELD)
union perf_mem_data_src { union perf_mem_data_src {
__u64 val; __u64 val;
struct { struct {
#ifdef __GENKSYMS__
__u64 mem_rsvd:24, __u64 mem_rsvd:24,
#else
__u64 mem_rsvd:21,
mem_blk:3, /* access blocked */
#endif
mem_snoopx:2, /* snoop mode, ext */ mem_snoopx:2, /* snoop mode, ext */
mem_remote:1, /* remote */ mem_remote:1, /* remote */
mem_lvl_num:4, /* memory hierarchy level number */ mem_lvl_num:4, /* memory hierarchy level number */
...@@ -1213,6 +1250,12 @@ union perf_mem_data_src { ...@@ -1213,6 +1250,12 @@ union perf_mem_data_src {
#define PERF_MEM_TLB_OS 0x40 /* OS fault handler */ #define PERF_MEM_TLB_OS 0x40 /* OS fault handler */
#define PERF_MEM_TLB_SHIFT 26 #define PERF_MEM_TLB_SHIFT 26
/* Access blocked */
#define PERF_MEM_BLK_NA 0x01 /* not available */
#define PERF_MEM_BLK_DATA 0x02 /* data could not be forwarded */
#define PERF_MEM_BLK_ADDR 0x04 /* address conflict */
#define PERF_MEM_BLK_SHIFT 40
#define PERF_MEM_S(a, s) \ #define PERF_MEM_S(a, s) \
(((__u64)PERF_MEM_##a##_##s) << PERF_MEM_##a##_SHIFT) (((__u64)PERF_MEM_##a##_##s) << PERF_MEM_##a##_SHIFT)
...@@ -1244,4 +1287,23 @@ struct perf_branch_entry { ...@@ -1244,4 +1287,23 @@ struct perf_branch_entry {
reserved:40; reserved:40;
}; };
union perf_sample_weight {
__u64 full;
#if defined(__LITTLE_ENDIAN_BITFIELD)
struct {
__u32 var1_dw;
__u16 var2_w;
__u16 var3_w;
};
#elif defined(__BIG_ENDIAN_BITFIELD)
struct {
__u16 var3_w;
__u16 var2_w;
__u32 var1_dw;
};
#else
#error "Unknown endianness"
#endif
};
#endif /* _UAPI_LINUX_PERF_EVENT_H */ #endif /* _UAPI_LINUX_PERF_EVENT_H */
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
L synthesize last branch entries on existing event records L synthesize last branch entries on existing event records
s skip initial number of events s skip initial number of events
q quicker (less detailed) decoding q quicker (less detailed) decoding
Z prefer to ignore timestamps (so-called "timeless" decoding)
The default is all events i.e. the same as --itrace=ibxwpe, The default is all events i.e. the same as --itrace=ibxwpe,
except for perf script where it is --itrace=ce except for perf script where it is --itrace=ce
......
...@@ -38,8 +38,6 @@ struct cs_etm_recording { ...@@ -38,8 +38,6 @@ struct cs_etm_recording {
struct auxtrace_record itr; struct auxtrace_record itr;
struct perf_pmu *cs_etm_pmu; struct perf_pmu *cs_etm_pmu;
struct evlist *evlist; struct evlist *evlist;
int wrapped_cnt;
bool *wrapped;
bool snapshot_mode; bool snapshot_mode;
size_t snapshot_size; size_t snapshot_size;
}; };
...@@ -49,15 +47,17 @@ static const char *metadata_etmv3_ro[CS_ETM_PRIV_MAX] = { ...@@ -49,15 +47,17 @@ static const char *metadata_etmv3_ro[CS_ETM_PRIV_MAX] = {
[CS_ETM_ETMIDR] = "mgmt/etmidr", [CS_ETM_ETMIDR] = "mgmt/etmidr",
}; };
static const char *metadata_etmv4_ro[CS_ETMV4_PRIV_MAX] = { static const char * const metadata_etmv4_ro[] = {
[CS_ETMV4_TRCIDR0] = "trcidr/trcidr0", [CS_ETMV4_TRCIDR0] = "trcidr/trcidr0",
[CS_ETMV4_TRCIDR1] = "trcidr/trcidr1", [CS_ETMV4_TRCIDR1] = "trcidr/trcidr1",
[CS_ETMV4_TRCIDR2] = "trcidr/trcidr2", [CS_ETMV4_TRCIDR2] = "trcidr/trcidr2",
[CS_ETMV4_TRCIDR8] = "trcidr/trcidr8", [CS_ETMV4_TRCIDR8] = "trcidr/trcidr8",
[CS_ETMV4_TRCAUTHSTATUS] = "mgmt/trcauthstatus", [CS_ETMV4_TRCAUTHSTATUS] = "mgmt/trcauthstatus",
[CS_ETE_TRCDEVARCH] = "mgmt/trcdevarch"
}; };
static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu); static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu);
static bool cs_etm_is_ete(struct auxtrace_record *itr, int cpu);
static int cs_etm_set_context_id(struct auxtrace_record *itr, static int cs_etm_set_context_id(struct auxtrace_record *itr,
struct evsel *evsel, int cpu) struct evsel *evsel, int cpu)
...@@ -67,6 +67,7 @@ static int cs_etm_set_context_id(struct auxtrace_record *itr, ...@@ -67,6 +67,7 @@ static int cs_etm_set_context_id(struct auxtrace_record *itr,
char path[PATH_MAX]; char path[PATH_MAX];
int err = -EINVAL; int err = -EINVAL;
u32 val; u32 val;
u64 contextid;
ptr = container_of(itr, struct cs_etm_recording, itr); ptr = container_of(itr, struct cs_etm_recording, itr);
cs_etm_pmu = ptr->cs_etm_pmu; cs_etm_pmu = ptr->cs_etm_pmu;
...@@ -74,7 +75,7 @@ static int cs_etm_set_context_id(struct auxtrace_record *itr, ...@@ -74,7 +75,7 @@ static int cs_etm_set_context_id(struct auxtrace_record *itr,
if (!cs_etm_is_etmv4(itr, cpu)) if (!cs_etm_is_etmv4(itr, cpu))
goto out; goto out;
/* Get a handle on TRCIRD2 */ /* Get a handle on TRCIDR2 */
snprintf(path, PATH_MAX, "cpu%d/%s", snprintf(path, PATH_MAX, "cpu%d/%s",
cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2]); cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2]);
err = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val); err = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val);
...@@ -86,25 +87,59 @@ static int cs_etm_set_context_id(struct auxtrace_record *itr, ...@@ -86,25 +87,59 @@ static int cs_etm_set_context_id(struct auxtrace_record *itr,
goto out; goto out;
} }
/* User has configured for PID tracing, respects it. */
contextid = evsel->core.attr.config &
(BIT(ETM_OPT_CTXTID) | BIT(ETM_OPT_CTXTID2));
/* /*
* TRCIDR2.CIDSIZE, bit [9-5], indicates whether contextID tracing * If user doesn't configure the contextid format, parse PMU format and
* is supported: * enable PID tracing according to the "contextid" format bits:
* 0b00000 Context ID tracing is not supported. *
* 0b00100 Maximum of 32-bit Context ID size. * If bit ETM_OPT_CTXTID is set, trace CONTEXTIDR_EL1;
* All other values are reserved. * If bit ETM_OPT_CTXTID2 is set, trace CONTEXTIDR_EL2.
*/ */
val = BMVAL(val, 5, 9); if (!contextid)
if (!val || val != 0x4) { contextid = perf_pmu__format_bits(&cs_etm_pmu->format,
err = -EINVAL; "contextid");
goto out;
if (contextid & BIT(ETM_OPT_CTXTID)) {
/*
* TRCIDR2.CIDSIZE, bit [9-5], indicates whether contextID
* tracing is supported:
* 0b00000 Context ID tracing is not supported.
* 0b00100 Maximum of 32-bit Context ID size.
* All other values are reserved.
*/
val = BMVAL(val, 5, 9);
if (!val || val != 0x4) {
pr_err("%s: CONTEXTIDR_EL1 isn't supported\n",
CORESIGHT_ETM_PMU_NAME);
err = -EINVAL;
goto out;
}
}
if (contextid & BIT(ETM_OPT_CTXTID2)) {
/*
* TRCIDR2.VMIDOPT[30:29] != 0 and
* TRCIDR2.VMIDSIZE[14:10] == 0b00100 (32bit virtual contextid)
* We can't support CONTEXTIDR in VMID if the size of the
* virtual context id is < 32bit.
* Any value of VMIDSIZE >= 4 (i.e, > 32bit) is fine for us.
*/
if (!BMVAL(val, 29, 30) || BMVAL(val, 10, 14) < 4) {
pr_err("%s: CONTEXTIDR_EL2 isn't supported\n",
CORESIGHT_ETM_PMU_NAME);
err = -EINVAL;
goto out;
}
} }
/* All good, let the kernel know */ /* All good, let the kernel know */
evsel->core.attr.config |= (1 << ETM_OPT_CTXTID); evsel->core.attr.config |= contextid;
err = 0; err = 0;
out: out:
return err; return err;
} }
...@@ -169,17 +204,17 @@ static int cs_etm_set_option(struct auxtrace_record *itr, ...@@ -169,17 +204,17 @@ static int cs_etm_set_option(struct auxtrace_record *itr,
!cpu_map__has(online_cpus, i)) !cpu_map__has(online_cpus, i))
continue; continue;
if (option & ETM_OPT_CTXTID) { if (option & BIT(ETM_OPT_CTXTID)) {
err = cs_etm_set_context_id(itr, evsel, i); err = cs_etm_set_context_id(itr, evsel, i);
if (err) if (err)
goto out; goto out;
} }
if (option & ETM_OPT_TS) { if (option & BIT(ETM_OPT_TS)) {
err = cs_etm_set_timestamp(itr, evsel, i); err = cs_etm_set_timestamp(itr, evsel, i);
if (err) if (err)
goto out; goto out;
} }
if (option & ~(ETM_OPT_CTXTID | ETM_OPT_TS)) if (option & ~(BIT(ETM_OPT_CTXTID) | BIT(ETM_OPT_TS)))
/* Nothing else is currently supported */ /* Nothing else is currently supported */
goto out; goto out;
} }
...@@ -368,25 +403,6 @@ static int cs_etm_recording_options(struct auxtrace_record *itr, ...@@ -368,25 +403,6 @@ static int cs_etm_recording_options(struct auxtrace_record *itr,
} }
/* Validate auxtrace_mmap_pages provided by user */
if (opts->auxtrace_mmap_pages) {
unsigned int max_page = (KiB(128) / page_size);
size_t sz = opts->auxtrace_mmap_pages * (size_t)page_size;
if (!privileged &&
opts->auxtrace_mmap_pages > max_page) {
opts->auxtrace_mmap_pages = max_page;
pr_err("auxtrace too big, truncating to %d\n",
max_page);
}
if (!is_power_of_2(sz)) {
pr_err("Invalid mmap size for %s: must be a power of 2\n",
CORESIGHT_ETM_PMU_NAME);
return -EINVAL;
}
}
if (opts->auxtrace_snapshot_mode) if (opts->auxtrace_snapshot_mode)
pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME, pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME,
opts->auxtrace_snapshot_size); opts->auxtrace_snapshot_size);
...@@ -406,7 +422,7 @@ static int cs_etm_recording_options(struct auxtrace_record *itr, ...@@ -406,7 +422,7 @@ static int cs_etm_recording_options(struct auxtrace_record *itr,
evsel__set_sample_bit(cs_etm_evsel, CPU); evsel__set_sample_bit(cs_etm_evsel, CPU);
err = cs_etm_set_option(itr, cs_etm_evsel, err = cs_etm_set_option(itr, cs_etm_evsel,
ETM_OPT_CTXTID | ETM_OPT_TS); BIT(ETM_OPT_CTXTID) | BIT(ETM_OPT_TS));
if (err) if (err)
goto out; goto out;
} }
...@@ -485,6 +501,11 @@ static u64 cs_etmv4_get_config(struct auxtrace_record *itr) ...@@ -485,6 +501,11 @@ static u64 cs_etmv4_get_config(struct auxtrace_record *itr)
config |= BIT(ETM4_CFG_BIT_TS); config |= BIT(ETM4_CFG_BIT_TS);
if (config_opts & BIT(ETM_OPT_RETSTK)) if (config_opts & BIT(ETM_OPT_RETSTK))
config |= BIT(ETM4_CFG_BIT_RETSTK); config |= BIT(ETM4_CFG_BIT_RETSTK);
if (config_opts & BIT(ETM_OPT_CTXTID2))
config |= BIT(ETM4_CFG_BIT_VMID) |
BIT(ETM4_CFG_BIT_VMID_OPT);
if (config_opts & BIT(ETM_OPT_BRANCH_BROADCAST))
config |= BIT(ETM4_CFG_BIT_BB);
return config; return config;
} }
...@@ -494,7 +515,7 @@ cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, ...@@ -494,7 +515,7 @@ cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused,
struct evlist *evlist __maybe_unused) struct evlist *evlist __maybe_unused)
{ {
int i; int i;
int etmv3 = 0, etmv4 = 0; int etmv3 = 0, etmv4 = 0, ete = 0;
struct perf_cpu_map *event_cpus = evlist->core.cpus; struct perf_cpu_map *event_cpus = evlist->core.cpus;
struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL); struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL);
...@@ -505,7 +526,9 @@ cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, ...@@ -505,7 +526,9 @@ cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused,
!cpu_map__has(online_cpus, i)) !cpu_map__has(online_cpus, i))
continue; continue;
if (cs_etm_is_etmv4(itr, i)) if (cs_etm_is_ete(itr, i))
ete++;
else if (cs_etm_is_etmv4(itr, i))
etmv4++; etmv4++;
else else
etmv3++; etmv3++;
...@@ -516,7 +539,9 @@ cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, ...@@ -516,7 +539,9 @@ cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused,
if (!cpu_map__has(online_cpus, i)) if (!cpu_map__has(online_cpus, i))
continue; continue;
if (cs_etm_is_etmv4(itr, i)) if (cs_etm_is_ete(itr, i))
ete++;
else if (cs_etm_is_etmv4(itr, i))
etmv4++; etmv4++;
else else
etmv3++; etmv3++;
...@@ -526,6 +551,7 @@ cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, ...@@ -526,6 +551,7 @@ cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused,
perf_cpu_map__put(online_cpus); perf_cpu_map__put(online_cpus);
return (CS_ETM_HEADER_SIZE + return (CS_ETM_HEADER_SIZE +
(ete * CS_ETE_PRIV_SIZE) +
(etmv4 * CS_ETMV4_PRIV_SIZE) + (etmv4 * CS_ETMV4_PRIV_SIZE) +
(etmv3 * CS_ETMV3_PRIV_SIZE)); (etmv3 * CS_ETMV3_PRIV_SIZE));
} }
...@@ -568,45 +594,78 @@ static int cs_etm_get_ro(struct perf_pmu *pmu, int cpu, const char *path) ...@@ -568,45 +594,78 @@ static int cs_etm_get_ro(struct perf_pmu *pmu, int cpu, const char *path)
return val; return val;
} }
#define TRCDEVARCH_ARCHPART_SHIFT 0
#define TRCDEVARCH_ARCHPART_MASK GENMASK(11, 0)
#define TRCDEVARCH_ARCHPART(x) (((x) & TRCDEVARCH_ARCHPART_MASK) >> TRCDEVARCH_ARCHPART_SHIFT)
#define TRCDEVARCH_ARCHVER_SHIFT 12
#define TRCDEVARCH_ARCHVER_MASK GENMASK(15, 12)
#define TRCDEVARCH_ARCHVER(x) (((x) & TRCDEVARCH_ARCHVER_MASK) >> TRCDEVARCH_ARCHVER_SHIFT)
static bool cs_etm_is_ete(struct auxtrace_record *itr, int cpu)
{
struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr);
struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
int trcdevarch = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETE_TRCDEVARCH]);
/*
* ETE if ARCHVER is 5 (ARCHVER is 4 for ETM) and ARCHPART is 0xA13.
* See ETM_DEVARCH_ETE_ARCH in coresight-etm4x.h
*/
return TRCDEVARCH_ARCHVER(trcdevarch) == 5 && TRCDEVARCH_ARCHPART(trcdevarch) == 0xA13;
}
static void cs_etm_save_etmv4_header(__u64 data[], struct auxtrace_record *itr, int cpu)
{
struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr);
struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
/* Get trace configuration register */
data[CS_ETMV4_TRCCONFIGR] = cs_etmv4_get_config(itr);
/* Get traceID from the framework */
data[CS_ETMV4_TRCTRACEIDR] = coresight_get_trace_id(cpu);
/* Get read-only information from sysFS */
data[CS_ETMV4_TRCIDR0] = cs_etm_get_ro(cs_etm_pmu, cpu,
metadata_etmv4_ro[CS_ETMV4_TRCIDR0]);
data[CS_ETMV4_TRCIDR1] = cs_etm_get_ro(cs_etm_pmu, cpu,
metadata_etmv4_ro[CS_ETMV4_TRCIDR1]);
data[CS_ETMV4_TRCIDR2] = cs_etm_get_ro(cs_etm_pmu, cpu,
metadata_etmv4_ro[CS_ETMV4_TRCIDR2]);
data[CS_ETMV4_TRCIDR8] = cs_etm_get_ro(cs_etm_pmu, cpu,
metadata_etmv4_ro[CS_ETMV4_TRCIDR8]);
data[CS_ETMV4_TRCAUTHSTATUS] = cs_etm_get_ro(cs_etm_pmu, cpu,
metadata_etmv4_ro[CS_ETMV4_TRCAUTHSTATUS]);
}
static void cs_etm_get_metadata(int cpu, u32 *offset, static void cs_etm_get_metadata(int cpu, u32 *offset,
struct auxtrace_record *itr, struct auxtrace_record *itr,
struct perf_record_auxtrace_info *info) struct perf_record_auxtrace_info *info)
{ {
u32 increment; u32 increment, nr_trc_params;
u64 magic; u64 magic;
struct cs_etm_recording *ptr = struct cs_etm_recording *ptr =
container_of(itr, struct cs_etm_recording, itr); container_of(itr, struct cs_etm_recording, itr);
struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
/* first see what kind of tracer this cpu is affined to */ /* first see what kind of tracer this cpu is affined to */
if (cs_etm_is_etmv4(itr, cpu)) { if (cs_etm_is_ete(itr, cpu)) {
magic = __perf_cs_etmv4_magic; magic = __perf_cs_ete_magic;
/* Get trace configuration register */ /* ETE uses the same registers as ETMv4 plus TRCDEVARCH */
info->priv[*offset + CS_ETMV4_TRCCONFIGR] = cs_etm_save_etmv4_header(&info->priv[*offset], itr, cpu);
cs_etmv4_get_config(itr); info->priv[*offset + CS_ETE_TRCDEVARCH] =
/* Get traceID from the framework */
info->priv[*offset + CS_ETMV4_TRCTRACEIDR] =
coresight_get_trace_id(cpu);
/* Get read-only information from sysFS */
info->priv[*offset + CS_ETMV4_TRCIDR0] =
cs_etm_get_ro(cs_etm_pmu, cpu,
metadata_etmv4_ro[CS_ETMV4_TRCIDR0]);
info->priv[*offset + CS_ETMV4_TRCIDR1] =
cs_etm_get_ro(cs_etm_pmu, cpu,
metadata_etmv4_ro[CS_ETMV4_TRCIDR1]);
info->priv[*offset + CS_ETMV4_TRCIDR2] =
cs_etm_get_ro(cs_etm_pmu, cpu,
metadata_etmv4_ro[CS_ETMV4_TRCIDR2]);
info->priv[*offset + CS_ETMV4_TRCIDR8] =
cs_etm_get_ro(cs_etm_pmu, cpu, cs_etm_get_ro(cs_etm_pmu, cpu,
metadata_etmv4_ro[CS_ETMV4_TRCIDR8]); metadata_etmv4_ro[CS_ETE_TRCDEVARCH]);
info->priv[*offset + CS_ETMV4_TRCAUTHSTATUS] =
cs_etm_get_ro(cs_etm_pmu, cpu, /* How much space was used */
metadata_etmv4_ro increment = CS_ETE_PRIV_MAX;
[CS_ETMV4_TRCAUTHSTATUS]); nr_trc_params = CS_ETE_PRIV_MAX - CS_ETM_COMMON_BLK_MAX_V1;
} else if (cs_etm_is_etmv4(itr, cpu)) {
magic = __perf_cs_etmv4_magic;
cs_etm_save_etmv4_header(&info->priv[*offset], itr, cpu);
/* How much space was used */ /* How much space was used */
increment = CS_ETMV4_PRIV_MAX; increment = CS_ETMV4_PRIV_MAX;
nr_trc_params = CS_ETMV4_PRIV_MAX - CS_ETMV4_TRCCONFIGR;
} else { } else {
magic = __perf_cs_etmv3_magic; magic = __perf_cs_etmv3_magic;
/* Get configuration register */ /* Get configuration register */
...@@ -624,11 +683,13 @@ static void cs_etm_get_metadata(int cpu, u32 *offset, ...@@ -624,11 +683,13 @@ static void cs_etm_get_metadata(int cpu, u32 *offset,
/* How much space was used */ /* How much space was used */
increment = CS_ETM_PRIV_MAX; increment = CS_ETM_PRIV_MAX;
nr_trc_params = CS_ETM_PRIV_MAX - CS_ETM_ETMCR;
} }
/* Build generic header portion */ /* Build generic header portion */
info->priv[*offset + CS_ETM_MAGIC] = magic; info->priv[*offset + CS_ETM_MAGIC] = magic;
info->priv[*offset + CS_ETM_CPU] = cpu; info->priv[*offset + CS_ETM_CPU] = cpu;
info->priv[*offset + CS_ETM_NR_TRC_PARAMS] = nr_trc_params;
/* Where the next CPU entry should start from */ /* Where the next CPU entry should start from */
*offset += increment; *offset += increment;
} }
...@@ -674,7 +735,7 @@ static int cs_etm_info_fill(struct auxtrace_record *itr, ...@@ -674,7 +735,7 @@ static int cs_etm_info_fill(struct auxtrace_record *itr,
/* First fill out the session header */ /* First fill out the session header */
info->type = PERF_AUXTRACE_CS_ETM; info->type = PERF_AUXTRACE_CS_ETM;
info->priv[CS_HEADER_VERSION_0] = 0; info->priv[CS_HEADER_VERSION] = CS_HEADER_CURRENT_VERSION;
info->priv[CS_PMU_TYPE_CPUS] = type << 32; info->priv[CS_PMU_TYPE_CPUS] = type << 32;
info->priv[CS_PMU_TYPE_CPUS] |= nr_cpu; info->priv[CS_PMU_TYPE_CPUS] |= nr_cpu;
info->priv[CS_ETM_SNAPSHOT] = ptr->snapshot_mode; info->priv[CS_ETM_SNAPSHOT] = ptr->snapshot_mode;
...@@ -690,135 +751,6 @@ static int cs_etm_info_fill(struct auxtrace_record *itr, ...@@ -690,135 +751,6 @@ static int cs_etm_info_fill(struct auxtrace_record *itr,
return 0; return 0;
} }
static int cs_etm_alloc_wrapped_array(struct cs_etm_recording *ptr, int idx)
{
bool *wrapped;
int cnt = ptr->wrapped_cnt;
/* Make @ptr->wrapped as big as @idx */
while (cnt <= idx)
cnt++;
/*
* Free'ed in cs_etm_recording_free(). Using realloc() to avoid
* cross compilation problems where the host's system supports
* reallocarray() but not the target.
*/
wrapped = realloc(ptr->wrapped, cnt * sizeof(bool));
if (!wrapped)
return -ENOMEM;
wrapped[cnt - 1] = false;
ptr->wrapped_cnt = cnt;
ptr->wrapped = wrapped;
return 0;
}
static bool cs_etm_buffer_has_wrapped(unsigned char *buffer,
size_t buffer_size, u64 head)
{
u64 i, watermark;
u64 *buf = (u64 *)buffer;
size_t buf_size = buffer_size;
/*
* We want to look the very last 512 byte (chosen arbitrarily) in
* the ring buffer.
*/
watermark = buf_size - 512;
/*
* @head is continuously increasing - if its value is equal or greater
* than the size of the ring buffer, it has wrapped around.
*/
if (head >= buffer_size)
return true;
/*
* The value of @head is somewhere within the size of the ring buffer.
* This can be that there hasn't been enough data to fill the ring
* buffer yet or the trace time was so long that @head has numerically
* wrapped around. To find we need to check if we have data at the very
* end of the ring buffer. We can reliably do this because mmap'ed
* pages are zeroed out and there is a fresh mapping with every new
* session.
*/
/* @head is less than 512 byte from the end of the ring buffer */
if (head > watermark)
watermark = head;
/*
* Speed things up by using 64 bit transactions (see "u64 *buf" above)
*/
watermark >>= 3;
buf_size >>= 3;
/*
* If we find trace data at the end of the ring buffer, @head has
* been there and has numerically wrapped around at least once.
*/
for (i = watermark; i < buf_size; i++)
if (buf[i])
return true;
return false;
}
static int cs_etm_find_snapshot(struct auxtrace_record *itr,
int idx, struct auxtrace_mmap *mm,
unsigned char *data,
u64 *head, u64 *old)
{
int err;
bool wrapped;
struct cs_etm_recording *ptr =
container_of(itr, struct cs_etm_recording, itr);
/*
* Allocate memory to keep track of wrapping if this is the first
* time we deal with this *mm.
*/
if (idx >= ptr->wrapped_cnt) {
err = cs_etm_alloc_wrapped_array(ptr, idx);
if (err)
return err;
}
/*
* Check to see if *head has wrapped around. If it hasn't only the
* amount of data between *head and *old is snapshot'ed to avoid
* bloating the perf.data file with zeros. But as soon as *head has
* wrapped around the entire size of the AUX ring buffer it taken.
*/
wrapped = ptr->wrapped[idx];
if (!wrapped && cs_etm_buffer_has_wrapped(data, mm->len, *head)) {
wrapped = true;
ptr->wrapped[idx] = true;
}
pr_debug3("%s: mmap index %d old head %zu new head %zu size %zu\n",
__func__, idx, (size_t)*old, (size_t)*head, mm->len);
/* No wrap has occurred, we can just use *head and *old. */
if (!wrapped)
return 0;
/*
* *head has wrapped around - adjust *head and *old to pickup the
* entire content of the AUX buffer.
*/
if (*head >= mm->len) {
*old = *head - mm->len;
} else {
*head += mm->len;
*old = *head - mm->len;
}
return 0;
}
static int cs_etm_snapshot_start(struct auxtrace_record *itr) static int cs_etm_snapshot_start(struct auxtrace_record *itr)
{ {
struct cs_etm_recording *ptr = struct cs_etm_recording *ptr =
...@@ -856,7 +788,6 @@ static void cs_etm_recording_free(struct auxtrace_record *itr) ...@@ -856,7 +788,6 @@ static void cs_etm_recording_free(struct auxtrace_record *itr)
struct cs_etm_recording *ptr = struct cs_etm_recording *ptr =
container_of(itr, struct cs_etm_recording, itr); container_of(itr, struct cs_etm_recording, itr);
zfree(&ptr->wrapped);
free(ptr); free(ptr);
} }
...@@ -884,7 +815,6 @@ struct auxtrace_record *cs_etm_record_init(int *err) ...@@ -884,7 +815,6 @@ struct auxtrace_record *cs_etm_record_init(int *err)
ptr->itr.recording_options = cs_etm_recording_options; ptr->itr.recording_options = cs_etm_recording_options;
ptr->itr.info_priv_size = cs_etm_info_priv_size; ptr->itr.info_priv_size = cs_etm_info_priv_size;
ptr->itr.info_fill = cs_etm_info_fill; ptr->itr.info_fill = cs_etm_info_fill;
ptr->itr.find_snapshot = cs_etm_find_snapshot;
ptr->itr.snapshot_start = cs_etm_snapshot_start; ptr->itr.snapshot_start = cs_etm_snapshot_start;
ptr->itr.snapshot_finish = cs_etm_snapshot_finish; ptr->itr.snapshot_finish = cs_etm_snapshot_finish;
ptr->itr.reference = cs_etm_reference; ptr->itr.reference = cs_etm_reference;
......
...@@ -5,7 +5,7 @@ group_fd=-1 ...@@ -5,7 +5,7 @@ group_fd=-1
flags=0|8 flags=0|8
cpu=* cpu=*
type=0|1 type=0|1
size=120 size=128
config=0 config=0
sample_period=* sample_period=*
sample_type=263 sample_type=263
......
...@@ -5,7 +5,7 @@ group_fd=-1 ...@@ -5,7 +5,7 @@ group_fd=-1
flags=0|8 flags=0|8
cpu=* cpu=*
type=0 type=0
size=120 size=128
config=0 config=0
sample_period=0 sample_period=0
sample_type=65536 sample_type=65536
......
...@@ -7,7 +7,7 @@ cpu=* ...@@ -7,7 +7,7 @@ cpu=*
pid=-1 pid=-1
flags=8 flags=8
type=1 type=1
size=120 size=128
config=9 config=9
sample_period=4000 sample_period=4000
sample_type=455 sample_type=455
......
...@@ -919,6 +919,7 @@ int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, ...@@ -919,6 +919,7 @@ int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,
err = symbol__annotate2(ms, evsel, opts, &browser.arch); err = symbol__annotate2(ms, evsel, opts, &browser.arch);
if (err) { if (err) {
char msg[BUFSIZ]; char msg[BUFSIZ];
ms->map->dso->annotate_warned = true;
symbol__strerror_disassemble(ms, err, msg, sizeof(msg)); symbol__strerror_disassemble(ms, err, msg, sizeof(msg));
ui__error("Couldn't annotate %s:\n%s", sym->name, msg); ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
goto out_free_offsets; goto out_free_offsets;
......
...@@ -177,6 +177,7 @@ static int symbol__gtk_annotate(struct map_symbol *ms, struct evsel *evsel, ...@@ -177,6 +177,7 @@ static int symbol__gtk_annotate(struct map_symbol *ms, struct evsel *evsel,
err = symbol__annotate(ms, evsel, &annotation__default_options, NULL); err = symbol__annotate(ms, evsel, &annotation__default_options, NULL);
if (err) { if (err) {
char msg[BUFSIZ]; char msg[BUFSIZ];
ms->map->dso->annotate_warned = true;
symbol__strerror_disassemble(ms, err, msg, sizeof(msg)); symbol__strerror_disassemble(ms, err, msg, sizeof(msg));
ui__error("Couldn't annotate %s: %s\n", sym->name, msg); ui__error("Couldn't annotate %s: %s\n", sym->name, msg);
return -1; return -1;
......
...@@ -2778,9 +2778,17 @@ int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel, ...@@ -2778,9 +2778,17 @@ int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel,
struct rb_root source_line = RB_ROOT; struct rb_root source_line = RB_ROOT;
struct hists *hists = evsel__hists(evsel); struct hists *hists = evsel__hists(evsel);
char buf[1024]; char buf[1024];
int err;
err = symbol__annotate2(ms, evsel, opts, NULL);
if (err) {
char msg[BUFSIZ];
if (symbol__annotate2(ms, evsel, opts, NULL) < 0) dso->annotate_warned = true;
symbol__strerror_disassemble(ms, err, msg, sizeof(msg));
ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
return -1; return -1;
}
if (opts->print_lines) { if (opts->print_lines) {
srcline_full_filename = opts->full_path; srcline_full_filename = opts->full_path;
...@@ -2804,9 +2812,17 @@ int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel, ...@@ -2804,9 +2812,17 @@ int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel,
struct dso *dso = ms->map->dso; struct dso *dso = ms->map->dso;
struct symbol *sym = ms->sym; struct symbol *sym = ms->sym;
struct rb_root source_line = RB_ROOT; struct rb_root source_line = RB_ROOT;
int err;
err = symbol__annotate(ms, evsel, opts, NULL);
if (err) {
char msg[BUFSIZ];
if (symbol__annotate(ms, evsel, opts, NULL) < 0) dso->annotate_warned = true;
symbol__strerror_disassemble(ms, err, msg, sizeof(msg));
ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
return -1; return -1;
}
symbol__calc_percent(sym, evsel); symbol__calc_percent(sym, evsel);
......
...@@ -1561,6 +1561,9 @@ int itrace_parse_synth_opts(const struct option *opt, const char *str, ...@@ -1561,6 +1561,9 @@ int itrace_parse_synth_opts(const struct option *opt, const char *str,
case 'q': case 'q':
synth_opts->quick += 1; synth_opts->quick += 1;
break; break;
case 'Z':
synth_opts->timeless_decoding = true;
break;
case ' ': case ' ':
case ',': case ',':
break; break;
......
...@@ -90,6 +90,7 @@ enum itrace_period_type { ...@@ -90,6 +90,7 @@ enum itrace_period_type {
* @tlb: whether to synthesize TLB events * @tlb: whether to synthesize TLB events
* @remote_access: whether to synthesize remote access events * @remote_access: whether to synthesize remote access events
* @mem: whether to synthesize memory events * @mem: whether to synthesize memory events
* @timeless_decoding: prefer "timeless" decoding i.e. ignore timestamps
* @callchain_sz: maximum callchain size * @callchain_sz: maximum callchain size
* @last_branch_sz: branch context size * @last_branch_sz: branch context size
* @period: 'instructions' events period * @period: 'instructions' events period
...@@ -129,6 +130,7 @@ struct itrace_synth_opts { ...@@ -129,6 +130,7 @@ struct itrace_synth_opts {
bool tlb; bool tlb;
bool remote_access; bool remote_access;
bool mem; bool mem;
bool timeless_decoding;
unsigned int callchain_sz; unsigned int callchain_sz;
unsigned int last_branch_sz; unsigned int last_branch_sz;
unsigned long long period; unsigned long long period;
......
...@@ -6,16 +6,17 @@ ...@@ -6,16 +6,17 @@
* Author: Mathieu Poirier <mathieu.poirier@linaro.org> * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
*/ */
#include <asm/bug.h>
#include <linux/coresight-pmu.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/zalloc.h> #include <linux/zalloc.h>
#include <stdlib.h> #include <stdlib.h>
#include <opencsd/c_api/opencsd_c_api.h> #include <opencsd/c_api/opencsd_c_api.h>
#include <opencsd/etmv4/trc_pkt_types_etmv4.h>
#include <opencsd/ocsd_if_types.h>
#include "cs-etm.h" #include "cs-etm.h"
#include "cs-etm-decoder.h" #include "cs-etm-decoder.h"
#include "debug.h"
#include "intlist.h" #include "intlist.h"
/* use raw logging */ /* use raw logging */
...@@ -32,9 +33,11 @@ ...@@ -32,9 +33,11 @@
struct cs_etm_decoder { struct cs_etm_decoder {
void *data; void *data;
void (*packet_printer)(const char *msg); void (*packet_printer)(const char *msg);
bool suppress_printing;
dcd_tree_handle_t dcd_tree; dcd_tree_handle_t dcd_tree;
cs_etm_mem_cb_type mem_access; cs_etm_mem_cb_type mem_access;
ocsd_datapath_resp_t prev_return; ocsd_datapath_resp_t prev_return;
const char *decoder_name;
}; };
static u32 static u32
...@@ -71,9 +74,10 @@ int cs_etm_decoder__reset(struct cs_etm_decoder *decoder) ...@@ -71,9 +74,10 @@ int cs_etm_decoder__reset(struct cs_etm_decoder *decoder)
ocsd_datapath_resp_t dp_ret; ocsd_datapath_resp_t dp_ret;
decoder->prev_return = OCSD_RESP_CONT; decoder->prev_return = OCSD_RESP_CONT;
decoder->suppress_printing = true;
dp_ret = ocsd_dt_process_data(decoder->dcd_tree, OCSD_OP_RESET, dp_ret = ocsd_dt_process_data(decoder->dcd_tree, OCSD_OP_RESET,
0, 0, NULL, NULL); 0, 0, NULL, NULL);
decoder->suppress_printing = false;
if (OCSD_DATA_RESP_IS_FATAL(dp_ret)) if (OCSD_DATA_RESP_IS_FATAL(dp_ret))
return -1; return -1;
...@@ -121,6 +125,21 @@ static int cs_etm_decoder__gen_etmv3_config(struct cs_etm_trace_params *params, ...@@ -121,6 +125,21 @@ static int cs_etm_decoder__gen_etmv3_config(struct cs_etm_trace_params *params,
return 0; return 0;
} }
#define TRCIDR1_TRCARCHMIN_SHIFT 4
#define TRCIDR1_TRCARCHMIN_MASK GENMASK(7, 4)
#define TRCIDR1_TRCARCHMIN(x) (((x) & TRCIDR1_TRCARCHMIN_MASK) >> TRCIDR1_TRCARCHMIN_SHIFT)
static enum _ocsd_arch_version cs_etm_decoder__get_etmv4_arch_ver(u32 reg_idr1)
{
/*
* For ETMv4 if the trace minor version is 4 or more then we can assume
* the architecture is ARCH_AA64 rather than just V8.
* ARCH_V8 = V8 architecture
* ARCH_AA64 = Min v8r3 plus additional AA64 PE features
*/
return TRCIDR1_TRCARCHMIN(reg_idr1) >= 4 ? ARCH_AA64 : ARCH_V8;
}
static void cs_etm_decoder__gen_etmv4_config(struct cs_etm_trace_params *params, static void cs_etm_decoder__gen_etmv4_config(struct cs_etm_trace_params *params,
ocsd_etmv4_cfg *config) ocsd_etmv4_cfg *config)
{ {
...@@ -135,7 +154,21 @@ static void cs_etm_decoder__gen_etmv4_config(struct cs_etm_trace_params *params, ...@@ -135,7 +154,21 @@ static void cs_etm_decoder__gen_etmv4_config(struct cs_etm_trace_params *params,
config->reg_idr11 = 0; config->reg_idr11 = 0;
config->reg_idr12 = 0; config->reg_idr12 = 0;
config->reg_idr13 = 0; config->reg_idr13 = 0;
config->arch_ver = ARCH_V8; config->arch_ver = cs_etm_decoder__get_etmv4_arch_ver(params->etmv4.reg_idr1);
config->core_prof = profile_CortexA;
}
static void cs_etm_decoder__gen_ete_config(struct cs_etm_trace_params *params,
ocsd_ete_cfg *config)
{
config->reg_configr = params->ete.reg_configr;
config->reg_traceidr = params->ete.reg_traceidr;
config->reg_idr0 = params->ete.reg_idr0;
config->reg_idr1 = params->ete.reg_idr1;
config->reg_idr2 = params->ete.reg_idr2;
config->reg_idr8 = params->ete.reg_idr8;
config->reg_devarch = params->ete.reg_devarch;
config->arch_ver = ARCH_AA64;
config->core_prof = profile_CortexA; config->core_prof = profile_CortexA;
} }
...@@ -143,8 +176,10 @@ static void cs_etm_decoder__print_str_cb(const void *p_context, ...@@ -143,8 +176,10 @@ static void cs_etm_decoder__print_str_cb(const void *p_context,
const char *msg, const char *msg,
const int str_len) const int str_len)
{ {
if (p_context && str_len) const struct cs_etm_decoder *decoder = p_context;
((struct cs_etm_decoder *)p_context)->packet_printer(msg);
if (p_context && str_len && !decoder->suppress_printing)
decoder->packet_printer(msg);
} }
static int static int
...@@ -220,68 +255,19 @@ cs_etm_decoder__init_raw_frame_logging( ...@@ -220,68 +255,19 @@ cs_etm_decoder__init_raw_frame_logging(
} }
#endif #endif
static int cs_etm_decoder__create_packet_printer(struct cs_etm_decoder *decoder,
const char *decoder_name,
void *trace_config)
{
u8 csid;
if (ocsd_dt_create_decoder(decoder->dcd_tree, decoder_name,
OCSD_CREATE_FLG_PACKET_PROC,
trace_config, &csid))
return -1;
if (ocsd_dt_set_pkt_protocol_printer(decoder->dcd_tree, csid, 0))
return -1;
return 0;
}
static int
cs_etm_decoder__create_etm_packet_printer(struct cs_etm_trace_params *t_params,
struct cs_etm_decoder *decoder)
{
const char *decoder_name;
ocsd_etmv3_cfg config_etmv3;
ocsd_etmv4_cfg trace_config_etmv4;
void *trace_config;
switch (t_params->protocol) {
case CS_ETM_PROTO_ETMV3:
case CS_ETM_PROTO_PTM:
cs_etm_decoder__gen_etmv3_config(t_params, &config_etmv3);
decoder_name = (t_params->protocol == CS_ETM_PROTO_ETMV3) ?
OCSD_BUILTIN_DCD_ETMV3 :
OCSD_BUILTIN_DCD_PTM;
trace_config = &config_etmv3;
break;
case CS_ETM_PROTO_ETMV4i:
cs_etm_decoder__gen_etmv4_config(t_params, &trace_config_etmv4);
decoder_name = OCSD_BUILTIN_DCD_ETMV4I;
trace_config = &trace_config_etmv4;
break;
default:
return -1;
}
return cs_etm_decoder__create_packet_printer(decoder,
decoder_name,
trace_config);
}
static ocsd_datapath_resp_t static ocsd_datapath_resp_t
cs_etm_decoder__do_soft_timestamp(struct cs_etm_queue *etmq, cs_etm_decoder__do_soft_timestamp(struct cs_etm_queue *etmq,
struct cs_etm_packet_queue *packet_queue, struct cs_etm_packet_queue *packet_queue,
const uint8_t trace_chan_id) const uint8_t trace_chan_id)
{ {
/* No timestamp packet has been received, nothing to do */ /* No timestamp packet has been received, nothing to do */
if (!packet_queue->timestamp) if (!packet_queue->cs_timestamp)
return OCSD_RESP_CONT; return OCSD_RESP_CONT;
packet_queue->timestamp = packet_queue->next_timestamp; packet_queue->cs_timestamp = packet_queue->next_cs_timestamp;
/* Estimate the timestamp for the next range packet */ /* Estimate the timestamp for the next range packet */
packet_queue->next_timestamp += packet_queue->instr_count; packet_queue->next_cs_timestamp += packet_queue->instr_count;
packet_queue->instr_count = 0; packet_queue->instr_count = 0;
/* Tell the front end which traceid_queue needs attention */ /* Tell the front end which traceid_queue needs attention */
...@@ -293,7 +279,8 @@ cs_etm_decoder__do_soft_timestamp(struct cs_etm_queue *etmq, ...@@ -293,7 +279,8 @@ cs_etm_decoder__do_soft_timestamp(struct cs_etm_queue *etmq,
static ocsd_datapath_resp_t static ocsd_datapath_resp_t
cs_etm_decoder__do_hard_timestamp(struct cs_etm_queue *etmq, cs_etm_decoder__do_hard_timestamp(struct cs_etm_queue *etmq,
const ocsd_generic_trace_elem *elem, const ocsd_generic_trace_elem *elem,
const uint8_t trace_chan_id) const uint8_t trace_chan_id,
const ocsd_trc_index_t indx)
{ {
struct cs_etm_packet_queue *packet_queue; struct cs_etm_packet_queue *packet_queue;
...@@ -307,20 +294,41 @@ cs_etm_decoder__do_hard_timestamp(struct cs_etm_queue *etmq, ...@@ -307,20 +294,41 @@ cs_etm_decoder__do_hard_timestamp(struct cs_etm_queue *etmq,
* Function do_soft_timestamp() will report the value to the front end, * Function do_soft_timestamp() will report the value to the front end,
* hence asking the decoder to keep decoding rather than stopping. * hence asking the decoder to keep decoding rather than stopping.
*/ */
if (packet_queue->timestamp) { if (packet_queue->cs_timestamp) {
packet_queue->next_timestamp = elem->timestamp; packet_queue->next_cs_timestamp = elem->timestamp;
return OCSD_RESP_CONT; return OCSD_RESP_CONT;
} }
/* if (!elem->timestamp) {
* This is the first timestamp we've seen since the beginning of traces /*
* or a discontinuity. Since timestamps packets are generated *after* * Zero timestamps can be seen due to misconfiguration or hardware bugs.
* range packets have been generated, we need to estimate the time at * Warn once, and don't try to subtract instr_count as it would result in an
* which instructions started by substracting the number of instructions * underflow.
* executed to the timestamp. */
*/ packet_queue->cs_timestamp = 0;
packet_queue->timestamp = elem->timestamp - packet_queue->instr_count; if (!cs_etm__etmq_is_timeless(etmq))
packet_queue->next_timestamp = elem->timestamp; pr_warning_once("Zero Coresight timestamp found at Idx:%" OCSD_TRC_IDX_STR
". Decoding may be improved by prepending 'Z' to your current --itrace arguments.\n",
indx);
} else if (packet_queue->instr_count > elem->timestamp) {
/*
* Sanity check that the elem->timestamp - packet_queue->instr_count would not
* result in an underflow. Warn and clamp at 0 if it would.
*/
packet_queue->cs_timestamp = 0;
pr_err("Timestamp calculation underflow at Idx:%" OCSD_TRC_IDX_STR "\n", indx);
} else {
/*
* This is the first timestamp we've seen since the beginning of traces
* or a discontinuity. Since timestamps packets are generated *after*
* range packets have been generated, we need to estimate the time at
* which instructions started by subtracting the number of instructions
* executed to the timestamp.
*/
packet_queue->cs_timestamp = elem->timestamp - packet_queue->instr_count;
}
packet_queue->next_cs_timestamp = elem->timestamp;
packet_queue->instr_count = 0; packet_queue->instr_count = 0;
/* Tell the front end which traceid_queue needs attention */ /* Tell the front end which traceid_queue needs attention */
...@@ -333,8 +341,8 @@ cs_etm_decoder__do_hard_timestamp(struct cs_etm_queue *etmq, ...@@ -333,8 +341,8 @@ cs_etm_decoder__do_hard_timestamp(struct cs_etm_queue *etmq,
static void static void
cs_etm_decoder__reset_timestamp(struct cs_etm_packet_queue *packet_queue) cs_etm_decoder__reset_timestamp(struct cs_etm_packet_queue *packet_queue)
{ {
packet_queue->timestamp = 0; packet_queue->cs_timestamp = 0;
packet_queue->next_timestamp = 0; packet_queue->next_cs_timestamp = 0;
packet_queue->instr_count = 0; packet_queue->instr_count = 0;
} }
...@@ -491,13 +499,42 @@ cs_etm_decoder__set_tid(struct cs_etm_queue *etmq, ...@@ -491,13 +499,42 @@ cs_etm_decoder__set_tid(struct cs_etm_queue *etmq,
const ocsd_generic_trace_elem *elem, const ocsd_generic_trace_elem *elem,
const uint8_t trace_chan_id) const uint8_t trace_chan_id)
{ {
pid_t tid; pid_t tid = -1;
static u64 pid_fmt;
int ret;
/*
* As all the ETMs run at the same exception level, the system should
* have the same PID format crossing CPUs. So cache the PID format
* and reuse it for sequential decoding.
*/
if (!pid_fmt) {
ret = cs_etm__get_pid_fmt(trace_chan_id, &pid_fmt);
if (ret)
return OCSD_RESP_FATAL_SYS_ERR;
}
/*
* Process the PE_CONTEXT packets if we have a valid contextID or VMID.
* If the kernel is running at EL2, the PID is traced in CONTEXTIDR_EL2
* as VMID, Bit ETM_OPT_CTXTID2 is set in this case.
*/
switch (pid_fmt) {
case BIT(ETM_OPT_CTXTID):
if (elem->context.ctxt_id_valid)
tid = elem->context.context_id;
break;
case BIT(ETM_OPT_CTXTID2):
if (elem->context.vmid_valid)
tid = elem->context.vmid;
break;
default:
break;
}
/* Ignore PE_CONTEXT packets that don't have a valid contextID */ if (tid == -1)
if (!elem->context.ctxt_id_valid)
return OCSD_RESP_CONT; return OCSD_RESP_CONT;
tid = elem->context.context_id;
if (cs_etm__etmq_set_tid(etmq, tid, trace_chan_id)) if (cs_etm__etmq_set_tid(etmq, tid, trace_chan_id))
return OCSD_RESP_FATAL_SYS_ERR; return OCSD_RESP_FATAL_SYS_ERR;
...@@ -512,7 +549,7 @@ cs_etm_decoder__set_tid(struct cs_etm_queue *etmq, ...@@ -512,7 +549,7 @@ cs_etm_decoder__set_tid(struct cs_etm_queue *etmq,
static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer( static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer(
const void *context, const void *context,
const ocsd_trc_index_t indx __maybe_unused, const ocsd_trc_index_t indx,
const u8 trace_chan_id __maybe_unused, const u8 trace_chan_id __maybe_unused,
const ocsd_generic_trace_elem *elem) const ocsd_generic_trace_elem *elem)
{ {
...@@ -549,7 +586,8 @@ static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer( ...@@ -549,7 +586,8 @@ static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer(
break; break;
case OCSD_GEN_TRC_ELEM_TIMESTAMP: case OCSD_GEN_TRC_ELEM_TIMESTAMP:
resp = cs_etm_decoder__do_hard_timestamp(etmq, elem, resp = cs_etm_decoder__do_hard_timestamp(etmq, elem,
trace_chan_id); trace_chan_id,
indx);
break; break;
case OCSD_GEN_TRC_ELEM_PE_CONTEXT: case OCSD_GEN_TRC_ELEM_PE_CONTEXT:
resp = cs_etm_decoder__set_tid(etmq, packet_queue, resp = cs_etm_decoder__set_tid(etmq, packet_queue,
...@@ -572,13 +610,14 @@ static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer( ...@@ -572,13 +610,14 @@ static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer(
return resp; return resp;
} }
static int cs_etm_decoder__create_etm_packet_decoder( static int
struct cs_etm_trace_params *t_params, cs_etm_decoder__create_etm_decoder(struct cs_etm_decoder_params *d_params,
struct cs_etm_decoder *decoder) struct cs_etm_trace_params *t_params,
struct cs_etm_decoder *decoder)
{ {
const char *decoder_name;
ocsd_etmv3_cfg config_etmv3; ocsd_etmv3_cfg config_etmv3;
ocsd_etmv4_cfg trace_config_etmv4; ocsd_etmv4_cfg trace_config_etmv4;
ocsd_ete_cfg trace_config_ete;
void *trace_config; void *trace_config;
u8 csid; u8 csid;
...@@ -586,51 +625,55 @@ static int cs_etm_decoder__create_etm_packet_decoder( ...@@ -586,51 +625,55 @@ static int cs_etm_decoder__create_etm_packet_decoder(
case CS_ETM_PROTO_ETMV3: case CS_ETM_PROTO_ETMV3:
case CS_ETM_PROTO_PTM: case CS_ETM_PROTO_PTM:
cs_etm_decoder__gen_etmv3_config(t_params, &config_etmv3); cs_etm_decoder__gen_etmv3_config(t_params, &config_etmv3);
decoder_name = (t_params->protocol == CS_ETM_PROTO_ETMV3) ? decoder->decoder_name = (t_params->protocol == CS_ETM_PROTO_ETMV3) ?
OCSD_BUILTIN_DCD_ETMV3 : OCSD_BUILTIN_DCD_ETMV3 :
OCSD_BUILTIN_DCD_PTM; OCSD_BUILTIN_DCD_PTM;
trace_config = &config_etmv3; trace_config = &config_etmv3;
break; break;
case CS_ETM_PROTO_ETMV4i: case CS_ETM_PROTO_ETMV4i:
cs_etm_decoder__gen_etmv4_config(t_params, &trace_config_etmv4); cs_etm_decoder__gen_etmv4_config(t_params, &trace_config_etmv4);
decoder_name = OCSD_BUILTIN_DCD_ETMV4I; decoder->decoder_name = OCSD_BUILTIN_DCD_ETMV4I;
trace_config = &trace_config_etmv4; trace_config = &trace_config_etmv4;
break; break;
case CS_ETM_PROTO_ETE:
cs_etm_decoder__gen_ete_config(t_params, &trace_config_ete);
decoder->decoder_name = OCSD_BUILTIN_DCD_ETE;
trace_config = &trace_config_ete;
break;
default: default:
return -1; return -1;
} }
if (ocsd_dt_create_decoder(decoder->dcd_tree, if (d_params->operation == CS_ETM_OPERATION_DECODE) {
decoder_name, if (ocsd_dt_create_decoder(decoder->dcd_tree,
OCSD_CREATE_FLG_FULL_DECODER, decoder->decoder_name,
trace_config, &csid)) OCSD_CREATE_FLG_FULL_DECODER,
return -1; trace_config, &csid))
return -1;
if (ocsd_dt_set_gen_elem_outfn(decoder->dcd_tree, if (ocsd_dt_set_gen_elem_outfn(decoder->dcd_tree,
cs_etm_decoder__gen_trace_elem_printer, cs_etm_decoder__gen_trace_elem_printer,
decoder)) decoder))
return -1; return -1;
return 0; return 0;
} } else if (d_params->operation == CS_ETM_OPERATION_PRINT) {
if (ocsd_dt_create_decoder(decoder->dcd_tree, decoder->decoder_name,
OCSD_CREATE_FLG_PACKET_PROC,
trace_config, &csid))
return -1;
static int if (ocsd_dt_set_pkt_protocol_printer(decoder->dcd_tree, csid, 0))
cs_etm_decoder__create_etm_decoder(struct cs_etm_decoder_params *d_params, return -1;
struct cs_etm_trace_params *t_params,
struct cs_etm_decoder *decoder) return 0;
{ }
if (d_params->operation == CS_ETM_OPERATION_PRINT)
return cs_etm_decoder__create_etm_packet_printer(t_params,
decoder);
else if (d_params->operation == CS_ETM_OPERATION_DECODE)
return cs_etm_decoder__create_etm_packet_decoder(t_params,
decoder);
return -1; return -1;
} }
struct cs_etm_decoder * struct cs_etm_decoder *
cs_etm_decoder__new(int num_cpu, struct cs_etm_decoder_params *d_params, cs_etm_decoder__new(int decoders, struct cs_etm_decoder_params *d_params,
struct cs_etm_trace_params t_params[]) struct cs_etm_trace_params t_params[])
{ {
struct cs_etm_decoder *decoder; struct cs_etm_decoder *decoder;
...@@ -675,7 +718,7 @@ cs_etm_decoder__new(int num_cpu, struct cs_etm_decoder_params *d_params, ...@@ -675,7 +718,7 @@ cs_etm_decoder__new(int num_cpu, struct cs_etm_decoder_params *d_params,
/* init raw frame logging if required */ /* init raw frame logging if required */
cs_etm_decoder__init_raw_frame_logging(d_params, decoder); cs_etm_decoder__init_raw_frame_logging(d_params, decoder);
for (i = 0; i < num_cpu; i++) { for (i = 0; i < decoders; i++) {
ret = cs_etm_decoder__create_etm_decoder(d_params, ret = cs_etm_decoder__create_etm_decoder(d_params,
&t_params[i], &t_params[i],
decoder); decoder);
...@@ -747,3 +790,8 @@ void cs_etm_decoder__free(struct cs_etm_decoder *decoder) ...@@ -747,3 +790,8 @@ void cs_etm_decoder__free(struct cs_etm_decoder *decoder)
decoder->dcd_tree = NULL; decoder->dcd_tree = NULL;
free(decoder); free(decoder);
} }
const char *cs_etm_decoder__get_name(struct cs_etm_decoder *decoder)
{
return decoder->decoder_name;
}
...@@ -37,11 +37,22 @@ struct cs_etmv4_trace_params { ...@@ -37,11 +37,22 @@ struct cs_etmv4_trace_params {
u32 reg_traceidr; u32 reg_traceidr;
}; };
struct cs_ete_trace_params {
u32 reg_idr0;
u32 reg_idr1;
u32 reg_idr2;
u32 reg_idr8;
u32 reg_configr;
u32 reg_traceidr;
u32 reg_devarch;
};
struct cs_etm_trace_params { struct cs_etm_trace_params {
int protocol; int protocol;
union { union {
struct cs_etmv3_trace_params etmv3; struct cs_etmv3_trace_params etmv3;
struct cs_etmv4_trace_params etmv4; struct cs_etmv4_trace_params etmv4;
struct cs_ete_trace_params ete;
}; };
}; };
...@@ -65,6 +76,7 @@ enum { ...@@ -65,6 +76,7 @@ enum {
CS_ETM_PROTO_ETMV4i, CS_ETM_PROTO_ETMV4i,
CS_ETM_PROTO_ETMV4d, CS_ETM_PROTO_ETMV4d,
CS_ETM_PROTO_PTM, CS_ETM_PROTO_PTM,
CS_ETM_PROTO_ETE
}; };
enum cs_etm_decoder_operation { enum cs_etm_decoder_operation {
...@@ -92,5 +104,6 @@ int cs_etm_decoder__get_packet(struct cs_etm_packet_queue *packet_queue, ...@@ -92,5 +104,6 @@ int cs_etm_decoder__get_packet(struct cs_etm_packet_queue *packet_queue,
struct cs_etm_packet *packet); struct cs_etm_packet *packet);
int cs_etm_decoder__reset(struct cs_etm_decoder *decoder); int cs_etm_decoder__reset(struct cs_etm_decoder *decoder);
const char *cs_etm_decoder__get_name(struct cs_etm_decoder *decoder);
#endif /* INCLUDE__CS_ETM_DECODER_H__ */ #endif /* INCLUDE__CS_ETM_DECODER_H__ */
此差异已折叠。
...@@ -17,23 +17,37 @@ struct perf_session; ...@@ -17,23 +17,37 @@ struct perf_session;
*/ */
enum { enum {
/* Starting with 0x0 */ /* Starting with 0x0 */
CS_HEADER_VERSION_0, CS_HEADER_VERSION,
/* PMU->type (32 bit), total # of CPUs (32 bit) */ /* PMU->type (32 bit), total # of CPUs (32 bit) */
CS_PMU_TYPE_CPUS, CS_PMU_TYPE_CPUS,
CS_ETM_SNAPSHOT, CS_ETM_SNAPSHOT,
CS_HEADER_VERSION_0_MAX, CS_HEADER_VERSION_MAX,
}; };
/*
* Update the version for new format.
*
* New version 1 format adds a param count to the per cpu metadata.
* This allows easy adding of new metadata parameters.
* Requires that new params always added after current ones.
* Also allows client reader to handle file versions that are different by
* checking the number of params in the file vs the number expected.
*/
#define CS_HEADER_CURRENT_VERSION 1
/* Beginning of header common to both ETMv3 and V4 */ /* Beginning of header common to both ETMv3 and V4 */
enum { enum {
CS_ETM_MAGIC, CS_ETM_MAGIC,
CS_ETM_CPU, CS_ETM_CPU,
/* Number of trace config params in following ETM specific block */
CS_ETM_NR_TRC_PARAMS,
CS_ETM_COMMON_BLK_MAX_V1,
}; };
/* ETMv3/PTM metadata */ /* ETMv3/PTM metadata */
enum { enum {
/* Dynamic, configurable parameters */ /* Dynamic, configurable parameters */
CS_ETM_ETMCR = CS_ETM_CPU + 1, CS_ETM_ETMCR = CS_ETM_COMMON_BLK_MAX_V1,
CS_ETM_ETMTRACEIDR, CS_ETM_ETMTRACEIDR,
/* RO, taken from sysFS */ /* RO, taken from sysFS */
CS_ETM_ETMCCER, CS_ETM_ETMCCER,
...@@ -41,10 +55,13 @@ enum { ...@@ -41,10 +55,13 @@ enum {
CS_ETM_PRIV_MAX, CS_ETM_PRIV_MAX,
}; };
/* define fixed version 0 length - allow new format reader to read old files. */
#define CS_ETM_NR_TRC_PARAMS_V0 (CS_ETM_ETMIDR - CS_ETM_ETMCR + 1)
/* ETMv4 metadata */ /* ETMv4 metadata */
enum { enum {
/* Dynamic, configurable parameters */ /* Dynamic, configurable parameters */
CS_ETMV4_TRCCONFIGR = CS_ETM_CPU + 1, CS_ETMV4_TRCCONFIGR = CS_ETM_COMMON_BLK_MAX_V1,
CS_ETMV4_TRCTRACEIDR, CS_ETMV4_TRCTRACEIDR,
/* RO, taken from sysFS */ /* RO, taken from sysFS */
CS_ETMV4_TRCIDR0, CS_ETMV4_TRCIDR0,
...@@ -55,6 +72,18 @@ enum { ...@@ -55,6 +72,18 @@ enum {
CS_ETMV4_PRIV_MAX, CS_ETMV4_PRIV_MAX,
}; };
/* define fixed version 0 length - allow new format reader to read old files. */
#define CS_ETMV4_NR_TRC_PARAMS_V0 (CS_ETMV4_TRCAUTHSTATUS - CS_ETMV4_TRCCONFIGR + 1)
/*
* ETE metadata is ETMv4 plus TRCDEVARCH register and doesn't support header V0 since it was
* added in header V1
*/
enum {
CS_ETE_TRCDEVARCH = CS_ETMV4_PRIV_MAX,
CS_ETE_PRIV_MAX
};
/* /*
* ETMv3 exception encoding number: * ETMv3 exception encoding number:
* See Embedded Trace Macrocell spcification (ARM IHI 0014Q) * See Embedded Trace Macrocell spcification (ARM IHI 0014Q)
...@@ -150,8 +179,8 @@ struct cs_etm_packet_queue { ...@@ -150,8 +179,8 @@ struct cs_etm_packet_queue {
u32 head; u32 head;
u32 tail; u32 tail;
u32 instr_count; u32 instr_count;
u64 timestamp; u64 cs_timestamp;
u64 next_timestamp; u64 next_cs_timestamp;
struct cs_etm_packet packet_buffer[CS_ETM_PACKET_MAX_BUFFER]; struct cs_etm_packet packet_buffer[CS_ETM_PACKET_MAX_BUFFER];
}; };
...@@ -162,17 +191,20 @@ struct cs_etm_packet_queue { ...@@ -162,17 +191,20 @@ struct cs_etm_packet_queue {
#define BMVAL(val, lsb, msb) ((val & GENMASK(msb, lsb)) >> lsb) #define BMVAL(val, lsb, msb) ((val & GENMASK(msb, lsb)) >> lsb)
#define CS_ETM_HEADER_SIZE (CS_HEADER_VERSION_0_MAX * sizeof(u64)) #define CS_ETM_HEADER_SIZE (CS_HEADER_VERSION_MAX * sizeof(u64))
#define __perf_cs_etmv3_magic 0x3030303030303030ULL #define __perf_cs_etmv3_magic 0x3030303030303030ULL
#define __perf_cs_etmv4_magic 0x4040404040404040ULL #define __perf_cs_etmv4_magic 0x4040404040404040ULL
#define __perf_cs_ete_magic 0x5050505050505050ULL
#define CS_ETMV3_PRIV_SIZE (CS_ETM_PRIV_MAX * sizeof(u64)) #define CS_ETMV3_PRIV_SIZE (CS_ETM_PRIV_MAX * sizeof(u64))
#define CS_ETMV4_PRIV_SIZE (CS_ETMV4_PRIV_MAX * sizeof(u64)) #define CS_ETMV4_PRIV_SIZE (CS_ETMV4_PRIV_MAX * sizeof(u64))
#define CS_ETE_PRIV_SIZE (CS_ETE_PRIV_MAX * sizeof(u64))
#ifdef HAVE_CSTRACE_SUPPORT #ifdef HAVE_CSTRACE_SUPPORT
int cs_etm__process_auxtrace_info(union perf_event *event, int cs_etm__process_auxtrace_info(union perf_event *event,
struct perf_session *session); struct perf_session *session);
int cs_etm__get_cpu(u8 trace_chan_id, int *cpu); int cs_etm__get_cpu(u8 trace_chan_id, int *cpu);
int cs_etm__get_pid_fmt(u8 trace_chan_id, u64 *pid_fmt);
int cs_etm__etmq_set_tid(struct cs_etm_queue *etmq, int cs_etm__etmq_set_tid(struct cs_etm_queue *etmq,
pid_t tid, u8 trace_chan_id); pid_t tid, u8 trace_chan_id);
bool cs_etm__etmq_is_timeless(struct cs_etm_queue *etmq); bool cs_etm__etmq_is_timeless(struct cs_etm_queue *etmq);
......
...@@ -21,6 +21,13 @@ extern int debug_data_convert; ...@@ -21,6 +21,13 @@ extern int debug_data_convert;
eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__) eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__)
#define pr_warning(fmt, ...) \ #define pr_warning(fmt, ...) \
eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__) eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__)
#define pr_warning_once(fmt, ...) ({ \
static int __warned; \
if (unlikely(!__warned)) { \
pr_warning(fmt, ##__VA_ARGS__); \
__warned = 1; \
} \
})
#define pr_info(fmt, ...) \ #define pr_info(fmt, ...) \
eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__) eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__)
#define pr_debug(fmt, ...) \ #define pr_debug(fmt, ...) \
...@@ -54,6 +61,13 @@ void trace_event(union perf_event *event); ...@@ -54,6 +61,13 @@ void trace_event(union perf_event *event);
int ui__error(const char *format, ...) __printf(1, 2); int ui__error(const char *format, ...) __printf(1, 2);
int ui__warning(const char *format, ...) __printf(1, 2); int ui__warning(const char *format, ...) __printf(1, 2);
#define ui__warning_once(format, ...) ({ \
static int __warned; \
if (unlikely(!__warned)) { \
ui__warning(format, ##__VA_ARGS__); \
__warned = 1; \
} \
})
void pr_stat(const char *fmt, ...); void pr_stat(const char *fmt, ...);
......
...@@ -170,6 +170,7 @@ struct dso { ...@@ -170,6 +170,7 @@ struct dso {
u8 has_srcline:1; u8 has_srcline:1;
u8 hit:1; u8 hit:1;
u8 annotate_warned:1; u8 annotate_warned:1;
u8 auxtrace_warned:1;
u8 short_name_allocated:1; u8 short_name_allocated:1;
u8 long_name_allocated:1; u8 long_name_allocated:1;
u8 is_64_bit:1; u8 is_64_bit:1;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册