perf tools: Add initial entry point for decoder CoreSight traces

This patch adds the entry point for CoreSight trace decoding, serving as
a jumping board for furhter expansions.

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-3-git-send-email-mathieu.poirier@linaro.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Mathieu Poirier 2018-01-17 10:52:11 -07:00 committed by Arnaldo Carvalho de Melo
parent aa6292f484
commit 440a23b34c
4 changed files with 235 additions and 0 deletions

View File

@ -88,6 +88,11 @@ libperf-$(CONFIG_AUXTRACE) += intel-pt.o
libperf-$(CONFIG_AUXTRACE) += intel-bts.o libperf-$(CONFIG_AUXTRACE) += intel-bts.o
libperf-$(CONFIG_AUXTRACE) += arm-spe.o libperf-$(CONFIG_AUXTRACE) += arm-spe.o
libperf-$(CONFIG_AUXTRACE) += arm-spe-pkt-decoder.o libperf-$(CONFIG_AUXTRACE) += arm-spe-pkt-decoder.o
ifdef CONFIG_LIBOPENCSD
libperf-$(CONFIG_AUXTRACE) += cs-etm.o
endif
libperf-y += parse-branch-options.o libperf-y += parse-branch-options.o
libperf-y += dump-insn.o libperf-y += dump-insn.o
libperf-y += parse-regs-options.o libperf-y += parse-regs-options.o

View File

@ -52,6 +52,7 @@
#include "debug.h" #include "debug.h"
#include <subcmd/parse-options.h> #include <subcmd/parse-options.h>
#include "cs-etm.h"
#include "intel-pt.h" #include "intel-pt.h"
#include "intel-bts.h" #include "intel-bts.h"
#include "arm-spe.h" #include "arm-spe.h"
@ -914,6 +915,7 @@ int perf_event__process_auxtrace_info(struct perf_tool *tool __maybe_unused,
case PERF_AUXTRACE_ARM_SPE: case PERF_AUXTRACE_ARM_SPE:
return arm_spe_process_auxtrace_info(event, session); return arm_spe_process_auxtrace_info(event, session);
case PERF_AUXTRACE_CS_ETM: case PERF_AUXTRACE_CS_ETM:
return cs_etm__process_auxtrace_info(event, session);
case PERF_AUXTRACE_UNKNOWN: case PERF_AUXTRACE_UNKNOWN:
default: default:
return -EINVAL; return -EINVAL;

213
tools/perf/util/cs-etm.c Normal file
View File

@ -0,0 +1,213 @@
/*
* SPDX-License-Identifier: GPL-2.0
*
* Copyright(C) 2015-2018 Linaro Limited.
*
* Author: Tor Jeremiassen <tor@ti.com>
* Author: Mathieu Poirier <mathieu.poirier@linaro.org>
*/
#include <linux/bitops.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/log2.h>
#include <linux/types.h>
#include <stdlib.h>
#include "auxtrace.h"
#include "color.h"
#include "cs-etm.h"
#include "debug.h"
#include "evlist.h"
#include "intlist.h"
#include "machine.h"
#include "map.h"
#include "perf.h"
#include "thread.h"
#include "thread_map.h"
#include "thread-stack.h"
#include "util.h"
#define MAX_TIMESTAMP (~0ULL)
struct cs_etm_auxtrace {
struct auxtrace auxtrace;
struct auxtrace_queues queues;
struct auxtrace_heap heap;
struct itrace_synth_opts synth_opts;
struct perf_session *session;
struct machine *machine;
struct thread *unknown_thread;
u8 timeless_decoding;
u8 snapshot_mode;
u8 data_queued;
u8 sample_branches;
int num_cpu;
u32 auxtrace_type;
u64 branches_sample_type;
u64 branches_id;
u64 **metadata;
u64 kernel_start;
unsigned int pmu_type;
};
struct cs_etm_queue {
struct cs_etm_auxtrace *etm;
struct thread *thread;
struct cs_etm_decoder *decoder;
struct auxtrace_buffer *buffer;
const struct cs_etm_state *state;
union perf_event *event_buf;
unsigned int queue_nr;
pid_t pid, tid;
int cpu;
u64 time;
u64 timestamp;
u64 offset;
};
static int cs_etm__flush_events(struct perf_session *session,
struct perf_tool *tool)
{
(void) session;
(void) tool;
return 0;
}
static void cs_etm__free_queue(void *priv)
{
struct cs_etm_queue *etmq = priv;
free(etmq);
}
static void cs_etm__free_events(struct perf_session *session)
{
unsigned int i;
struct cs_etm_auxtrace *aux = container_of(session->auxtrace,
struct cs_etm_auxtrace,
auxtrace);
struct auxtrace_queues *queues = &aux->queues;
for (i = 0; i < queues->nr_queues; i++) {
cs_etm__free_queue(queues->queue_array[i].priv);
queues->queue_array[i].priv = NULL;
}
auxtrace_queues__free(queues);
}
static void cs_etm__free(struct perf_session *session)
{
struct cs_etm_auxtrace *aux = container_of(session->auxtrace,
struct cs_etm_auxtrace,
auxtrace);
cs_etm__free_events(session);
session->auxtrace = NULL;
zfree(&aux);
}
static int cs_etm__process_event(struct perf_session *session,
union perf_event *event,
struct perf_sample *sample,
struct perf_tool *tool)
{
(void) session;
(void) event;
(void) sample;
(void) tool;
return 0;
}
static int cs_etm__process_auxtrace_event(struct perf_session *session,
union perf_event *event,
struct perf_tool *tool)
{
(void) session;
(void) event;
(void) tool;
return 0;
}
static bool cs_etm__is_timeless_decoding(struct cs_etm_auxtrace *etm)
{
struct perf_evsel *evsel;
struct perf_evlist *evlist = etm->session->evlist;
bool timeless_decoding = true;
/*
* Circle through the list of event and complain if we find one
* with the time bit set.
*/
evlist__for_each_entry(evlist, evsel) {
if ((evsel->attr.sample_type & PERF_SAMPLE_TIME))
timeless_decoding = false;
}
return timeless_decoding;
}
int cs_etm__process_auxtrace_info(union perf_event *event,
struct perf_session *session)
{
struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info;
struct cs_etm_auxtrace *etm = NULL;
int event_header_size = sizeof(struct perf_event_header);
int info_header_size;
int total_size = auxtrace_info->header.size;
int err = 0;
/*
* sizeof(auxtrace_info_event::type) +
* sizeof(auxtrace_info_event::reserved) == 8
*/
info_header_size = 8;
if (total_size < (event_header_size + info_header_size))
return -EINVAL;
etm = zalloc(sizeof(*etm));
if (!etm)
err = -ENOMEM;
err = auxtrace_queues__init(&etm->queues);
if (err)
goto err_free_etm;
etm->session = session;
etm->machine = &session->machines.host;
etm->auxtrace_type = auxtrace_info->type;
etm->timeless_decoding = cs_etm__is_timeless_decoding(etm);
etm->auxtrace.process_event = cs_etm__process_event;
etm->auxtrace.process_auxtrace_event = cs_etm__process_auxtrace_event;
etm->auxtrace.flush_events = cs_etm__flush_events;
etm->auxtrace.free_events = cs_etm__free_events;
etm->auxtrace.free = cs_etm__free;
session->auxtrace = &etm->auxtrace;
if (dump_trace)
return 0;
err = auxtrace_queues__process_index(&etm->queues, session);
if (err)
goto err_free_queues;
etm->data_queued = etm->queues.populated;
return 0;
err_free_queues:
auxtrace_queues__free(&etm->queues);
session->auxtrace = NULL;
err_free_etm:
zfree(&etm);
return -EINVAL;
}

View File

@ -18,6 +18,9 @@
#ifndef INCLUDE__UTIL_PERF_CS_ETM_H__ #ifndef INCLUDE__UTIL_PERF_CS_ETM_H__
#define INCLUDE__UTIL_PERF_CS_ETM_H__ #define INCLUDE__UTIL_PERF_CS_ETM_H__
#include "util/event.h"
#include "util/session.h"
/* Versionning header in case things need tro change in the future. That way /* Versionning header in case things need tro change in the future. That way
* decoding of old snapshot is still possible. * decoding of old snapshot is still possible.
*/ */
@ -71,4 +74,16 @@ static const u64 __perf_cs_etmv4_magic = 0x4040404040404040ULL;
#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))
#ifdef HAVE_CSTRACE_SUPPORT
int cs_etm__process_auxtrace_info(union perf_event *event,
struct perf_session *session);
#else
static inline int
cs_etm__process_auxtrace_info(union perf_event *event __maybe_unused,
struct perf_session *session __maybe_unused)
{
return -1;
}
#endif
#endif #endif