forked from Minki/linux
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:
parent
aa6292f484
commit
440a23b34c
@ -88,6 +88,11 @@ libperf-$(CONFIG_AUXTRACE) += intel-pt.o
|
||||
libperf-$(CONFIG_AUXTRACE) += intel-bts.o
|
||||
libperf-$(CONFIG_AUXTRACE) += arm-spe.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 += dump-insn.o
|
||||
libperf-y += parse-regs-options.o
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include "debug.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
|
||||
#include "cs-etm.h"
|
||||
#include "intel-pt.h"
|
||||
#include "intel-bts.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:
|
||||
return arm_spe_process_auxtrace_info(event, session);
|
||||
case PERF_AUXTRACE_CS_ETM:
|
||||
return cs_etm__process_auxtrace_info(event, session);
|
||||
case PERF_AUXTRACE_UNKNOWN:
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
213
tools/perf/util/cs-etm.c
Normal file
213
tools/perf/util/cs-etm.c
Normal 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;
|
||||
}
|
@ -18,6 +18,9 @@
|
||||
#ifndef 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
|
||||
* 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_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
|
||||
|
Loading…
Reference in New Issue
Block a user