perf inject: Fix output from a file to a pipe
authorNamhyung Kim <namhyung@kernel.org>
Mon, 19 Jul 2021 22:31:52 +0000 (15:31 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Mon, 2 Aug 2021 13:14:34 +0000 (10:14 -0300)
When the input is a regular file but the output is a pipe, it should
write a pipe header.  But just repiping would write a portion of the
existing header which is different in 'size' value.  So we need to
prevent it and write a new pipe header along with other information
like event attributes and features.

This can handle something like this:

  # perf record -a -B sleep 1

  # perf inject -b -i perf.data | perf report -i -

Factor out perf_event__synthesize_for_pipe() to be shared between perf
record and inject.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lore.kernel.org/lkml/20210719223153.1618812-5-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/builtin-inject.c
tools/perf/builtin-record.c
tools/perf/util/synthetic-events.c
tools/perf/util/synthetic-events.h

index f9af243..6ad191e 100644 (file)
@@ -919,6 +919,7 @@ int cmd_inject(int argc, const char **argv)
                .use_stdio = true,
        };
        int ret;
+       bool repipe = true;
 
        struct option options[] = {
                OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
@@ -993,10 +994,18 @@ int cmd_inject(int argc, const char **argv)
        }
 
        data.path = inject.input_name;
-       if (!strcmp(inject.input_name, "-") || inject.output.is_pipe)
+       if (!strcmp(inject.input_name, "-") || inject.output.is_pipe) {
                inject.is_pipe = true;
+               /*
+                * Do not repipe header when input is a regular file
+                * since either it can rewrite the header at the end
+                * or write a new pipe header.
+                */
+               if (strcmp(inject.input_name, "-"))
+                       repipe = false;
+       }
 
-       inject.session = __perf_session__new(&data, inject.is_pipe,
+       inject.session = __perf_session__new(&data, repipe,
                                             perf_data__fd(&inject.output),
                                             &inject.tool);
        if (IS_ERR(inject.session)) {
@@ -1007,6 +1016,21 @@ int cmd_inject(int argc, const char **argv)
        if (zstd_init(&(inject.session->zstd_data), 0) < 0)
                pr_warning("Decompression initialization failed.\n");
 
+       if (!data.is_pipe && inject.output.is_pipe) {
+               ret = perf_header__write_pipe(perf_data__fd(&inject.output));
+               if (ret < 0) {
+                       pr_err("Couldn't write a new pipe header.\n");
+                       goto out_delete;
+               }
+
+               ret = perf_event__synthesize_for_pipe(&inject.tool,
+                                                     inject.session,
+                                                     &inject.output,
+                                                     perf_event__repipe);
+               if (ret < 0)
+                       goto out_delete;
+       }
+
        if (inject.build_ids && !inject.build_id_all) {
                /*
                 * to make sure the mmap records are ordered correctly
index 472cd12..548c1db 100644 (file)
@@ -1387,7 +1387,6 @@ static int record__synthesize(struct record *rec, bool tail)
        struct perf_data *data = &rec->data;
        struct record_opts *opts = &rec->opts;
        struct perf_tool *tool = &rec->tool;
-       int fd = perf_data__fd(data);
        int err = 0;
        event_op f = process_synthesized_event;
 
@@ -1395,41 +1394,12 @@ static int record__synthesize(struct record *rec, bool tail)
                return 0;
 
        if (data->is_pipe) {
-               /*
-                * We need to synthesize events first, because some
-                * features works on top of them (on report side).
-                */
-               err = perf_event__synthesize_attrs(tool, rec->evlist,
-                                                  process_synthesized_event);
-               if (err < 0) {
-                       pr_err("Couldn't synthesize attrs.\n");
-                       goto out;
-               }
-
-               err = perf_event__synthesize_features(tool, session, rec->evlist,
+               err = perf_event__synthesize_for_pipe(tool, session, data,
                                                      process_synthesized_event);
-               if (err < 0) {
-                       pr_err("Couldn't synthesize features.\n");
-                       return err;
-               }
+               if (err < 0)
+                       goto out;
 
-               if (have_tracepoints(&rec->evlist->core.entries)) {
-                       /*
-                        * FIXME err <= 0 here actually means that
-                        * there were no tracepoints so its not really
-                        * an error, just that we don't need to
-                        * synthesize anything.  We really have to
-                        * return this more properly and also
-                        * propagate errors that now are calling die()
-                        */
-                       err = perf_event__synthesize_tracing_data(tool, fd, rec->evlist,
-                                                                 process_synthesized_event);
-                       if (err <= 0) {
-                               pr_err("Couldn't record tracing data.\n");
-                               goto out;
-                       }
-                       rec->bytes_written += err;
-               }
+               rec->bytes_written += err;
        }
 
        err = perf_event__synth_time_conv(record__pick_pc(rec), tool,
index 35aa0c0..a7e981b 100644 (file)
@@ -1,5 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only 
 
+#include "util/cgroup.h"
+#include "util/data.h"
 #include "util/debug.h"
 #include "util/dso.h"
 #include "util/event.h"
@@ -16,7 +18,6 @@
 #include "util/synthetic-events.h"
 #include "util/target.h"
 #include "util/time-utils.h"
-#include "util/cgroup.h"
 #include <linux/bitops.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -2179,3 +2180,53 @@ int perf_event__synthesize_features(struct perf_tool *tool, struct perf_session
        free(ff.buf);
        return ret;
 }
+
+int perf_event__synthesize_for_pipe(struct perf_tool *tool,
+                                   struct perf_session *session,
+                                   struct perf_data *data,
+                                   perf_event__handler_t process)
+{
+       int err;
+       int ret = 0;
+       struct evlist *evlist = session->evlist;
+
+       /*
+        * We need to synthesize events first, because some
+        * features works on top of them (on report side).
+        */
+       err = perf_event__synthesize_attrs(tool, evlist, process);
+       if (err < 0) {
+               pr_err("Couldn't synthesize attrs.\n");
+               return err;
+       }
+       ret += err;
+
+       err = perf_event__synthesize_features(tool, session, evlist, process);
+       if (err < 0) {
+               pr_err("Couldn't synthesize features.\n");
+               return err;
+       }
+       ret += err;
+
+       if (have_tracepoints(&evlist->core.entries)) {
+               int fd = perf_data__fd(data);
+
+               /*
+                * FIXME err <= 0 here actually means that
+                * there were no tracepoints so its not really
+                * an error, just that we don't need to
+                * synthesize anything.  We really have to
+                * return this more properly and also
+                * propagate errors that now are calling die()
+                */
+               err = perf_event__synthesize_tracing_data(tool, fd, evlist,
+                                                         process);
+               if (err <= 0) {
+                       pr_err("Couldn't record tracing data.\n");
+                       return err;
+               }
+               ret += err;
+       }
+
+       return ret;
+}
index e7a3e95..c845e2b 100644 (file)
@@ -14,6 +14,7 @@ struct evsel;
 struct machine;
 struct perf_counts_values;
 struct perf_cpu_map;
+struct perf_data;
 struct perf_event_attr;
 struct perf_event_mmap_page;
 struct perf_sample;
@@ -101,4 +102,9 @@ static inline int perf_event__synthesize_bpf_events(struct perf_session *session
 }
 #endif // HAVE_LIBBPF_SUPPORT
 
+int perf_event__synthesize_for_pipe(struct perf_tool *tool,
+                                   struct perf_session *session,
+                                   struct perf_data *data,
+                                   perf_event__handler_t process);
+
 #endif // __PERF_SYNTHETIC_EVENTS_H