linux-stable/tools/perf/util/cs-etm.c

214 lines
4.5 KiB
C
Raw Normal View History

/*
* 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;
}