summaryrefslogtreecommitdiff
path: root/tools/perf/util/data-convert-bt.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/data-convert-bt.c')
-rw-r--r--tools/perf/util/data-convert-bt.c378
1 files changed, 264 insertions, 114 deletions
diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c
index 3149b70799fd..3d2e437e1354 100644
--- a/tools/perf/util/data-convert-bt.c
+++ b/tools/perf/util/data-convert-bt.c
@@ -1,16 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* CTF writing support via babeltrace.
*
* Copyright (C) 2014, Jiri Olsa <jolsa@redhat.com>
* Copyright (C) 2014, Sebastian Andrzej Siewior <bigeasy@linutronix.de>
- *
- * Released under the GPL v2. (and only v2, not any later version)
*/
#include <errno.h>
#include <inttypes.h>
#include <linux/compiler.h>
#include <linux/kernel.h>
+#include <linux/zalloc.h>
#include <babeltrace/ctf-writer/writer.h>
#include <babeltrace/ctf-writer/clock.h>
#include <babeltrace/ctf-writer/stream.h>
@@ -19,18 +19,25 @@
#include <babeltrace/ctf-writer/event-fields.h>
#include <babeltrace/ctf-ir/utils.h>
#include <babeltrace/ctf/events.h>
-#include <traceevent/event-parse.h>
#include "asm/bug.h"
-#include "data-convert-bt.h"
+#include "data-convert.h"
#include "session.h"
-#include "util.h"
#include "debug.h"
#include "tool.h"
#include "evlist.h"
#include "evsel.h"
#include "machine.h"
#include "config.h"
-#include "sane_ctype.h"
+#include <linux/ctype.h>
+#include <linux/err.h>
+#include <linux/time64.h>
+#include "util.h"
+#include "clockid.h"
+#include "util/sample.h"
+
+#ifdef HAVE_LIBTRACEEVENT
+#include <event-parse.h>
+#endif
#define pr_N(n, fmt, ...) \
eprintf(n, debug_data_convert, fmt, ##__VA_ARGS__)
@@ -76,6 +83,8 @@ struct ctf_writer {
struct bt_ctf_event_class *comm_class;
struct bt_ctf_event_class *exit_class;
struct bt_ctf_event_class *fork_class;
+ struct bt_ctf_event_class *mmap_class;
+ struct bt_ctf_event_class *mmap2_class;
};
struct convert {
@@ -180,20 +189,20 @@ err_put_field:
}
static struct bt_ctf_field_type*
-get_tracepoint_field_type(struct ctf_writer *cw, struct format_field *field)
+get_tracepoint_field_type(struct ctf_writer *cw, struct tep_format_field *field)
{
unsigned long flags = field->flags;
- if (flags & FIELD_IS_STRING)
+ if (flags & TEP_FIELD_IS_STRING)
return cw->data.string;
- if (!(flags & FIELD_IS_SIGNED)) {
+ if (!(flags & TEP_FIELD_IS_SIGNED)) {
/* unsigned long are mostly pointers */
- if (flags & FIELD_IS_LONG || flags & FIELD_IS_POINTER)
+ if (flags & TEP_FIELD_IS_LONG || flags & TEP_FIELD_IS_POINTER)
return cw->data.u64_hex;
}
- if (flags & FIELD_IS_SIGNED) {
+ if (flags & TEP_FIELD_IS_SIGNED) {
if (field->size == 8)
return cw->data.s64;
else
@@ -269,7 +278,7 @@ static int string_set_value(struct bt_ctf_field *field, const char *string)
if (i > 0)
strncpy(buffer, string, i);
}
- strncat(buffer + p, numstr, 4);
+ memcpy(buffer + p, numstr, 4);
p += 3;
}
}
@@ -285,7 +294,7 @@ static int add_tracepoint_field_value(struct ctf_writer *cw,
struct bt_ctf_event_class *event_class,
struct bt_ctf_event *event,
struct perf_sample *sample,
- struct format_field *fmtf)
+ struct tep_format_field *fmtf)
{
struct bt_ctf_field_type *type;
struct bt_ctf_field *array_field;
@@ -302,20 +311,22 @@ static int add_tracepoint_field_value(struct ctf_writer *cw,
name = fmtf->alias;
offset = fmtf->offset;
len = fmtf->size;
- if (flags & FIELD_IS_STRING)
- flags &= ~FIELD_IS_ARRAY;
+ if (flags & TEP_FIELD_IS_STRING)
+ flags &= ~TEP_FIELD_IS_ARRAY;
- if (flags & FIELD_IS_DYNAMIC) {
+ if (flags & TEP_FIELD_IS_DYNAMIC) {
unsigned long long tmp_val;
- tmp_val = pevent_read_number(fmtf->event->pevent,
- data + offset, len);
+ tmp_val = tep_read_number(fmtf->event->tep,
+ data + offset, len);
offset = tmp_val;
len = offset >> 16;
offset &= 0xffff;
+ if (tep_field_is_relative(flags))
+ offset += fmtf->offset + fmtf->size;
}
- if (flags & FIELD_IS_ARRAY) {
+ if (flags & TEP_FIELD_IS_ARRAY) {
type = bt_ctf_event_class_get_field_by_name(
event_class, name);
@@ -336,7 +347,7 @@ static int add_tracepoint_field_value(struct ctf_writer *cw,
type = get_tracepoint_field_type(cw, fmtf);
for (i = 0; i < n_items; i++) {
- if (flags & FIELD_IS_ARRAY)
+ if (flags & TEP_FIELD_IS_ARRAY)
field = bt_ctf_field_array_get_field(array_field, i);
else
field = bt_ctf_field_create(type);
@@ -346,16 +357,16 @@ static int add_tracepoint_field_value(struct ctf_writer *cw,
return -1;
}
- if (flags & FIELD_IS_STRING)
+ if (flags & TEP_FIELD_IS_STRING)
ret = string_set_value(field, data + offset + i * len);
else {
unsigned long long value_int;
- value_int = pevent_read_number(
- fmtf->event->pevent,
+ value_int = tep_read_number(
+ fmtf->event->tep,
data + offset + i * len, len);
- if (!(flags & FIELD_IS_SIGNED))
+ if (!(flags & TEP_FIELD_IS_SIGNED))
ret = bt_ctf_field_unsigned_integer_set_value(
field, value_int);
else
@@ -367,7 +378,7 @@ static int add_tracepoint_field_value(struct ctf_writer *cw,
pr_err("failed to set file value %s\n", name);
goto err_put_field;
}
- if (!(flags & FIELD_IS_ARRAY)) {
+ if (!(flags & TEP_FIELD_IS_ARRAY)) {
ret = bt_ctf_event_set_payload(event, name, field);
if (ret) {
pr_err("failed to set payload %s\n", name);
@@ -376,7 +387,7 @@ static int add_tracepoint_field_value(struct ctf_writer *cw,
}
bt_ctf_field_put(field);
}
- if (flags & FIELD_IS_ARRAY) {
+ if (flags & TEP_FIELD_IS_ARRAY) {
ret = bt_ctf_event_set_payload(event, name, array_field);
if (ret) {
pr_err("Failed add payload array %s\n", name);
@@ -394,10 +405,10 @@ err_put_field:
static int add_tracepoint_fields_values(struct ctf_writer *cw,
struct bt_ctf_event_class *event_class,
struct bt_ctf_event *event,
- struct format_field *fields,
+ struct tep_format_field *fields,
struct perf_sample *sample)
{
- struct format_field *field;
+ struct tep_format_field *field;
int ret;
for (field = fields; field; field = field->next) {
@@ -412,11 +423,12 @@ static int add_tracepoint_fields_values(struct ctf_writer *cw,
static int add_tracepoint_values(struct ctf_writer *cw,
struct bt_ctf_event_class *event_class,
struct bt_ctf_event *event,
- struct perf_evsel *evsel,
+ struct evsel *evsel,
struct perf_sample *sample)
{
- struct format_field *common_fields = evsel->tp_format->format.common_fields;
- struct format_field *fields = evsel->tp_format->format.fields;
+ const struct tep_event *tp_format = evsel__tp_format(evsel);
+ struct tep_format_field *common_fields = tp_format->format.common_fields;
+ struct tep_format_field *fields = tp_format->format.fields;
int ret;
ret = add_tracepoint_fields_values(cw, event_class, event,
@@ -506,12 +518,87 @@ put_len_type:
return ret;
}
+static int
+add_callchain_output_values(struct bt_ctf_event_class *event_class,
+ struct bt_ctf_event *event,
+ struct ip_callchain *callchain)
+{
+ struct bt_ctf_field_type *len_type, *seq_type;
+ struct bt_ctf_field *len_field, *seq_field;
+ unsigned int nr_elements = callchain->nr;
+ unsigned int i;
+ int ret;
+
+ len_type = bt_ctf_event_class_get_field_by_name(
+ event_class, "perf_callchain_size");
+ len_field = bt_ctf_field_create(len_type);
+ if (!len_field) {
+ pr_err("failed to create 'perf_callchain_size' for callchain output event\n");
+ ret = -1;
+ goto put_len_type;
+ }
+
+ ret = bt_ctf_field_unsigned_integer_set_value(len_field, nr_elements);
+ if (ret) {
+ pr_err("failed to set field value for perf_callchain_size\n");
+ goto put_len_field;
+ }
+ ret = bt_ctf_event_set_payload(event, "perf_callchain_size", len_field);
+ if (ret) {
+ pr_err("failed to set payload to perf_callchain_size\n");
+ goto put_len_field;
+ }
+
+ seq_type = bt_ctf_event_class_get_field_by_name(
+ event_class, "perf_callchain");
+ seq_field = bt_ctf_field_create(seq_type);
+ if (!seq_field) {
+ pr_err("failed to create 'perf_callchain' for callchain output event\n");
+ ret = -1;
+ goto put_seq_type;
+ }
+
+ ret = bt_ctf_field_sequence_set_length(seq_field, len_field);
+ if (ret) {
+ pr_err("failed to set length of 'perf_callchain'\n");
+ goto put_seq_field;
+ }
+
+ for (i = 0; i < nr_elements; i++) {
+ struct bt_ctf_field *elem_field =
+ bt_ctf_field_sequence_get_field(seq_field, i);
+
+ ret = bt_ctf_field_unsigned_integer_set_value(elem_field,
+ ((u64 *)(callchain->ips))[i]);
+
+ bt_ctf_field_put(elem_field);
+ if (ret) {
+ pr_err("failed to set callchain[%d]\n", i);
+ goto put_seq_field;
+ }
+ }
+
+ ret = bt_ctf_event_set_payload(event, "perf_callchain", seq_field);
+ if (ret)
+ pr_err("failed to set payload for raw_data\n");
+
+put_seq_field:
+ bt_ctf_field_put(seq_field);
+put_seq_type:
+ bt_ctf_field_type_put(seq_type);
+put_len_field:
+ bt_ctf_field_put(len_field);
+put_len_type:
+ bt_ctf_field_type_put(len_type);
+ return ret;
+}
+
static int add_generic_values(struct ctf_writer *cw,
struct bt_ctf_event *event,
- struct perf_evsel *evsel,
+ struct evsel *evsel,
struct perf_sample *sample)
{
- u64 type = evsel->attr.sample_type;
+ u64 type = evsel->core.attr.sample_type;
int ret;
/*
@@ -519,7 +606,6 @@ static int add_generic_values(struct ctf_writer *cw,
* PERF_SAMPLE_TIME - not needed as we have it in
* ctf event header
* PERF_SAMPLE_READ - TODO
- * PERF_SAMPLE_CALLCHAIN - TODO
* PERF_SAMPLE_RAW - tracepoint fields are handled separately
* PERF_SAMPLE_BRANCH_STACK - TODO
* PERF_SAMPLE_REGS_USER - TODO
@@ -678,11 +764,11 @@ static struct ctf_stream *ctf_stream(struct ctf_writer *cw, int cpu)
}
static int get_sample_cpu(struct ctf_writer *cw, struct perf_sample *sample,
- struct perf_evsel *evsel)
+ struct evsel *evsel)
{
int cpu = 0;
- if (evsel->attr.sample_type & PERF_SAMPLE_CPU)
+ if (evsel->core.attr.sample_type & PERF_SAMPLE_CPU)
cpu = sample->cpu;
if (cpu > cw->stream_cnt) {
@@ -707,10 +793,10 @@ static bool is_flush_needed(struct ctf_stream *cs)
return cs->count >= STREAM_FLUSH_COUNT;
}
-static int process_sample_event(struct perf_tool *tool,
+static int process_sample_event(const struct perf_tool *tool,
union perf_event *_event,
struct perf_sample *sample,
- struct perf_evsel *evsel,
+ struct evsel *evsel,
struct machine *machine __maybe_unused)
{
struct convert *c = container_of(tool, struct convert, tool);
@@ -720,6 +806,7 @@ static int process_sample_event(struct perf_tool *tool,
struct bt_ctf_event_class *event_class;
struct bt_ctf_event *event;
int ret;
+ unsigned long type = evsel->core.attr.sample_type;
if (WARN_ONCE(!priv, "Failed to setup all events.\n"))
return 0;
@@ -744,14 +831,21 @@ static int process_sample_event(struct perf_tool *tool,
if (ret)
return -1;
- if (evsel->attr.type == PERF_TYPE_TRACEPOINT) {
+ if (evsel->core.attr.type == PERF_TYPE_TRACEPOINT) {
ret = add_tracepoint_values(cw, event_class, event,
evsel, sample);
if (ret)
return -1;
}
- if (perf_evsel__is_bpf_output(evsel)) {
+ if (type & PERF_SAMPLE_CALLCHAIN) {
+ ret = add_callchain_output_values(event_class,
+ event, sample->callchain);
+ if (ret)
+ return -1;
+ }
+
+ if (evsel__is_bpf_output(evsel)) {
ret = add_bpf_output_values(event_class, event, sample);
if (ret)
return -1;
@@ -778,7 +872,7 @@ do { \
} while(0)
#define __FUNC_PROCESS_NON_SAMPLE(_name, body) \
-static int process_##_name##_event(struct perf_tool *tool, \
+static int process_##_name##_event(const struct perf_tool *tool, \
union perf_event *_event, \
struct perf_sample *sample, \
struct machine *machine) \
@@ -833,6 +927,18 @@ __FUNC_PROCESS_NON_SAMPLE(exit,
__NON_SAMPLE_SET_FIELD(fork, u32, ptid);
__NON_SAMPLE_SET_FIELD(fork, u64, time);
)
+__FUNC_PROCESS_NON_SAMPLE(mmap,
+ __NON_SAMPLE_SET_FIELD(mmap, u32, pid);
+ __NON_SAMPLE_SET_FIELD(mmap, u32, tid);
+ __NON_SAMPLE_SET_FIELD(mmap, u64_hex, start);
+ __NON_SAMPLE_SET_FIELD(mmap, string, filename);
+)
+__FUNC_PROCESS_NON_SAMPLE(mmap2,
+ __NON_SAMPLE_SET_FIELD(mmap2, u32, pid);
+ __NON_SAMPLE_SET_FIELD(mmap2, u32, tid);
+ __NON_SAMPLE_SET_FIELD(mmap2, u64_hex, start);
+ __NON_SAMPLE_SET_FIELD(mmap2, string, filename);
+)
#undef __NON_SAMPLE_SET_FIELD
#undef __FUNC_PROCESS_NON_SAMPLE
@@ -849,8 +955,8 @@ static char *change_name(char *name, char *orig_name, int dup)
goto out;
/*
* Add '_' prefix to potential keywork. According to
- * Mathieu Desnoyers (https://lkml.org/lkml/2015/1/23/652),
- * futher CTF spec updating may require us to use '$'.
+ * Mathieu Desnoyers (https://lore.kernel.org/lkml/1074266107.40857.1422045946295.JavaMail.zimbra@efficios.com),
+ * further CTF spec updating may require us to use '$'.
*/
if (dup < 0)
len = strlen(name) + sizeof("_");
@@ -874,7 +980,7 @@ out:
static int event_class_add_field(struct bt_ctf_event_class *event_class,
struct bt_ctf_field_type *type,
- struct format_field *field)
+ struct tep_format_field *field)
{
struct bt_ctf_field_type *t = NULL;
char *name;
@@ -913,10 +1019,10 @@ static int event_class_add_field(struct bt_ctf_event_class *event_class,
}
static int add_tracepoint_fields_types(struct ctf_writer *cw,
- struct format_field *fields,
+ struct tep_format_field *fields,
struct bt_ctf_event_class *event_class)
{
- struct format_field *field;
+ struct tep_format_field *field;
int ret;
for (field = fields; field; field = field->next) {
@@ -934,15 +1040,15 @@ static int add_tracepoint_fields_types(struct ctf_writer *cw,
* type and don't care that it is an array. What we don't
* support is an array of strings.
*/
- if (flags & FIELD_IS_STRING)
- flags &= ~FIELD_IS_ARRAY;
+ if (flags & TEP_FIELD_IS_STRING)
+ flags &= ~TEP_FIELD_IS_ARRAY;
- if (flags & FIELD_IS_ARRAY)
+ if (flags & TEP_FIELD_IS_ARRAY)
type = bt_ctf_field_type_array_create(type, field->arraylen);
ret = event_class_add_field(event_class, type, field);
- if (flags & FIELD_IS_ARRAY)
+ if (flags & TEP_FIELD_IS_ARRAY)
bt_ctf_field_type_put(type);
if (ret) {
@@ -956,11 +1062,12 @@ static int add_tracepoint_fields_types(struct ctf_writer *cw,
}
static int add_tracepoint_types(struct ctf_writer *cw,
- struct perf_evsel *evsel,
+ struct evsel *evsel,
struct bt_ctf_event_class *class)
{
- struct format_field *common_fields = evsel->tp_format->format.common_fields;
- struct format_field *fields = evsel->tp_format->format.fields;
+ const struct tep_event *tp_format = evsel__tp_format(evsel);
+ struct tep_format_field *common_fields = tp_format ? tp_format->format.common_fields : NULL;
+ struct tep_format_field *fields = tp_format ? tp_format->format.fields : NULL;
int ret;
ret = add_tracepoint_fields_types(cw, common_fields, class);
@@ -989,10 +1096,10 @@ static int add_bpf_output_types(struct ctf_writer *cw,
return bt_ctf_event_class_add_field(class, seq_type, "raw_data");
}
-static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel,
+static int add_generic_types(struct ctf_writer *cw, struct evsel *evsel,
struct bt_ctf_event_class *event_class)
{
- u64 type = evsel->attr.sample_type;
+ u64 type = evsel->core.attr.sample_type;
/*
* missing:
@@ -1043,18 +1150,26 @@ static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel,
if (type & PERF_SAMPLE_TRANSACTION)
ADD_FIELD(event_class, cw->data.u64, "perf_transaction");
+ if (type & PERF_SAMPLE_CALLCHAIN) {
+ ADD_FIELD(event_class, cw->data.u32, "perf_callchain_size");
+ ADD_FIELD(event_class,
+ bt_ctf_field_type_sequence_create(
+ cw->data.u64_hex, "perf_callchain_size"),
+ "perf_callchain");
+ }
+
#undef ADD_FIELD
return 0;
}
-static int add_event(struct ctf_writer *cw, struct perf_evsel *evsel)
+static int add_event(struct ctf_writer *cw, struct evsel *evsel)
{
struct bt_ctf_event_class *event_class;
struct evsel_priv *priv;
- const char *name = perf_evsel__name(evsel);
+ const char *name = evsel__name(evsel);
int ret;
- pr("Adding event '%s' (type %d)\n", name, evsel->attr.type);
+ pr("Adding event '%s' (type %d)\n", name, evsel->core.attr.type);
event_class = bt_ctf_event_class_create(name);
if (!event_class)
@@ -1064,13 +1179,13 @@ static int add_event(struct ctf_writer *cw, struct perf_evsel *evsel)
if (ret)
goto err;
- if (evsel->attr.type == PERF_TYPE_TRACEPOINT) {
+ if (evsel->core.attr.type == PERF_TYPE_TRACEPOINT) {
ret = add_tracepoint_types(cw, evsel, event_class);
if (ret)
goto err;
}
- if (perf_evsel__is_bpf_output(evsel)) {
+ if (evsel__is_bpf_output(evsel)) {
ret = add_bpf_output_types(cw, event_class);
if (ret)
goto err;
@@ -1098,8 +1213,8 @@ err:
static int setup_events(struct ctf_writer *cw, struct perf_session *session)
{
- struct perf_evlist *evlist = session->evlist;
- struct perf_evsel *evsel;
+ struct evlist *evlist = session->evlist;
+ struct evsel *evsel;
int ret;
evlist__for_each_entry(evlist, evsel) {
@@ -1164,6 +1279,19 @@ __FUNC_ADD_NON_SAMPLE_EVENT_CLASS(exit,
__NON_SAMPLE_ADD_FIELD(u64, time);
)
+__FUNC_ADD_NON_SAMPLE_EVENT_CLASS(mmap,
+ __NON_SAMPLE_ADD_FIELD(u32, pid);
+ __NON_SAMPLE_ADD_FIELD(u32, tid);
+ __NON_SAMPLE_ADD_FIELD(u64_hex, start);
+ __NON_SAMPLE_ADD_FIELD(string, filename);
+)
+
+__FUNC_ADD_NON_SAMPLE_EVENT_CLASS(mmap2,
+ __NON_SAMPLE_ADD_FIELD(u32, pid);
+ __NON_SAMPLE_ADD_FIELD(u32, tid);
+ __NON_SAMPLE_ADD_FIELD(u64_hex, start);
+ __NON_SAMPLE_ADD_FIELD(string, filename);
+)
#undef __NON_SAMPLE_ADD_FIELD
#undef __FUNC_ADD_NON_SAMPLE_EVENT_CLASS
@@ -1181,13 +1309,19 @@ static int setup_non_sample_events(struct ctf_writer *cw,
ret = add_fork_event(cw);
if (ret)
return ret;
+ ret = add_mmap_event(cw);
+ if (ret)
+ return ret;
+ ret = add_mmap2_event(cw);
+ if (ret)
+ return ret;
return 0;
}
static void cleanup_events(struct perf_session *session)
{
- struct perf_evlist *evlist = session->evlist;
- struct perf_evsel *evsel;
+ struct evlist *evlist = session->evlist;
+ struct evsel *evsel;
evlist__for_each_entry(evlist, evsel) {
struct evsel_priv *priv;
@@ -1197,21 +1331,21 @@ static void cleanup_events(struct perf_session *session)
zfree(&evsel->priv);
}
- perf_evlist__delete(evlist);
+ evlist__delete(evlist);
session->evlist = NULL;
}
static int setup_streams(struct ctf_writer *cw, struct perf_session *session)
{
struct ctf_stream **stream;
- struct perf_header *ph = &session->header;
+ struct perf_env *env = perf_session__env(session);
int ncpus;
/*
* Try to get the number of cpus used in the data file,
* if not present fallback to the MAX_CPUS.
*/
- ncpus = ph->env.nr_cpus_avail ?: MAX_CPUS;
+ ncpus = env->nr_cpus_avail ?: MAX_CPUS;
stream = zalloc(sizeof(*stream) * ncpus);
if (!stream) {
@@ -1231,13 +1365,13 @@ static void free_streams(struct ctf_writer *cw)
for (cpu = 0; cpu < cw->stream_cnt; cpu++)
ctf_stream__delete(cw->stream[cpu]);
- free(cw->stream);
+ zfree(&cw->stream);
}
static int ctf_writer__setup_env(struct ctf_writer *cw,
struct perf_session *session)
{
- struct perf_header *header = &session->header;
+ struct perf_env *env = perf_session__env(session);
struct bt_ctf_writer *writer = cw->writer;
#define ADD(__n, __v) \
@@ -1246,11 +1380,11 @@ do { \
return -1; \
} while (0)
- ADD("host", header->env.hostname);
+ ADD("host", env->hostname);
ADD("sysname", "Linux");
- ADD("release", header->env.os_release);
- ADD("version", header->env.version);
- ADD("machine", header->env.arch);
+ ADD("release", env->os_release);
+ ADD("version", env->version);
+ ADD("machine", env->arch);
ADD("domain", "kernel");
ADD("tracer_name", "perf");
@@ -1258,11 +1392,26 @@ do { \
return 0;
}
-static int ctf_writer__setup_clock(struct ctf_writer *cw)
+static int ctf_writer__setup_clock(struct ctf_writer *cw,
+ struct perf_session *session,
+ bool tod)
{
struct bt_ctf_clock *clock = cw->clock;
+ const char *desc = "perf clock";
+ int64_t offset = 0;
+
+ if (tod) {
+ struct perf_env *env = perf_session__env(session);
- bt_ctf_clock_set_description(clock, "perf clock");
+ if (!env->clock.enabled) {
+ pr_err("Can't provide --tod time, missing clock data. "
+ "Please record with -k/--clockid option.\n");
+ return -1;
+ }
+
+ desc = clockid_name(env->clock.clockid);
+ offset = env->clock.tod_ns - env->clock.clockid_ns;
+ }
#define SET(__n, __v) \
do { \
@@ -1271,8 +1420,8 @@ do { \
} while (0)
SET(frequency, 1000000000);
- SET(offset_s, 0);
- SET(offset, 0);
+ SET(offset, offset);
+ SET(description, desc);
SET(precision, 10);
SET(is_absolute, 0);
@@ -1296,7 +1445,7 @@ static struct bt_ctf_field_type *create_int_type(int size, bool sign, bool hex)
bt_ctf_field_type_integer_set_base(type, BT_CTF_INTEGER_BASE_HEXADECIMAL))
goto err;
-#if __BYTE_ORDER == __BIG_ENDIAN
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
bt_ctf_field_type_set_byte_order(type, BT_CTF_BYTE_ORDER_BIG_ENDIAN);
#else
bt_ctf_field_type_set_byte_order(type, BT_CTF_BYTE_ORDER_LITTLE_ENDIAN);
@@ -1358,7 +1507,8 @@ static void ctf_writer__cleanup(struct ctf_writer *cw)
memset(cw, 0, sizeof(*cw));
}
-static int ctf_writer__init(struct ctf_writer *cw, const char *path)
+static int ctf_writer__init(struct ctf_writer *cw, const char *path,
+ struct perf_session *session, bool tod)
{
struct bt_ctf_writer *writer;
struct bt_ctf_stream_class *stream_class;
@@ -1382,7 +1532,7 @@ static int ctf_writer__init(struct ctf_writer *cw, const char *path)
cw->clock = clock;
- if (ctf_writer__setup_clock(cw)) {
+ if (ctf_writer__setup_clock(cw, session, tod)) {
pr("Failed to setup CTF clock.\n");
goto err_cleanup;
}
@@ -1454,49 +1604,49 @@ int bt_convert__perf2ctf(const char *input, const char *path,
struct perf_data_convert_opts *opts)
{
struct perf_session *session;
- struct perf_data_file file = {
- .path = input,
- .mode = PERF_DATA_MODE_READ,
- .force = opts->force,
- };
- struct convert c = {
- .tool = {
- .sample = process_sample_event,
- .mmap = perf_event__process_mmap,
- .mmap2 = perf_event__process_mmap2,
- .comm = perf_event__process_comm,
- .exit = perf_event__process_exit,
- .fork = perf_event__process_fork,
- .lost = perf_event__process_lost,
- .tracing_data = perf_event__process_tracing_data,
- .build_id = perf_event__process_build_id,
- .namespaces = perf_event__process_namespaces,
- .ordered_events = true,
- .ordering_requires_timestamps = true,
- },
+ struct perf_data data = {
+ .path = input,
+ .mode = PERF_DATA_MODE_READ,
+ .force = opts->force,
};
+ struct convert c = {};
struct ctf_writer *cw = &c.writer;
int err;
+ perf_tool__init(&c.tool, /*ordered_events=*/true);
+ c.tool.sample = process_sample_event;
+ c.tool.mmap = perf_event__process_mmap;
+ c.tool.mmap2 = perf_event__process_mmap2;
+ c.tool.comm = perf_event__process_comm;
+ c.tool.exit = perf_event__process_exit;
+ c.tool.fork = perf_event__process_fork;
+ c.tool.lost = perf_event__process_lost;
+ c.tool.tracing_data = perf_event__process_tracing_data;
+ c.tool.build_id = perf_event__process_build_id;
+ c.tool.namespaces = perf_event__process_namespaces;
+ c.tool.ordering_requires_timestamps = true;
+
if (opts->all) {
c.tool.comm = process_comm_event;
c.tool.exit = process_exit_event;
c.tool.fork = process_fork_event;
+ c.tool.mmap = process_mmap_event;
+ c.tool.mmap2 = process_mmap2_event;
}
err = perf_config(convert__config, &c);
if (err)
return err;
- /* CTF writer */
- if (ctf_writer__init(cw, path))
- return -1;
-
err = -1;
/* perf.data session */
- session = perf_session__new(&file, 0, &c.tool);
- if (!session)
- goto free_writer;
+ session = perf_session__new(&data, &c.tool);
+ if (IS_ERR(session))
+ return PTR_ERR(session);
+
+ /* CTF writer */
+ if (ctf_writer__init(cw, path, session, opts->tod))
+ goto free_session;
if (c.queue_size) {
ordered_events__set_alloc_size(&session->ordered_events,
@@ -1505,17 +1655,17 @@ int bt_convert__perf2ctf(const char *input, const char *path,
/* CTF writer env/clock setup */
if (ctf_writer__setup_env(cw, session))
- goto free_session;
+ goto free_writer;
/* CTF events setup */
if (setup_events(cw, session))
- goto free_session;
+ goto free_writer;
if (opts->all && setup_non_sample_events(cw, session))
- goto free_session;
+ goto free_writer;
if (setup_streams(cw, session))
- goto free_session;
+ goto free_writer;
err = perf_session__process_events(session);
if (!err)
@@ -1525,7 +1675,7 @@ int bt_convert__perf2ctf(const char *input, const char *path,
fprintf(stderr,
"[ perf data convert: Converted '%s' into CTF data '%s' ]\n",
- file.path, path);
+ data.path, path);
fprintf(stderr,
"[ perf data convert: Converted and wrote %.3f MB (%" PRIu64 " samples",
@@ -1543,10 +1693,10 @@ int bt_convert__perf2ctf(const char *input, const char *path,
return err;
-free_session:
- perf_session__delete(session);
free_writer:
ctf_writer__cleanup(cw);
+free_session:
+ perf_session__delete(session);
pr_err("Error during conversion setup.\n");
return err;
}