[PATCH v2 4/4] perf arm-spe: Enable timestamp with arch timer counter

From: Leo Yan
Date: Fri Aug 07 2020 - 03:16:59 EST


Since the arch timer's counter is used for SPE tracing data, and now
it's ready to use arch timer for sample's timestamp in Perf tool, this
patch is to enable timestamp by convert the arch timer counter value to
the time.

After enabling timestamp for Arm SPE with this patch, we can see the
timestamp with 'time' field:

$ perf script -F,+time
dd 6799 [034] 25496.733475: 1 l1d-access: ffff87f37b88 _dl_start+0x288 (/usr/lib/aarch64-linux-gnu/ld-2.28.so)
dd 6799 [034] 25496.733475: 1 tlb-access: ffff87f37b88 _dl_start+0x288 (/usr/lib/aarch64-linux-gnu/ld-2.28.so)
dd 6799 [034] 25496.733479: 1 l1d-access: ffff87f37c74 _dl_start+0x374 (/usr/lib/aarch64-linux-gnu/ld-2.28.so)
dd 6799 [034] 25496.733479: 1 tlb-access: ffff87f37c74 _dl_start+0x374 (/usr/lib/aarch64-linux-gnu/ld-2.28.so)
dd 6799 [034] 25496.733485: 1 l1d-access: ffff87f49af4 __GI___tunables_init+0x3c (/usr/lib/aarch64-linux-gnu/ld-2.28.so)
dd 6799 [034] 25496.733485: 1 tlb-access: ffff87f49af4 __GI___tunables_init+0x3c (/usr/lib/aarch64-linux-gnu/ld-2.28.so)

Signed-off-by: Leo Yan <leo.yan@xxxxxxxxxx>
---
tools/perf/arch/arm64/util/arm-spe.c | 17 +++++++++++++++++
tools/perf/util/arm-spe.c | 16 ++++++++++++++--
tools/perf/util/arm-spe.h | 5 +++++
3 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c
index e3593063b3d1..a7cbd5fdb30e 100644
--- a/tools/perf/arch/arm64/util/arm-spe.c
+++ b/tools/perf/arch/arm64/util/arm-spe.c
@@ -11,6 +11,7 @@
#include <linux/zalloc.h>
#include <time.h>

+#include "../../../util/arm_arch_timer.h"
#include "../../../util/cpumap.h"
#include "../../../util/event.h"
#include "../../../util/evsel.h"
@@ -22,6 +23,7 @@
#include "../../../util/auxtrace.h"
#include "../../../util/record.h"
#include "../../../util/arm-spe.h"
+#include "../../../util/mmap.h"

#define KiB(x) ((x) * 1024)
#define MiB(x) ((x) * 1024 * 1024)
@@ -47,6 +49,9 @@ static int arm_spe_info_fill(struct auxtrace_record *itr,
struct arm_spe_recording *sper =
container_of(itr, struct arm_spe_recording, itr);
struct perf_pmu *arm_spe_pmu = sper->arm_spe_pmu;
+ struct perf_event_mmap_page *pc;
+ struct perf_arch_timer_conversion tc = { 0 };
+ int err;

if (priv_size != ARM_SPE_AUXTRACE_PRIV_SIZE)
return -EINVAL;
@@ -54,8 +59,20 @@ static int arm_spe_info_fill(struct auxtrace_record *itr,
if (!session->evlist->core.nr_mmaps)
return -EINVAL;

+ pc = session->evlist->mmap[0].core.base;
+ if (pc) {
+ err = perf_read_arch_timer_conversion(pc, &tc);
+ if (err)
+ return err;
+ }
+
auxtrace_info->type = PERF_AUXTRACE_ARM_SPE;
auxtrace_info->priv[ARM_SPE_PMU_TYPE] = arm_spe_pmu->type;
+ auxtrace_info->priv[ARM_SPE_TIME_SHIFT] = tc.time_shift;
+ auxtrace_info->priv[ARM_SPE_TIME_MULT] = tc.time_mult;
+ auxtrace_info->priv[ARM_SPE_TIME_ZERO] = tc.time_zero;
+ auxtrace_info->priv[ARM_SPE_TIME_CYCLES] = tc.time_cycles;
+ auxtrace_info->priv[ARM_SPE_TIME_MASK] = tc.time_mask;

return 0;
}
diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c
index 3882a5360ada..07232664c927 100644
--- a/tools/perf/util/arm-spe.c
+++ b/tools/perf/util/arm-spe.c
@@ -16,6 +16,7 @@
#include <stdlib.h>
#include <unistd.h>

+#include "arm_arch_timer.h"
#include "auxtrace.h"
#include "color.h"
#include "debug.h"
@@ -44,6 +45,7 @@ struct arm_spe {
struct perf_session *session;
struct machine *machine;
u32 pmu_type;
+ struct perf_arch_timer_conversion tc;

u8 timeless_decoding;
u8 data_queued;
@@ -229,7 +231,8 @@ static void arm_spe_prep_sample(struct arm_spe *spe,
struct arm_spe_record *record = &speq->decoder->record;

if (!spe->timeless_decoding)
- sample->time = speq->timestamp;
+ sample->time = arch_timer_cyc_to_perf_time(speq->timestamp,
+ &spe->tc);

sample->ip = record->from_ip;
sample->cpumode = arm_spe_cpumode(spe, sample->ip);
@@ -350,6 +353,7 @@ static int arm_spe_sample(struct arm_spe_queue *speq)
static int arm_spe_run_decoder(struct arm_spe_queue *speq, u64 *timestamp)
{
struct arm_spe *spe = speq->spe;
+ struct arm_spe_record *record;
int ret;

if (!spe->kernel_start)
@@ -369,6 +373,9 @@ static int arm_spe_run_decoder(struct arm_spe_queue *speq, u64 *timestamp)
if (ret < 0)
continue;

+ record = &speq->decoder->record;
+ speq->timestamp = record->timestamp;
+
ret = arm_spe_sample(speq);
if (ret)
return ret;
@@ -585,7 +592,7 @@ static int arm_spe_process_event(struct perf_session *session,
}

if (sample->time && (sample->time != (u64) -1))
- timestamp = sample->time;
+ timestamp = perf_time_to_arch_timer_cyc(sample->time, &spe->tc);
else
timestamp = 0;

@@ -934,6 +941,11 @@ int arm_spe_process_auxtrace_info(union perf_event *event,
spe->machine = &session->machines.host; /* No kvm support */
spe->auxtrace_type = auxtrace_info->type;
spe->pmu_type = auxtrace_info->priv[ARM_SPE_PMU_TYPE];
+ spe->tc.time_shift = auxtrace_info->priv[ARM_SPE_TIME_SHIFT];
+ spe->tc.time_mult = auxtrace_info->priv[ARM_SPE_TIME_MULT];
+ spe->tc.time_zero = auxtrace_info->priv[ARM_SPE_TIME_ZERO];
+ spe->tc.time_cycles = auxtrace_info->priv[ARM_SPE_TIME_CYCLES];
+ spe->tc.time_mask = auxtrace_info->priv[ARM_SPE_TIME_MASK];

spe->timeless_decoding = arm_spe__is_timeless_decoding(spe);
spe->auxtrace.process_event = arm_spe_process_event;
diff --git a/tools/perf/util/arm-spe.h b/tools/perf/util/arm-spe.h
index 98d3235781c3..8baa32ad179d 100644
--- a/tools/perf/util/arm-spe.h
+++ b/tools/perf/util/arm-spe.h
@@ -12,6 +12,11 @@
enum {
ARM_SPE_PMU_TYPE,
ARM_SPE_PER_CPU_MMAPS,
+ ARM_SPE_TIME_SHIFT,
+ ARM_SPE_TIME_MULT,
+ ARM_SPE_TIME_ZERO,
+ ARM_SPE_TIME_CYCLES,
+ ARM_SPE_TIME_MASK,
ARM_SPE_AUXTRACE_PRIV_MAX,
};

--
2.17.1