[PATCH 6/8] perf data: Switch to multiple cpu stream files
From: Sebastian Andrzej Siewior 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. Cc: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Frederic Weisbecker Cc: Jeremie Galarneau Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Sebastian Andrzej Siewior Cc: Tom Zanussi Signed-off-by: Jiri Olsa Signed-off-by: Sebastian Andrzej Siewior --- tools/perf/util/data-convert-bt.c | 205 +- 1 file changed, 181 insertions(+), 24 deletions(-) diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 6fa5c3ef336b..4bb769e081a8 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -38,12 +38,20 @@ struct evsel_priv { struct bt_ctf_event_class *event_class; }; +#define MAX_CPUS 4096 + +struct ctf_stream { + struct bt_ctf_stream *stream; + int cpu; +}; + struct ctf_writer { /* writer primitives */ - struct bt_ctf_writer*writer; - struct bt_ctf_stream*stream; - struct bt_ctf_stream_class *stream_class; - struct bt_ctf_clock *clock; + struct bt_ctf_writer *writer; + struct ctf_stream **stream; + int stream_cnt; + struct bt_ctf_stream_class *stream_class; + struct bt_ctf_clock *clock; /* data types */ union { @@ -346,12 +354,6 @@ static int add_generic_values(struct ctf_writer *cw, 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) { ret = value_set_u64(cw, event, "perf_period", sample->period); if (ret) @@ -381,6 +383,113 @@ static int add_generic_values(struct ctf_writer *cw, 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
[PATCH 6/8] perf data: Switch to multiple cpu stream files
From: Sebastian Andrzej Siewior bige...@linutronix.de 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. Cc: Arnaldo Carvalho de Melo a...@redhat.com Cc: David Ahern dsah...@gmail.com Cc: Frederic Weisbecker fweis...@gmail.com Cc: Jeremie Galarneau jga...@efficios.com Cc: Jiri Olsa jo...@kernel.org Cc: Namhyung Kim namhy...@gmail.com Cc: Paul Mackerras pau...@samba.org Cc: Peter Zijlstra pet...@infradead.org Cc: Sebastian Andrzej Siewior bige...@linutronix.de Cc: Tom Zanussi tzanu...@gmail.com Signed-off-by: Jiri Olsa jo...@kernel.org Signed-off-by: Sebastian Andrzej Siewior bige...@linutronix.de --- tools/perf/util/data-convert-bt.c | 205 +- 1 file changed, 181 insertions(+), 24 deletions(-) diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 6fa5c3ef336b..4bb769e081a8 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -38,12 +38,20 @@ struct evsel_priv { struct bt_ctf_event_class *event_class; }; +#define MAX_CPUS 4096 + +struct ctf_stream { + struct bt_ctf_stream *stream; + int cpu; +}; + struct ctf_writer { /* writer primitives */ - struct bt_ctf_writer*writer; - struct bt_ctf_stream*stream; - struct bt_ctf_stream_class *stream_class; - struct bt_ctf_clock *clock; + struct bt_ctf_writer *writer; + struct ctf_stream **stream; + int stream_cnt; + struct bt_ctf_stream_class *stream_class; + struct bt_ctf_clock *clock; /* data types */ union { @@ -346,12 +354,6 @@ static int add_generic_values(struct ctf_writer *cw, 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) { ret = value_set_u64(cw, event, perf_period, sample-period); if (ret) @@ -381,6 +383,113 @@ static int add_generic_values(struct ctf_writer *cw, 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; +
[PATCH 6/8] perf data: Switch to multiple cpu stream files
From: Sebastian Andrzej Siewior 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. Cc: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Frederic Weisbecker Cc: Jeremie Galarneau Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Sebastian Andrzej Siewior Cc: Tom Zanussi Signed-off-by: Jiri Olsa Signed-off-by: Sebastian Andrzej Siewior --- tools/perf/util/data-convert-bt.c | 205 +- 1 file changed, 181 insertions(+), 24 deletions(-) diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 6fa5c3ef336b..4bb769e081a8 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -38,12 +38,20 @@ struct evsel_priv { struct bt_ctf_event_class *event_class; }; +#define MAX_CPUS 4096 + +struct ctf_stream { + struct bt_ctf_stream *stream; + int cpu; +}; + struct ctf_writer { /* writer primitives */ - struct bt_ctf_writer*writer; - struct bt_ctf_stream*stream; - struct bt_ctf_stream_class *stream_class; - struct bt_ctf_clock *clock; + struct bt_ctf_writer *writer; + struct ctf_stream **stream; + int stream_cnt; + struct bt_ctf_stream_class *stream_class; + struct bt_ctf_clock *clock; /* data types */ union { @@ -346,12 +354,6 @@ static int add_generic_values(struct ctf_writer *cw, 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) { ret = value_set_u64(cw, event, "perf_period", sample->period); if (ret) @@ -381,6 +383,113 @@ static int add_generic_values(struct ctf_writer *cw, 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
[PATCH 6/8] perf data: Switch to multiple cpu stream files
From: Sebastian Andrzej Siewior bige...@linutronix.de 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. Cc: Arnaldo Carvalho de Melo a...@redhat.com Cc: David Ahern dsah...@gmail.com Cc: Frederic Weisbecker fweis...@gmail.com Cc: Jeremie Galarneau jga...@efficios.com Cc: Jiri Olsa jo...@kernel.org Cc: Namhyung Kim namhy...@gmail.com Cc: Paul Mackerras pau...@samba.org Cc: Peter Zijlstra pet...@infradead.org Cc: Sebastian Andrzej Siewior bige...@linutronix.de Cc: Tom Zanussi tzanu...@gmail.com Signed-off-by: Jiri Olsa jo...@kernel.org Signed-off-by: Sebastian Andrzej Siewior bige...@linutronix.de --- tools/perf/util/data-convert-bt.c | 205 +- 1 file changed, 181 insertions(+), 24 deletions(-) diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 6fa5c3ef336b..4bb769e081a8 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -38,12 +38,20 @@ struct evsel_priv { struct bt_ctf_event_class *event_class; }; +#define MAX_CPUS 4096 + +struct ctf_stream { + struct bt_ctf_stream *stream; + int cpu; +}; + struct ctf_writer { /* writer primitives */ - struct bt_ctf_writer*writer; - struct bt_ctf_stream*stream; - struct bt_ctf_stream_class *stream_class; - struct bt_ctf_clock *clock; + struct bt_ctf_writer *writer; + struct ctf_stream **stream; + int stream_cnt; + struct bt_ctf_stream_class *stream_class; + struct bt_ctf_clock *clock; /* data types */ union { @@ -346,12 +354,6 @@ static int add_generic_values(struct ctf_writer *cw, 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) { ret = value_set_u64(cw, event, perf_period, sample-period); if (ret) @@ -381,6 +383,113 @@ static int add_generic_values(struct ctf_writer *cw, 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; +
Re: [PATCH 6/8] perf data: Switch to multiple cpu stream files
On Mon, Dec 08, 2014 at 05:17:44PM +0900, Namhyung Kim wrote: > On Thu, Dec 4, 2014 at 1:24 AM, Jiri Olsa wrote: > > +static int setup_streams(struct ctf_writer *cw, struct perf_session > > *session) > > +{ > > + struct ctf_stream **stream; > > + struct perf_header *ph = >header; > > + int ncpus; > > + > > + /* > > +* Try to get the number of cpus used in the data file, > > +* if not present fallback to the MAX_CPUS. > > +*/ > > + if (!ph) > > I think this check is meaningless since perf_header struct is embedded > in perf_session so it shouldn't be NULL when refered from a session.. right, it's actually different in the git, I used: if (!ph || !ph->env.nr_cpus_avail) ncpus = MAX_CPUS; I attached slightyl older version in email :-\ anyway, I'll send v2 shortly thanks, jirka -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 6/8] perf data: Switch to multiple cpu stream files
On Mon, Dec 08, 2014 at 05:17:44PM +0900, Namhyung Kim wrote: On Thu, Dec 4, 2014 at 1:24 AM, Jiri Olsa jo...@kernel.org wrote: +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. +*/ + if (!ph) I think this check is meaningless since perf_header struct is embedded in perf_session so it shouldn't be NULL when refered from a session.. right, it's actually different in the git, I used: if (!ph || !ph-env.nr_cpus_avail) ncpus = MAX_CPUS; I attached slightyl older version in email :-\ anyway, I'll send v2 shortly thanks, jirka -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 6/8] perf data: Switch to multiple cpu stream files
On Thu, Dec 4, 2014 at 1:24 AM, Jiri Olsa wrote: > +static int setup_streams(struct ctf_writer *cw, struct perf_session *session) > +{ > + struct ctf_stream **stream; > + struct perf_header *ph = >header; > + int ncpus; > + > + /* > +* Try to get the number of cpus used in the data file, > +* if not present fallback to the MAX_CPUS. > +*/ > + if (!ph) I think this check is meaningless since perf_header struct is embedded in perf_session so it shouldn't be NULL when refered from a session.. Thanks, Namhyung > + ncpus = MAX_CPUS; > + else > + ncpus = ph->env.nr_cpus_avail; > + > + 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; > +} -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 6/8] perf data: Switch to multiple cpu stream files
On Thu, Dec 4, 2014 at 1:24 AM, Jiri Olsa jo...@kernel.org wrote: +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. +*/ + if (!ph) I think this check is meaningless since perf_header struct is embedded in perf_session so it shouldn't be NULL when refered from a session.. Thanks, Namhyung + ncpus = MAX_CPUS; + else + ncpus = ph-env.nr_cpus_avail; + + 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; +} -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 6/8] perf data: Switch to multiple cpu stream files
From: Sebastian Andrzej Siewior 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. Cc: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Frederic Weisbecker Cc: Jeremie Galarneau Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Sebastian Andrzej Siewior Cc: Tom Zanussi Signed-off-by: Jiri Olsa Signed-off-by: Sebastian Andrzej Siewior --- tools/perf/util/data-convert-bt.c | 208 +- 1 file changed, 184 insertions(+), 24 deletions(-) diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index cf1b16c89120..2bc70b8d128d 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -38,12 +38,20 @@ struct evsel_priv { struct bt_ctf_event_class *event_class; }; +#define MAX_CPUS 4096 + +struct ctf_stream { + struct bt_ctf_stream *stream; + int cpu; +}; + struct ctf_writer { /* writer primitives */ - struct bt_ctf_writer*writer; - struct bt_ctf_stream*stream; - struct bt_ctf_stream_class *stream_class; - struct bt_ctf_clock *clock; + struct bt_ctf_writer *writer; + struct ctf_stream **stream; + int stream_cnt; + struct bt_ctf_stream_class *stream_class; + struct bt_ctf_clock *clock; /* data types */ union { @@ -346,12 +354,6 @@ static int add_generic_values(struct ctf_writer *cw, 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) { ret = value_set_u64(cw, event, "perf_period", sample->period); if (ret) @@ -381,6 +383,113 @@ static int add_generic_values(struct ctf_writer *cw, 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
[PATCH 6/8] perf data: Switch to multiple cpu stream files
From: Sebastian Andrzej Siewior bige...@linutronix.de 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. Cc: Arnaldo Carvalho de Melo a...@redhat.com Cc: David Ahern dsah...@gmail.com Cc: Frederic Weisbecker fweis...@gmail.com Cc: Jeremie Galarneau jga...@efficios.com Cc: Jiri Olsa jo...@kernel.org Cc: Namhyung Kim namhy...@gmail.com Cc: Paul Mackerras pau...@samba.org Cc: Peter Zijlstra pet...@infradead.org Cc: Sebastian Andrzej Siewior bige...@linutronix.de Cc: Tom Zanussi tzanu...@gmail.com Signed-off-by: Jiri Olsa jo...@kernel.org Signed-off-by: Sebastian Andrzej Siewior bige...@linutronix.de --- tools/perf/util/data-convert-bt.c | 208 +- 1 file changed, 184 insertions(+), 24 deletions(-) diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index cf1b16c89120..2bc70b8d128d 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -38,12 +38,20 @@ struct evsel_priv { struct bt_ctf_event_class *event_class; }; +#define MAX_CPUS 4096 + +struct ctf_stream { + struct bt_ctf_stream *stream; + int cpu; +}; + struct ctf_writer { /* writer primitives */ - struct bt_ctf_writer*writer; - struct bt_ctf_stream*stream; - struct bt_ctf_stream_class *stream_class; - struct bt_ctf_clock *clock; + struct bt_ctf_writer *writer; + struct ctf_stream **stream; + int stream_cnt; + struct bt_ctf_stream_class *stream_class; + struct bt_ctf_clock *clock; /* data types */ union { @@ -346,12 +354,6 @@ static int add_generic_values(struct ctf_writer *cw, 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) { ret = value_set_u64(cw, event, perf_period, sample-period); if (ret) @@ -381,6 +383,113 @@ static int add_generic_values(struct ctf_writer *cw, 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; +