Commit 90e129ff authored by Sebastian Andrzej Siewior's avatar Sebastian Andrzej Siewior Committed by Arnaldo Carvalho de Melo

perf data: Switch to multiple cpu stream files

Currently we store the data into single data strea/file. The cpu if data
is stored within the event sample. The lttng puts the CPU number that
belongs to the event into the packet context instead into the event.

This patch makes sure that the trace produce by perf does look the same
way. We now use one stream per-CPU. Having it all in one stream
increased the total size of the resulting file. The test went from
416KiB (with perf_cpu event member) to 24MiB due to the required (and
pointless) flush. With the per-cpu streams the total size went up to
588KiB.
Signed-off-by: default avatarSebastian Andrzej Siewior <bigeasy@linutronix.de>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: He Kuang <hekuang@huawei.com>
Cc: Jeremie Galarneau <jgalar@efficios.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Tom Zanussi <tzanussi@gmail.com>
Cc: Wang Nan <wangnan0@huawei.com>
Link: http://lkml.kernel.org/r/1429372220-6406-3-git-send-email-jolsa@kernel.orgSigned-off-by: default avatarJiri Olsa <jolsa@kernel.org>
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent c41c6647
...@@ -38,12 +38,20 @@ struct evsel_priv { ...@@ -38,12 +38,20 @@ struct evsel_priv {
struct bt_ctf_event_class *event_class; struct bt_ctf_event_class *event_class;
}; };
#define MAX_CPUS 4096
struct ctf_stream {
struct bt_ctf_stream *stream;
int cpu;
};
struct ctf_writer { struct ctf_writer {
/* writer primitives */ /* writer primitives */
struct bt_ctf_writer *writer; struct bt_ctf_writer *writer;
struct bt_ctf_stream *stream; struct ctf_stream **stream;
struct bt_ctf_stream_class *stream_class; int stream_cnt;
struct bt_ctf_clock *clock; struct bt_ctf_stream_class *stream_class;
struct bt_ctf_clock *clock;
/* data types */ /* data types */
union { union {
...@@ -346,12 +354,6 @@ static int add_generic_values(struct ctf_writer *cw, ...@@ -346,12 +354,6 @@ static int add_generic_values(struct ctf_writer *cw,
return -1; return -1;
} }
if (type & PERF_SAMPLE_CPU) {
ret = value_set_u32(cw, event, "perf_cpu", sample->cpu);
if (ret)
return -1;
}
if (type & PERF_SAMPLE_PERIOD) { if (type & PERF_SAMPLE_PERIOD) {
ret = value_set_u64(cw, event, "perf_period", sample->period); ret = value_set_u64(cw, event, "perf_period", sample->period);
if (ret) if (ret)
...@@ -381,6 +383,113 @@ static int add_generic_values(struct ctf_writer *cw, ...@@ -381,6 +383,113 @@ static int add_generic_values(struct ctf_writer *cw,
return 0; return 0;
} }
static int ctf_stream__flush(struct ctf_stream *cs)
{
int err = 0;
if (cs) {
err = bt_ctf_stream_flush(cs->stream);
if (err)
pr_err("CTF stream %d flush failed\n", cs->cpu);
pr("Flush stream for cpu %d\n", cs->cpu);
}
return err;
}
static struct ctf_stream *ctf_stream__create(struct ctf_writer *cw, int cpu)
{
struct ctf_stream *cs;
struct bt_ctf_field *pkt_ctx = NULL;
struct bt_ctf_field *cpu_field = NULL;
struct bt_ctf_stream *stream = NULL;
int ret;
cs = zalloc(sizeof(*cs));
if (!cs) {
pr_err("Failed to allocate ctf stream\n");
return NULL;
}
stream = bt_ctf_writer_create_stream(cw->writer, cw->stream_class);
if (!stream) {
pr_err("Failed to create CTF stream\n");
goto out;
}
pkt_ctx = bt_ctf_stream_get_packet_context(stream);
if (!pkt_ctx) {
pr_err("Failed to obtain packet context\n");
goto out;
}
cpu_field = bt_ctf_field_structure_get_field(pkt_ctx, "cpu_id");
bt_ctf_field_put(pkt_ctx);
if (!cpu_field) {
pr_err("Failed to obtain cpu field\n");
goto out;
}
ret = bt_ctf_field_unsigned_integer_set_value(cpu_field, (u32) cpu);
if (ret) {
pr_err("Failed to update CPU number\n");
goto out;
}
bt_ctf_field_put(cpu_field);
cs->cpu = cpu;
cs->stream = stream;
return cs;
out:
if (cpu_field)
bt_ctf_field_put(cpu_field);
if (stream)
bt_ctf_stream_put(stream);
free(cs);
return NULL;
}
static void ctf_stream__delete(struct ctf_stream *cs)
{
if (cs) {
bt_ctf_stream_put(cs->stream);
free(cs);
}
}
static struct ctf_stream *ctf_stream(struct ctf_writer *cw, int cpu)
{
struct ctf_stream *cs = cw->stream[cpu];
if (!cs) {
cs = ctf_stream__create(cw, cpu);
cw->stream[cpu] = cs;
}
return cs;
}
static int get_sample_cpu(struct ctf_writer *cw, struct perf_sample *sample,
struct perf_evsel *evsel)
{
int cpu = 0;
if (evsel->attr.sample_type & PERF_SAMPLE_CPU)
cpu = sample->cpu;
if (cpu > cw->stream_cnt) {
pr_err("Event was recorded for CPU %d, limit is at %d.\n",
cpu, cw->stream_cnt);
cpu = 0;
}
return cpu;
}
static int process_sample_event(struct perf_tool *tool, static int process_sample_event(struct perf_tool *tool,
union perf_event *_event __maybe_unused, union perf_event *_event __maybe_unused,
struct perf_sample *sample, struct perf_sample *sample,
...@@ -390,6 +499,7 @@ static int process_sample_event(struct perf_tool *tool, ...@@ -390,6 +499,7 @@ static int process_sample_event(struct perf_tool *tool,
struct convert *c = container_of(tool, struct convert, tool); struct convert *c = container_of(tool, struct convert, tool);
struct evsel_priv *priv = evsel->priv; struct evsel_priv *priv = evsel->priv;
struct ctf_writer *cw = &c->writer; struct ctf_writer *cw = &c->writer;
struct ctf_stream *cs;
struct bt_ctf_event_class *event_class; struct bt_ctf_event_class *event_class;
struct bt_ctf_event *event; struct bt_ctf_event *event;
int ret; int ret;
...@@ -424,9 +534,12 @@ static int process_sample_event(struct perf_tool *tool, ...@@ -424,9 +534,12 @@ static int process_sample_event(struct perf_tool *tool,
return -1; return -1;
} }
bt_ctf_stream_append_event(cw->stream, event); cs = ctf_stream(cw, get_sample_cpu(cw, sample, evsel));
if (cs)
bt_ctf_stream_append_event(cs->stream, event);
bt_ctf_event_put(event); bt_ctf_event_put(event);
return 0; return cs ? 0 : -1;
} }
static int add_tracepoint_fields_types(struct ctf_writer *cw, static int add_tracepoint_fields_types(struct ctf_writer *cw,
...@@ -528,9 +641,6 @@ static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel, ...@@ -528,9 +641,6 @@ static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel,
if (type & PERF_SAMPLE_STREAM_ID) if (type & PERF_SAMPLE_STREAM_ID)
ADD_FIELD(event_class, cw->data.u64, "perf_stream_id"); ADD_FIELD(event_class, cw->data.u64, "perf_stream_id");
if (type & PERF_SAMPLE_CPU)
ADD_FIELD(event_class, cw->data.u32, "perf_cpu");
if (type & PERF_SAMPLE_PERIOD) if (type & PERF_SAMPLE_PERIOD)
ADD_FIELD(event_class, cw->data.u64, "perf_period"); ADD_FIELD(event_class, cw->data.u64, "perf_period");
...@@ -604,6 +714,39 @@ static int setup_events(struct ctf_writer *cw, struct perf_session *session) ...@@ -604,6 +714,39 @@ static int setup_events(struct ctf_writer *cw, struct perf_session *session)
return 0; return 0;
} }
static int setup_streams(struct ctf_writer *cw, struct perf_session *session)
{
struct ctf_stream **stream;
struct perf_header *ph = &session->header;
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;
stream = zalloc(sizeof(*stream) * ncpus);
if (!stream) {
pr_err("Failed to allocate streams.\n");
return -ENOMEM;
}
cw->stream = stream;
cw->stream_cnt = ncpus;
return 0;
}
static void free_streams(struct ctf_writer *cw)
{
int cpu;
for (cpu = 0; cpu < cw->stream_cnt; cpu++)
ctf_stream__delete(cw->stream[cpu]);
free(cw->stream);
}
static int ctf_writer__setup_env(struct ctf_writer *cw, static int ctf_writer__setup_env(struct ctf_writer *cw,
struct perf_session *session) struct perf_session *session)
{ {
...@@ -713,7 +856,7 @@ static void ctf_writer__cleanup(struct ctf_writer *cw) ...@@ -713,7 +856,7 @@ static void ctf_writer__cleanup(struct ctf_writer *cw)
ctf_writer__cleanup_data(cw); ctf_writer__cleanup_data(cw);
bt_ctf_clock_put(cw->clock); bt_ctf_clock_put(cw->clock);
bt_ctf_stream_put(cw->stream); free_streams(cw);
bt_ctf_stream_class_put(cw->stream_class); bt_ctf_stream_class_put(cw->stream_class);
bt_ctf_writer_put(cw->writer); bt_ctf_writer_put(cw->writer);
...@@ -725,8 +868,9 @@ static int ctf_writer__init(struct ctf_writer *cw, const char *path) ...@@ -725,8 +868,9 @@ static int ctf_writer__init(struct ctf_writer *cw, const char *path)
{ {
struct bt_ctf_writer *writer; struct bt_ctf_writer *writer;
struct bt_ctf_stream_class *stream_class; struct bt_ctf_stream_class *stream_class;
struct bt_ctf_stream *stream;
struct bt_ctf_clock *clock; struct bt_ctf_clock *clock;
struct bt_ctf_field_type *pkt_ctx_type;
int ret;
/* CTF writer */ /* CTF writer */
writer = bt_ctf_writer_create(path); writer = bt_ctf_writer_create(path);
...@@ -767,14 +911,15 @@ static int ctf_writer__init(struct ctf_writer *cw, const char *path) ...@@ -767,14 +911,15 @@ static int ctf_writer__init(struct ctf_writer *cw, const char *path)
if (ctf_writer__init_data(cw)) if (ctf_writer__init_data(cw))
goto err_cleanup; goto err_cleanup;
/* CTF stream instance */ /* Add cpu_id for packet context */
stream = bt_ctf_writer_create_stream(writer, stream_class); pkt_ctx_type = bt_ctf_stream_class_get_packet_context_type(stream_class);
if (!stream) { if (!pkt_ctx_type)
pr("Failed to create CTF stream.\n");
goto err_cleanup; goto err_cleanup;
}
cw->stream = stream; ret = bt_ctf_field_type_structure_add_field(pkt_ctx_type, cw->data.u32, "cpu_id");
bt_ctf_field_type_put(pkt_ctx_type);
if (ret)
goto err_cleanup;
/* CTF clock writer setup */ /* CTF clock writer setup */
if (bt_ctf_writer_add_clock(writer, clock)) { if (bt_ctf_writer_add_clock(writer, clock)) {
...@@ -791,6 +936,16 @@ static int ctf_writer__init(struct ctf_writer *cw, const char *path) ...@@ -791,6 +936,16 @@ static int ctf_writer__init(struct ctf_writer *cw, const char *path)
return -1; return -1;
} }
static int ctf_writer__flush_streams(struct ctf_writer *cw)
{
int cpu, ret = 0;
for (cpu = 0; cpu < cw->stream_cnt && !ret; cpu++)
ret = ctf_stream__flush(cw->stream[cpu]);
return ret;
}
int bt_convert__perf2ctf(const char *input, const char *path, bool force) int bt_convert__perf2ctf(const char *input, const char *path, bool force)
{ {
struct perf_session *session; struct perf_session *session;
...@@ -834,9 +989,12 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force) ...@@ -834,9 +989,12 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force)
if (setup_events(cw, session)) if (setup_events(cw, session))
goto free_session; goto free_session;
if (setup_streams(cw, session))
goto free_session;
err = perf_session__process_events(session); err = perf_session__process_events(session);
if (!err) if (!err)
err = bt_ctf_stream_flush(cw->stream); err = ctf_writer__flush_streams(cw);
else else
pr_err("Error during conversion.\n"); pr_err("Error during conversion.\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment