All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/5] perf inject: Minor improvements
@ 2022-05-20 13:23 Adrian Hunter
  2022-05-20 13:24 ` [PATCH 1/5] perf header: Add ability to keep feature sections Adrian Hunter
                   ` (5 more replies)
  0 siblings, 6 replies; 12+ messages in thread
From: Adrian Hunter @ 2022-05-20 13:23 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo; +Cc: Jiri Olsa, Namhyung Kim, linux-kernel

Hi

Here are patches for 2 minor improvements for perf inject:
1. Keep some features sections from input file
2. Keep a copy of kcore_dir


Adrian Hunter (5):
      perf header: Add ability to keep feature sections
      libperf: Add preadn()
      perf inject: Keep some features sections from input file
      perf data: Add has_kcore_dir()
      perf inject: Keep a copy of kcore_dir

 tools/lib/perf/include/internal/lib.h |   2 +
 tools/lib/perf/lib.c                  |  20 +++++
 tools/perf/builtin-inject.c           | 162 +++++++++++++++++++++++++++++++++-
 tools/perf/util/data.c                |  14 +++
 tools/perf/util/data.h                |   1 +
 tools/perf/util/header.c              |  62 +++++++++++--
 tools/perf/util/header.h              |  15 ++++
 7 files changed, 264 insertions(+), 12 deletions(-)


Regards
Adrian

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/5] perf header: Add ability to keep feature sections
  2022-05-20 13:23 [PATCH 0/5] perf inject: Minor improvements Adrian Hunter
@ 2022-05-20 13:24 ` Adrian Hunter
  2022-05-20 13:24 ` [PATCH 2/5] libperf: Add preadn() Adrian Hunter
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 12+ messages in thread
From: Adrian Hunter @ 2022-05-20 13:24 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo; +Cc: Jiri Olsa, Namhyung Kim, linux-kernel

Many feature sections should not be re-written during perf inject. In
preparation to support that, add callbacks that a tool can use to copy
a feature section from elsewhere. perf inject will use this facility to
copy features sections from the input file.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/util/header.c | 54 ++++++++++++++++++++++++++++++++++------
 tools/perf/util/header.h | 10 ++++++++
 2 files changed, 56 insertions(+), 8 deletions(-)

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index a27132e5a5ef..b0c57a130d1e 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -3462,9 +3462,22 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full)
 	return 0;
 }
 
+struct header_fw {
+	struct feat_writer	fw;
+	struct feat_fd		*ff;
+};
+
+static int feat_writer_cb(struct feat_writer *fw, void *buf, size_t sz)
+{
+	struct header_fw *h = container_of(fw, struct header_fw, fw);
+
+	return do_write(h->ff, buf, sz);
+}
+
 static int do_write_feat(struct feat_fd *ff, int type,
 			 struct perf_file_section **p,
-			 struct evlist *evlist)
+			 struct evlist *evlist,
+			 struct feat_copier *fc)
 {
 	int err;
 	int ret = 0;
@@ -3478,7 +3491,23 @@ static int do_write_feat(struct feat_fd *ff, int type,
 
 		(*p)->offset = lseek(ff->fd, 0, SEEK_CUR);
 
-		err = feat_ops[type].write(ff, evlist);
+		/*
+		 * Hook to let perf inject copy features sections from the input
+		 * file.
+		 */
+		if (fc && fc->copy) {
+			struct header_fw h = {
+				.fw.write = feat_writer_cb,
+				.ff = ff,
+			};
+
+			/* ->copy() returns 0 if the feature was not copied */
+			err = fc->copy(fc, type, &h.fw);
+		} else {
+			err = 0;
+		}
+		if (!err)
+			err = feat_ops[type].write(ff, evlist);
 		if (err < 0) {
 			pr_debug("failed to write feature %s\n", feat_ops[type].name);
 
@@ -3494,7 +3523,8 @@ static int do_write_feat(struct feat_fd *ff, int type,
 }
 
 static int perf_header__adds_write(struct perf_header *header,
-				   struct evlist *evlist, int fd)
+				   struct evlist *evlist, int fd,
+				   struct feat_copier *fc)
 {
 	int nr_sections;
 	struct feat_fd ff;
@@ -3523,7 +3553,7 @@ static int perf_header__adds_write(struct perf_header *header,
 	lseek(fd, sec_start + sec_size, SEEK_SET);
 
 	for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) {
-		if (do_write_feat(&ff, feat, &p, evlist))
+		if (do_write_feat(&ff, feat, &p, evlist, fc))
 			perf_header__clear_feat(header, feat);
 	}
 
@@ -3561,9 +3591,10 @@ int perf_header__write_pipe(int fd)
 	return 0;
 }
 
-int perf_session__write_header(struct perf_session *session,
-			       struct evlist *evlist,
-			       int fd, bool at_exit)
+static int perf_session__do_write_header(struct perf_session *session,
+					 struct evlist *evlist,
+					 int fd, bool at_exit,
+					 struct feat_copier *fc)
 {
 	struct perf_file_header f_header;
 	struct perf_file_attr   f_attr;
@@ -3615,7 +3646,7 @@ int perf_session__write_header(struct perf_session *session,
 	header->feat_offset = header->data_offset + header->data_size;
 
 	if (at_exit) {
-		err = perf_header__adds_write(header, evlist, fd);
+		err = perf_header__adds_write(header, evlist, fd, fc);
 		if (err < 0)
 			return err;
 	}
@@ -3648,6 +3679,13 @@ int perf_session__write_header(struct perf_session *session,
 	return 0;
 }
 
+int perf_session__write_header(struct perf_session *session,
+			       struct evlist *evlist,
+			       int fd, bool at_exit)
+{
+	return perf_session__do_write_header(session, evlist, fd, at_exit, NULL);
+}
+
 static int perf_header__getbuffer64(struct perf_header *header,
 				    int fd, void *buf, size_t size)
 {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 0eb4bc29a5a4..e76ab02d5541 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -121,6 +121,16 @@ int perf_session__write_header(struct perf_session *session,
 			       int fd, bool at_exit);
 int perf_header__write_pipe(int fd);
 
+/* feat_writer writes a feature section to output */
+struct feat_writer {
+	int (*write)(struct feat_writer *fw, void *buf, size_t sz);
+};
+
+/* feat_copier copies a feature section using feat_writer to output */
+struct feat_copier {
+	int (*copy)(struct feat_copier *fc, int feat, struct feat_writer *fw);
+};
+
 void perf_header__set_feat(struct perf_header *header, int feat);
 void perf_header__clear_feat(struct perf_header *header, int feat);
 bool perf_header__has_feat(const struct perf_header *header, int feat);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/5] libperf: Add preadn()
  2022-05-20 13:23 [PATCH 0/5] perf inject: Minor improvements Adrian Hunter
  2022-05-20 13:24 ` [PATCH 1/5] perf header: Add ability to keep feature sections Adrian Hunter
@ 2022-05-20 13:24 ` Adrian Hunter
  2022-05-20 13:55   ` David Laight
  2022-05-20 15:56   ` [PATCH V2 " Adrian Hunter
  2022-05-20 13:24 ` [PATCH 3/5] perf inject: Keep some features sections from input file Adrian Hunter
                   ` (3 subsequent siblings)
  5 siblings, 2 replies; 12+ messages in thread
From: Adrian Hunter @ 2022-05-20 13:24 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo; +Cc: Jiri Olsa, Namhyung Kim, linux-kernel

Add preadn() to provide pread() and readn() semantics.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/lib/perf/include/internal/lib.h |  2 ++
 tools/lib/perf/lib.c                  | 20 ++++++++++++++++++++
 2 files changed, 22 insertions(+)

diff --git a/tools/lib/perf/include/internal/lib.h b/tools/lib/perf/include/internal/lib.h
index 5175d491b2d4..85471a4b900f 100644
--- a/tools/lib/perf/include/internal/lib.h
+++ b/tools/lib/perf/include/internal/lib.h
@@ -9,4 +9,6 @@ extern unsigned int page_size;
 ssize_t readn(int fd, void *buf, size_t n);
 ssize_t writen(int fd, const void *buf, size_t n);
 
+ssize_t preadn(int fd, void *buf, size_t n, off_t offs);
+
 #endif /* __LIBPERF_INTERNAL_CPUMAP_H */
diff --git a/tools/lib/perf/lib.c b/tools/lib/perf/lib.c
index 18658931fc71..ecc8035a3ae3 100644
--- a/tools/lib/perf/lib.c
+++ b/tools/lib/perf/lib.c
@@ -38,6 +38,26 @@ ssize_t readn(int fd, void *buf, size_t n)
 	return ion(true, fd, buf, n);
 }
 
+ssize_t preadn(int fd, void *buf, size_t n, off_t offs)
+{
+	ssize_t ret;
+	off_t cur;
+
+	cur = lseek(fd, 0, SEEK_CUR);
+	if (cur < 0)
+		return -1;
+
+	if (lseek(fd, offs, SEEK_SET) < 0)
+		return -1;
+
+	ret = readn(fd, buf, n);
+
+	if (lseek(fd, cur, SEEK_CUR) < 0)
+		return -1;
+
+	return ret;
+}
+
 /*
  * Write exactly 'n' bytes or return an error.
  */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/5] perf inject: Keep some features sections from input file
  2022-05-20 13:23 [PATCH 0/5] perf inject: Minor improvements Adrian Hunter
  2022-05-20 13:24 ` [PATCH 1/5] perf header: Add ability to keep feature sections Adrian Hunter
  2022-05-20 13:24 ` [PATCH 2/5] libperf: Add preadn() Adrian Hunter
@ 2022-05-20 13:24 ` Adrian Hunter
  2022-05-23  8:14   ` Jiri Olsa
  2022-05-20 13:24 ` [PATCH 4/5] perf data: Add has_kcore_dir() Adrian Hunter
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 12+ messages in thread
From: Adrian Hunter @ 2022-05-20 13:24 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo; +Cc: Jiri Olsa, Namhyung Kim, linux-kernel

perf inject overwrites feature sections with information from the current
machine. It makes more sense to keep original information that describes
the machine or software when perf record was run.

Example: perf.data from "Desktop" injected on "nuc11"

 Before:

  $ perf script --header-only -i perf.data-from-desktop | head -15
  # ========
  # captured on    : Thu May 19 09:55:50 2022
  # header version : 1
  # data offset    : 1208
  # data size      : 837480
  # feat offset    : 838688
  # hostname : Desktop
  # os release : 5.13.0-41-generic
  # perf version : 5.18.rc5.gac837f7ca7ed
  # arch : x86_64
  # nrcpus online : 28
  # nrcpus avail : 28
  # cpudesc : Intel(R) Core(TM) i9-9940X CPU @ 3.30GHz
  # cpuid : GenuineIntel,6,85,4
  # total memory : 65548656 kB

  $ perf inject -i perf.data-from-desktop -o injected-perf.data

  $ perf script --header-only -i injected-perf.data | head -15
  # ========
  # captured on    : Fri May 20 15:06:55 2022
  # header version : 1
  # data offset    : 1208
  # data size      : 837480
  # feat offset    : 838688
  # hostname : nuc11
  # os release : 5.17.5-local
  # perf version : 5.18.rc5.g0f828fdeb9af
  # arch : x86_64
  # nrcpus online : 8
  # nrcpus avail : 8
  # cpudesc : 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
  # cpuid : GenuineIntel,6,140,1
  # total memory : 16012124 kB

 After:

  $ perf inject -i perf.data-from-desktop -o injected-perf.data

  $ perf script --header-only -i injected-perf.data | head -15
  # ========
  # captured on    : Fri May 20 15:08:54 2022
  # header version : 1
  # data offset    : 1208
  # data size      : 837480
  # feat offset    : 838688
  # hostname : Desktop
  # os release : 5.13.0-41-generic
  # perf version : 5.18.rc5.gac837f7ca7ed
  # arch : x86_64
  # nrcpus online : 28
  # nrcpus avail : 28
  # cpudesc : Intel(R) Core(TM) i9-9940X CPU @ 3.30GHz
  # cpuid : GenuineIntel,6,85,4
  # total memory : 65548656 kB

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/builtin-inject.c | 129 +++++++++++++++++++++++++++++++++++-
 tools/perf/util/header.c    |   8 +++
 tools/perf/util/header.h    |   5 ++
 3 files changed, 141 insertions(+), 1 deletion(-)

diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 5b50a4abf95f..71b6eafe4c19 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -27,6 +27,8 @@
 #include "util/namespaces.h"
 #include "util/util.h"
 
+#include <internal/lib.h>
+
 #include <linux/err.h>
 #include <subcmd/parse-options.h>
 #include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */
@@ -55,6 +57,7 @@ struct perf_inject {
 	struct list_head	samples;
 	struct itrace_synth_opts itrace_synth_opts;
 	char			event_copy[PERF_SAMPLE_MAX_SIZE];
+	struct perf_file_section secs[HEADER_FEAT_BITS];
 };
 
 struct event_entry {
@@ -763,6 +766,120 @@ static int parse_vm_time_correlation(const struct option *opt, const char *str,
 	return inject->itrace_synth_opts.vm_tm_corr_args ? 0 : -ENOMEM;
 }
 
+static int save_section_info_cb(struct perf_file_section *section,
+				struct perf_header *ph __maybe_unused,
+				int feat, int fd __maybe_unused, void *data)
+{
+	struct perf_inject *inject = data;
+
+	inject->secs[feat] = *section;
+	return 0;
+}
+
+static int save_section_info(struct perf_inject *inject)
+{
+	struct perf_header *header = &inject->session->header;
+	int fd = perf_data__fd(inject->session->data);
+
+	return perf_header__process_sections(header, fd, inject, save_section_info_cb);
+}
+
+static bool keep_feat(int feat)
+{
+	switch (feat) {
+	/* Keep original information that describes the machine or software */
+	case HEADER_TRACING_DATA:
+	case HEADER_HOSTNAME:
+	case HEADER_OSRELEASE:
+	case HEADER_VERSION:
+	case HEADER_ARCH:
+	case HEADER_NRCPUS:
+	case HEADER_CPUDESC:
+	case HEADER_CPUID:
+	case HEADER_TOTAL_MEM:
+	case HEADER_CPU_TOPOLOGY:
+	case HEADER_NUMA_TOPOLOGY:
+	case HEADER_PMU_MAPPINGS:
+	case HEADER_CACHE:
+	case HEADER_MEM_TOPOLOGY:
+	case HEADER_CLOCKID:
+	case HEADER_BPF_PROG_INFO:
+	case HEADER_BPF_BTF:
+	case HEADER_CPU_PMU_CAPS:
+	case HEADER_CLOCK_DATA:
+	case HEADER_HYBRID_TOPOLOGY:
+	case HEADER_HYBRID_CPU_PMU_CAPS:
+		return true;
+	/* Information that can be updated */
+	case HEADER_BUILD_ID:
+	case HEADER_CMDLINE:
+	case HEADER_EVENT_DESC:
+	case HEADER_BRANCH_STACK:
+	case HEADER_GROUP_DESC:
+	case HEADER_AUXTRACE:
+	case HEADER_STAT:
+	case HEADER_SAMPLE_TIME:
+	case HEADER_DIR_FORMAT:
+	case HEADER_COMPRESSED:
+	default:
+		return false;
+	};
+}
+
+static int read_file(int fd, u64 offs, void *buf, size_t sz)
+{
+	ssize_t ret = preadn(fd, buf, sz, offs);
+
+	if (ret < 0)
+		return -errno;
+	if ((size_t)ret != sz)
+		return -EINVAL;
+	return 0;
+}
+
+static int feat_copy(struct perf_inject *inject, int feat, struct feat_writer *fw)
+{
+	int fd = perf_data__fd(inject->session->data);
+	u64 offs = inject->secs[feat].offset;
+	size_t sz = inject->secs[feat].size;
+	void *buf = malloc(sz);
+	int ret;
+
+	if (!buf)
+		return -ENOMEM;
+
+	ret = read_file(fd, offs, buf, sz);
+	if (ret)
+		goto out_free;
+
+	ret = fw->write(fw, buf, sz);
+out_free:
+	free(buf);
+	return ret;
+}
+
+struct inject_fc {
+	struct feat_copier fc;
+	struct perf_inject *inject;
+};
+
+static int feat_copy_cb(struct feat_copier *fc, int feat, struct feat_writer *fw)
+{
+	struct inject_fc *inj_fc = container_of(fc, struct inject_fc, fc);
+	struct perf_inject *inject = inj_fc->inject;
+	int ret;
+
+	if (!inject->secs[feat].offset ||
+	    !keep_feat(feat))
+		return 0;
+
+	ret = feat_copy(inject, feat, fw);
+	if (ret < 0)
+		return ret;
+
+	return 1; /* Feature section copied */
+}
+
 static int output_fd(struct perf_inject *inject)
 {
 	return inject->in_place_update ? -1 : perf_data__fd(&inject->output);
@@ -848,6 +965,11 @@ static int __cmd_inject(struct perf_inject *inject)
 		return ret;
 
 	if (!inject->is_pipe && !inject->in_place_update) {
+		struct inject_fc inj_fc = {
+			.fc.copy = feat_copy_cb,
+			.inject = inject,
+		};
+
 		if (inject->build_ids)
 			perf_header__set_feat(&session->header,
 					      HEADER_BUILD_ID);
@@ -872,7 +994,7 @@ static int __cmd_inject(struct perf_inject *inject)
 		}
 		session->header.data_offset = output_data_offset;
 		session->header.data_size = inject->bytes_written;
-		perf_session__write_header(session, session->evlist, fd, true);
+		perf_session__inject_header(session, session->evlist, fd, &inj_fc.fc);
 	}
 
 	return ret;
@@ -1037,6 +1159,11 @@ int cmd_inject(int argc, const char **argv)
 	if (zstd_init(&(inject.session->zstd_data), 0) < 0)
 		pr_warning("Decompression initialization failed.\n");
 
+	/* Save original section info before feature bits change */
+	ret = save_section_info(&inject);
+	if (ret)
+		goto out_delete;
+
 	if (!data.is_pipe && inject.output.is_pipe) {
 		ret = perf_header__write_pipe(perf_data__fd(&inject.output));
 		if (ret < 0) {
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index b0c57a130d1e..53332da100e8 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -3686,6 +3686,14 @@ int perf_session__write_header(struct perf_session *session,
 	return perf_session__do_write_header(session, evlist, fd, at_exit, NULL);
 }
 
+int perf_session__inject_header(struct perf_session *session,
+				struct evlist *evlist,
+				int fd,
+				struct feat_copier *fc)
+{
+	return perf_session__do_write_header(session, evlist, fd, true, fc);
+}
+
 static int perf_header__getbuffer64(struct perf_header *header,
 				    int fd, void *buf, size_t size)
 {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index e76ab02d5541..08563c1f1bff 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -131,6 +131,11 @@ struct feat_copier {
 	int (*copy)(struct feat_copier *fc, int feat, struct feat_writer *fw);
 };
 
+int perf_session__inject_header(struct perf_session *session,
+				struct evlist *evlist,
+				int fd,
+				struct feat_copier *fc);
+
 void perf_header__set_feat(struct perf_header *header, int feat);
 void perf_header__clear_feat(struct perf_header *header, int feat);
 bool perf_header__has_feat(const struct perf_header *header, int feat);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 4/5] perf data: Add has_kcore_dir()
  2022-05-20 13:23 [PATCH 0/5] perf inject: Minor improvements Adrian Hunter
                   ` (2 preceding siblings ...)
  2022-05-20 13:24 ` [PATCH 3/5] perf inject: Keep some features sections from input file Adrian Hunter
@ 2022-05-20 13:24 ` Adrian Hunter
  2022-05-20 13:24 ` [PATCH 5/5] perf inject: Keep a copy of kcore_dir Adrian Hunter
  2022-05-23  8:16 ` [PATCH 0/5] perf inject: Minor improvements Jiri Olsa
  5 siblings, 0 replies; 12+ messages in thread
From: Adrian Hunter @ 2022-05-20 13:24 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo; +Cc: Jiri Olsa, Namhyung Kim, linux-kernel

Add a helper function has_kcore_dir(), so that perf inject can determine if
it needs to keep the kcore_dir.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/util/data.c | 14 ++++++++++++++
 tools/perf/util/data.h |  1 +
 2 files changed, 15 insertions(+)

diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index a5ace2bbc28d..caabeac24c69 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -479,6 +479,20 @@ int perf_data__make_kcore_dir(struct perf_data *data, char *buf, size_t buf_sz)
 	return mkdir(buf, S_IRWXU);
 }
 
+bool has_kcore_dir(const char *path)
+{
+	char *kcore_dir;
+	int ret;
+
+	if (asprintf(&kcore_dir, "%s/kcore_dir", path) < 0)
+		return false;
+
+	ret = access(kcore_dir, F_OK);
+
+	free(kcore_dir);
+	return !ret;
+}
+
 char *perf_data__kallsyms_name(struct perf_data *data)
 {
 	char *kallsyms_name;
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
index 1402d9657ef2..7de53d6e2d7f 100644
--- a/tools/perf/util/data.h
+++ b/tools/perf/util/data.h
@@ -99,6 +99,7 @@ void perf_data__close_dir(struct perf_data *data);
 int perf_data__update_dir(struct perf_data *data);
 unsigned long perf_data__size(struct perf_data *data);
 int perf_data__make_kcore_dir(struct perf_data *data, char *buf, size_t buf_sz);
+bool has_kcore_dir(const char *path);
 char *perf_data__kallsyms_name(struct perf_data *data);
 bool is_perf_data(const char *path);
 #endif /* __PERF_DATA_H */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 5/5] perf inject: Keep a copy of kcore_dir
  2022-05-20 13:23 [PATCH 0/5] perf inject: Minor improvements Adrian Hunter
                   ` (3 preceding siblings ...)
  2022-05-20 13:24 ` [PATCH 4/5] perf data: Add has_kcore_dir() Adrian Hunter
@ 2022-05-20 13:24 ` Adrian Hunter
  2022-05-23  8:16 ` [PATCH 0/5] perf inject: Minor improvements Jiri Olsa
  5 siblings, 0 replies; 12+ messages in thread
From: Adrian Hunter @ 2022-05-20 13:24 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo; +Cc: Jiri Olsa, Namhyung Kim, linux-kernel

If the input perf.data has a kcore_dir, copy it into the output, since
at least the kallsyms in the kcore_dir will be useful to the output.

Example:

 Before:

  $ ls -lR perf.data-from-desktop
  perf.data-from-desktop:
  total 916
  -rw------- 1 user user 931756 May 19 09:55 data
  drwx------ 2 user user   4096 May 19 09:55 kcore_dir

  perf.data-from-desktop/kcore_dir:
  total 42952
  -r-------- 1 user user  7582467 May 19 09:55 kallsyms
  -r-------- 1 user user 36388864 May 19 09:55 kcore
  -r-------- 1 user user     4828 May 19 09:55 modules

  $ perf inject -i perf.data-from-desktop -o injected-perf.data

  $ ls -lR injected-perf.data
  -rw------- 1 user user 931320 May 20 15:08 injected-perf.data

 After:

  $ perf inject -i perf.data-from-desktop -o injected-perf.data

  $ ls -lR injected-perf.data
  injected-perf.data:
  total 916
  -rw------- 1 user user 931320 May 20 15:21 data
  drwx------ 2 user user   4096 May 20 15:21 kcore_dir

  injected-perf.data/kcore_dir:
  total 42952
  -r-------- 1 user user  7582467 May 20 15:21 kallsyms
  -r-------- 1 user user 36388864 May 20 15:21 kcore
  -r-------- 1 user user     4828 May 20 15:21 modules

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/builtin-inject.c | 33 ++++++++++++++++++++++++++++++---
 1 file changed, 30 insertions(+), 3 deletions(-)

diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 71b6eafe4c19..a75bf11585b5 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -50,6 +50,7 @@ struct perf_inject {
 	bool			in_place_update;
 	bool			in_place_update_dry_run;
 	bool			is_pipe;
+	bool			copy_kcore_dir;
 	const char		*input_name;
 	struct perf_data	output;
 	u64			bytes_written;
@@ -880,6 +881,19 @@ static int feat_copy_cb(struct feat_copier *fc, int feat, struct feat_writer *fw
 	return 1; /* Feature section copied */
 }
 
+static int copy_kcore_dir(struct perf_inject *inject)
+{
+	char *cmd;
+	int ret;
+
+	ret = asprintf(&cmd, "cp -r -n %s/kcore_dir* %s >/dev/null 2>&1",
+		       inject->input_name, inject->output.path);
+	if (ret < 0)
+		return ret;
+	pr_debug("%s\n", cmd);
+	return system(cmd);
+}
+
 static int output_fd(struct perf_inject *inject)
 {
 	return inject->in_place_update ? -1 : perf_data__fd(&inject->output);
@@ -995,6 +1009,12 @@ static int __cmd_inject(struct perf_inject *inject)
 		session->header.data_offset = output_data_offset;
 		session->header.data_size = inject->bytes_written;
 		perf_session__inject_header(session, session->evlist, fd, &inj_fc.fc);
+
+		if (inject->copy_kcore_dir) {
+			ret = copy_kcore_dir(inject);
+			if (ret)
+				return ret;
+		}
 	}
 
 	return ret;
@@ -1131,9 +1151,16 @@ int cmd_inject(int argc, const char **argv)
 		}
 		if (!inject.in_place_update_dry_run)
 			data.in_place_update = true;
-	} else if (perf_data__open(&inject.output)) {
-		perror("failed to create output file");
-		return -1;
+	} else {
+		if (strcmp(inject.output.path, "-") && !inject.strip &&
+		    has_kcore_dir(inject.input_name)) {
+			inject.output.is_dir = true;
+			inject.copy_kcore_dir = true;
+		}
+		if (perf_data__open(&inject.output)) {
+			perror("failed to create output file");
+			return -1;
+		}
 	}
 
 	data.path = inject.input_name;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* RE: [PATCH 2/5] libperf: Add preadn()
  2022-05-20 13:24 ` [PATCH 2/5] libperf: Add preadn() Adrian Hunter
@ 2022-05-20 13:55   ` David Laight
  2022-05-20 15:56   ` [PATCH V2 " Adrian Hunter
  1 sibling, 0 replies; 12+ messages in thread
From: David Laight @ 2022-05-20 13:55 UTC (permalink / raw)
  To: 'Adrian Hunter', Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Namhyung Kim, linux-kernel

From: Adrian Hunter
> Sent: 20 May 2022 14:24
> 
> Add preadn() to provide pread() and readn() semantics.
> 
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
>  tools/lib/perf/include/internal/lib.h |  2 ++
>  tools/lib/perf/lib.c                  | 20 ++++++++++++++++++++
>  2 files changed, 22 insertions(+)
> 
> diff --git a/tools/lib/perf/include/internal/lib.h b/tools/lib/perf/include/internal/lib.h
> index 5175d491b2d4..85471a4b900f 100644
> --- a/tools/lib/perf/include/internal/lib.h
> +++ b/tools/lib/perf/include/internal/lib.h
> @@ -9,4 +9,6 @@ extern unsigned int page_size;
>  ssize_t readn(int fd, void *buf, size_t n);
>  ssize_t writen(int fd, const void *buf, size_t n);
> 
> +ssize_t preadn(int fd, void *buf, size_t n, off_t offs);
> +
>  #endif /* __LIBPERF_INTERNAL_CPUMAP_H */
> diff --git a/tools/lib/perf/lib.c b/tools/lib/perf/lib.c
> index 18658931fc71..ecc8035a3ae3 100644
> --- a/tools/lib/perf/lib.c
> +++ b/tools/lib/perf/lib.c
> @@ -38,6 +38,26 @@ ssize_t readn(int fd, void *buf, size_t n)
>  	return ion(true, fd, buf, n);
>  }
> 
> +ssize_t preadn(int fd, void *buf, size_t n, off_t offs)
> +{
> +	ssize_t ret;
> +	off_t cur;
> +
> +	cur = lseek(fd, 0, SEEK_CUR);
> +	if (cur < 0)
> +		return -1;
> +
> +	if (lseek(fd, offs, SEEK_SET) < 0)
> +		return -1;
> +
> +	ret = readn(fd, buf, n);
> +
> +	if (lseek(fd, cur, SEEK_CUR) < 0)
> +		return -1;
> +
> +	return ret;
> +}

Please don't ever write that code, not ever.
It isn't an implementation of pread().

Oh, and shoot whoever put in into (IIRC) uclibc.

pread() needs to use the syscall, you cannot implement
it in userspace.

It is better to have the function missing that that version.

There is a similar problem with clock_nanosleep() and TIMER_ABSTIME
in glibc - completely broken emulation.

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH V2 2/5] libperf: Add preadn()
  2022-05-20 13:24 ` [PATCH 2/5] libperf: Add preadn() Adrian Hunter
  2022-05-20 13:55   ` David Laight
@ 2022-05-20 15:56   ` Adrian Hunter
  1 sibling, 0 replies; 12+ messages in thread
From: Adrian Hunter @ 2022-05-20 15:56 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo; +Cc: Jiri Olsa, Namhyung Kim, linux-kernel

Add preadn() to provide pread() and readn() semantics.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---


Changes in V2:

	Make preadn() thread-safe in case someone infers
	from the name that it is.


 tools/lib/perf/include/internal/lib.h |  2 ++
 tools/lib/perf/lib.c                  | 20 ++++++++++++++++++++
 2 files changed, 22 insertions(+)

diff --git a/tools/lib/perf/include/internal/lib.h b/tools/lib/perf/include/internal/lib.h
index 5175d491b2d49..85471a4b900f7 100644
--- a/tools/lib/perf/include/internal/lib.h
+++ b/tools/lib/perf/include/internal/lib.h
@@ -9,4 +9,6 @@ extern unsigned int page_size;
 ssize_t readn(int fd, void *buf, size_t n);
 ssize_t writen(int fd, const void *buf, size_t n);
 
+ssize_t preadn(int fd, void *buf, size_t n, off_t offs);
+
 #endif /* __LIBPERF_INTERNAL_CPUMAP_H */
diff --git a/tools/lib/perf/lib.c b/tools/lib/perf/lib.c
index 18658931fc714..696fb0ea67c6e 100644
--- a/tools/lib/perf/lib.c
+++ b/tools/lib/perf/lib.c
@@ -38,6 +38,26 @@ ssize_t readn(int fd, void *buf, size_t n)
 	return ion(true, fd, buf, n);
 }
 
+ssize_t preadn(int fd, void *buf, size_t n, off_t offs)
+{
+	size_t left = n;
+
+	while (left) {
+		ssize_t ret = pread(fd, buf, left, offs);
+
+		if (ret < 0 && errno == EINTR)
+			continue;
+		if (ret <= 0)
+			return ret;
+
+		left -= ret;
+		buf  += ret;
+		offs += ret;
+	}
+
+	return n;
+}
+
 /*
  * Write exactly 'n' bytes or return an error.
  */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 3/5] perf inject: Keep some features sections from input file
  2022-05-20 13:24 ` [PATCH 3/5] perf inject: Keep some features sections from input file Adrian Hunter
@ 2022-05-23  8:14   ` Jiri Olsa
  2022-05-23  9:23     ` Adrian Hunter
  0 siblings, 1 reply; 12+ messages in thread
From: Jiri Olsa @ 2022-05-23  8:14 UTC (permalink / raw)
  To: Adrian Hunter; +Cc: Arnaldo Carvalho de Melo, Namhyung Kim, linux-kernel

On Fri, May 20, 2022 at 04:24:02PM +0300, Adrian Hunter wrote:
> perf inject overwrites feature sections with information from the current
> machine. It makes more sense to keep original information that describes
> the machine or software when perf record was run.
> 
> Example: perf.data from "Desktop" injected on "nuc11"
> 
>  Before:
> 
>   $ perf script --header-only -i perf.data-from-desktop | head -15
>   # ========
>   # captured on    : Thu May 19 09:55:50 2022
>   # header version : 1
>   # data offset    : 1208
>   # data size      : 837480
>   # feat offset    : 838688
>   # hostname : Desktop
>   # os release : 5.13.0-41-generic
>   # perf version : 5.18.rc5.gac837f7ca7ed
>   # arch : x86_64
>   # nrcpus online : 28
>   # nrcpus avail : 28
>   # cpudesc : Intel(R) Core(TM) i9-9940X CPU @ 3.30GHz
>   # cpuid : GenuineIntel,6,85,4
>   # total memory : 65548656 kB
> 
>   $ perf inject -i perf.data-from-desktop -o injected-perf.data
> 
>   $ perf script --header-only -i injected-perf.data | head -15
>   # ========
>   # captured on    : Fri May 20 15:06:55 2022
>   # header version : 1
>   # data offset    : 1208
>   # data size      : 837480
>   # feat offset    : 838688
>   # hostname : nuc11
>   # os release : 5.17.5-local
>   # perf version : 5.18.rc5.g0f828fdeb9af
>   # arch : x86_64
>   # nrcpus online : 8
>   # nrcpus avail : 8
>   # cpudesc : 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
>   # cpuid : GenuineIntel,6,140,1
>   # total memory : 16012124 kB
> 
>  After:
> 
>   $ perf inject -i perf.data-from-desktop -o injected-perf.data
> 
>   $ perf script --header-only -i injected-perf.data | head -15
>   # ========
>   # captured on    : Fri May 20 15:08:54 2022

too bad date is not in separate feature right?

jirka

>   # header version : 1
>   # data offset    : 1208
>   # data size      : 837480
>   # feat offset    : 838688
>   # hostname : Desktop
>   # os release : 5.13.0-41-generic
>   # perf version : 5.18.rc5.gac837f7ca7ed
>   # arch : x86_64
>   # nrcpus online : 28
>   # nrcpus avail : 28
>   # cpudesc : Intel(R) Core(TM) i9-9940X CPU @ 3.30GHz
>   # cpuid : GenuineIntel,6,85,4
>   # total memory : 65548656 kB
> 
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
>  tools/perf/builtin-inject.c | 129 +++++++++++++++++++++++++++++++++++-
>  tools/perf/util/header.c    |   8 +++
>  tools/perf/util/header.h    |   5 ++
>  3 files changed, 141 insertions(+), 1 deletion(-)
> 
> diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
> index 5b50a4abf95f..71b6eafe4c19 100644
> --- a/tools/perf/builtin-inject.c
> +++ b/tools/perf/builtin-inject.c
> @@ -27,6 +27,8 @@
>  #include "util/namespaces.h"
>  #include "util/util.h"
>  
> +#include <internal/lib.h>
> +
>  #include <linux/err.h>
>  #include <subcmd/parse-options.h>
>  #include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */
> @@ -55,6 +57,7 @@ struct perf_inject {
>  	struct list_head	samples;
>  	struct itrace_synth_opts itrace_synth_opts;
>  	char			event_copy[PERF_SAMPLE_MAX_SIZE];
> +	struct perf_file_section secs[HEADER_FEAT_BITS];
>  };
>  
>  struct event_entry {
> @@ -763,6 +766,120 @@ static int parse_vm_time_correlation(const struct option *opt, const char *str,
>  	return inject->itrace_synth_opts.vm_tm_corr_args ? 0 : -ENOMEM;
>  }
>  
> +static int save_section_info_cb(struct perf_file_section *section,
> +				struct perf_header *ph __maybe_unused,
> +				int feat, int fd __maybe_unused, void *data)
> +{
> +	struct perf_inject *inject = data;
> +
> +	inject->secs[feat] = *section;
> +	return 0;
> +}
> +
> +static int save_section_info(struct perf_inject *inject)
> +{
> +	struct perf_header *header = &inject->session->header;
> +	int fd = perf_data__fd(inject->session->data);
> +
> +	return perf_header__process_sections(header, fd, inject, save_section_info_cb);
> +}
> +
> +static bool keep_feat(int feat)
> +{
> +	switch (feat) {
> +	/* Keep original information that describes the machine or software */
> +	case HEADER_TRACING_DATA:
> +	case HEADER_HOSTNAME:
> +	case HEADER_OSRELEASE:
> +	case HEADER_VERSION:
> +	case HEADER_ARCH:
> +	case HEADER_NRCPUS:
> +	case HEADER_CPUDESC:
> +	case HEADER_CPUID:
> +	case HEADER_TOTAL_MEM:
> +	case HEADER_CPU_TOPOLOGY:
> +	case HEADER_NUMA_TOPOLOGY:
> +	case HEADER_PMU_MAPPINGS:
> +	case HEADER_CACHE:
> +	case HEADER_MEM_TOPOLOGY:
> +	case HEADER_CLOCKID:
> +	case HEADER_BPF_PROG_INFO:
> +	case HEADER_BPF_BTF:
> +	case HEADER_CPU_PMU_CAPS:
> +	case HEADER_CLOCK_DATA:
> +	case HEADER_HYBRID_TOPOLOGY:
> +	case HEADER_HYBRID_CPU_PMU_CAPS:
> +		return true;
> +	/* Information that can be updated */
> +	case HEADER_BUILD_ID:
> +	case HEADER_CMDLINE:
> +	case HEADER_EVENT_DESC:
> +	case HEADER_BRANCH_STACK:
> +	case HEADER_GROUP_DESC:
> +	case HEADER_AUXTRACE:
> +	case HEADER_STAT:
> +	case HEADER_SAMPLE_TIME:
> +	case HEADER_DIR_FORMAT:
> +	case HEADER_COMPRESSED:
> +	default:
> +		return false;
> +	};
> +}
> +
> +static int read_file(int fd, u64 offs, void *buf, size_t sz)
> +{
> +	ssize_t ret = preadn(fd, buf, sz, offs);
> +
> +	if (ret < 0)
> +		return -errno;
> +	if ((size_t)ret != sz)
> +		return -EINVAL;
> +	return 0;
> +}
> +
> +static int feat_copy(struct perf_inject *inject, int feat, struct feat_writer *fw)
> +{
> +	int fd = perf_data__fd(inject->session->data);
> +	u64 offs = inject->secs[feat].offset;
> +	size_t sz = inject->secs[feat].size;
> +	void *buf = malloc(sz);
> +	int ret;
> +
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	ret = read_file(fd, offs, buf, sz);
> +	if (ret)
> +		goto out_free;
> +
> +	ret = fw->write(fw, buf, sz);
> +out_free:
> +	free(buf);
> +	return ret;
> +}
> +
> +struct inject_fc {
> +	struct feat_copier fc;
> +	struct perf_inject *inject;
> +};
> +
> +static int feat_copy_cb(struct feat_copier *fc, int feat, struct feat_writer *fw)
> +{
> +	struct inject_fc *inj_fc = container_of(fc, struct inject_fc, fc);
> +	struct perf_inject *inject = inj_fc->inject;
> +	int ret;
> +
> +	if (!inject->secs[feat].offset ||
> +	    !keep_feat(feat))
> +		return 0;
> +
> +	ret = feat_copy(inject, feat, fw);
> +	if (ret < 0)
> +		return ret;
> +
> +	return 1; /* Feature section copied */
> +}
> +
>  static int output_fd(struct perf_inject *inject)
>  {
>  	return inject->in_place_update ? -1 : perf_data__fd(&inject->output);
> @@ -848,6 +965,11 @@ static int __cmd_inject(struct perf_inject *inject)
>  		return ret;
>  
>  	if (!inject->is_pipe && !inject->in_place_update) {
> +		struct inject_fc inj_fc = {
> +			.fc.copy = feat_copy_cb,
> +			.inject = inject,
> +		};
> +
>  		if (inject->build_ids)
>  			perf_header__set_feat(&session->header,
>  					      HEADER_BUILD_ID);
> @@ -872,7 +994,7 @@ static int __cmd_inject(struct perf_inject *inject)
>  		}
>  		session->header.data_offset = output_data_offset;
>  		session->header.data_size = inject->bytes_written;
> -		perf_session__write_header(session, session->evlist, fd, true);
> +		perf_session__inject_header(session, session->evlist, fd, &inj_fc.fc);
>  	}
>  
>  	return ret;
> @@ -1037,6 +1159,11 @@ int cmd_inject(int argc, const char **argv)
>  	if (zstd_init(&(inject.session->zstd_data), 0) < 0)
>  		pr_warning("Decompression initialization failed.\n");
>  
> +	/* Save original section info before feature bits change */
> +	ret = save_section_info(&inject);
> +	if (ret)
> +		goto out_delete;
> +
>  	if (!data.is_pipe && inject.output.is_pipe) {
>  		ret = perf_header__write_pipe(perf_data__fd(&inject.output));
>  		if (ret < 0) {
> diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
> index b0c57a130d1e..53332da100e8 100644
> --- a/tools/perf/util/header.c
> +++ b/tools/perf/util/header.c
> @@ -3686,6 +3686,14 @@ int perf_session__write_header(struct perf_session *session,
>  	return perf_session__do_write_header(session, evlist, fd, at_exit, NULL);
>  }
>  
> +int perf_session__inject_header(struct perf_session *session,
> +				struct evlist *evlist,
> +				int fd,
> +				struct feat_copier *fc)
> +{
> +	return perf_session__do_write_header(session, evlist, fd, true, fc);
> +}
> +
>  static int perf_header__getbuffer64(struct perf_header *header,
>  				    int fd, void *buf, size_t size)
>  {
> diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
> index e76ab02d5541..08563c1f1bff 100644
> --- a/tools/perf/util/header.h
> +++ b/tools/perf/util/header.h
> @@ -131,6 +131,11 @@ struct feat_copier {
>  	int (*copy)(struct feat_copier *fc, int feat, struct feat_writer *fw);
>  };
>  
> +int perf_session__inject_header(struct perf_session *session,
> +				struct evlist *evlist,
> +				int fd,
> +				struct feat_copier *fc);
> +
>  void perf_header__set_feat(struct perf_header *header, int feat);
>  void perf_header__clear_feat(struct perf_header *header, int feat);
>  bool perf_header__has_feat(const struct perf_header *header, int feat);
> -- 
> 2.25.1
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 0/5] perf inject: Minor improvements
  2022-05-20 13:23 [PATCH 0/5] perf inject: Minor improvements Adrian Hunter
                   ` (4 preceding siblings ...)
  2022-05-20 13:24 ` [PATCH 5/5] perf inject: Keep a copy of kcore_dir Adrian Hunter
@ 2022-05-23  8:16 ` Jiri Olsa
  2022-05-23 13:12   ` Arnaldo Carvalho de Melo
  5 siblings, 1 reply; 12+ messages in thread
From: Jiri Olsa @ 2022-05-23  8:16 UTC (permalink / raw)
  To: Adrian Hunter; +Cc: Arnaldo Carvalho de Melo, Namhyung Kim, linux-kernel

On Fri, May 20, 2022 at 04:23:59PM +0300, Adrian Hunter wrote:
> Hi
> 
> Here are patches for 2 minor improvements for perf inject:
> 1. Keep some features sections from input file
> 2. Keep a copy of kcore_dir
> 
> 
> Adrian Hunter (5):
>       perf header: Add ability to keep feature sections
>       libperf: Add preadn()
>       perf inject: Keep some features sections from input file
>       perf data: Add has_kcore_dir()
>       perf inject: Keep a copy of kcore_dir

LGTM

Acked-by: Jiri Olsa <jolsa@kernel.org>

thanks,
jirka

> 
>  tools/lib/perf/include/internal/lib.h |   2 +
>  tools/lib/perf/lib.c                  |  20 +++++
>  tools/perf/builtin-inject.c           | 162 +++++++++++++++++++++++++++++++++-
>  tools/perf/util/data.c                |  14 +++
>  tools/perf/util/data.h                |   1 +
>  tools/perf/util/header.c              |  62 +++++++++++--
>  tools/perf/util/header.h              |  15 ++++
>  7 files changed, 264 insertions(+), 12 deletions(-)
> 
> 
> Regards
> Adrian

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 3/5] perf inject: Keep some features sections from input file
  2022-05-23  8:14   ` Jiri Olsa
@ 2022-05-23  9:23     ` Adrian Hunter
  0 siblings, 0 replies; 12+ messages in thread
From: Adrian Hunter @ 2022-05-23  9:23 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: Arnaldo Carvalho de Melo, Namhyung Kim, linux-kernel

On 23/05/22 11:14, Jiri Olsa wrote:
> On Fri, May 20, 2022 at 04:24:02PM +0300, Adrian Hunter wrote:
>> perf inject overwrites feature sections with information from the current
>> machine. It makes more sense to keep original information that describes
>> the machine or software when perf record was run.
>>
>> Example: perf.data from "Desktop" injected on "nuc11"
>>
>>  Before:
>>
>>   $ perf script --header-only -i perf.data-from-desktop | head -15
>>   # ========
>>   # captured on    : Thu May 19 09:55:50 2022
>>   # header version : 1
>>   # data offset    : 1208
>>   # data size      : 837480
>>   # feat offset    : 838688
>>   # hostname : Desktop
>>   # os release : 5.13.0-41-generic
>>   # perf version : 5.18.rc5.gac837f7ca7ed
>>   # arch : x86_64
>>   # nrcpus online : 28
>>   # nrcpus avail : 28
>>   # cpudesc : Intel(R) Core(TM) i9-9940X CPU @ 3.30GHz
>>   # cpuid : GenuineIntel,6,85,4
>>   # total memory : 65548656 kB
>>
>>   $ perf inject -i perf.data-from-desktop -o injected-perf.data
>>
>>   $ perf script --header-only -i injected-perf.data | head -15
>>   # ========
>>   # captured on    : Fri May 20 15:06:55 2022
>>   # header version : 1
>>   # data offset    : 1208
>>   # data size      : 837480
>>   # feat offset    : 838688
>>   # hostname : nuc11
>>   # os release : 5.17.5-local
>>   # perf version : 5.18.rc5.g0f828fdeb9af
>>   # arch : x86_64
>>   # nrcpus online : 8
>>   # nrcpus avail : 8
>>   # cpudesc : 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
>>   # cpuid : GenuineIntel,6,140,1
>>   # total memory : 16012124 kB
>>
>>  After:
>>
>>   $ perf inject -i perf.data-from-desktop -o injected-perf.data
>>
>>   $ perf script --header-only -i injected-perf.data | head -15
>>   # ========
>>   # captured on    : Fri May 20 15:08:54 2022
> 
> too bad date is not in separate feature right?

True.  I'd also like to have both the original and new cmdline.

> 
> jirka
> 
>>   # header version : 1
>>   # data offset    : 1208
>>   # data size      : 837480
>>   # feat offset    : 838688
>>   # hostname : Desktop
>>   # os release : 5.13.0-41-generic
>>   # perf version : 5.18.rc5.gac837f7ca7ed
>>   # arch : x86_64
>>   # nrcpus online : 28
>>   # nrcpus avail : 28
>>   # cpudesc : Intel(R) Core(TM) i9-9940X CPU @ 3.30GHz
>>   # cpuid : GenuineIntel,6,85,4
>>   # total memory : 65548656 kB
>>
>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
>> ---
>>  tools/perf/builtin-inject.c | 129 +++++++++++++++++++++++++++++++++++-
>>  tools/perf/util/header.c    |   8 +++
>>  tools/perf/util/header.h    |   5 ++
>>  3 files changed, 141 insertions(+), 1 deletion(-)
>>
>> diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
>> index 5b50a4abf95f..71b6eafe4c19 100644
>> --- a/tools/perf/builtin-inject.c
>> +++ b/tools/perf/builtin-inject.c
>> @@ -27,6 +27,8 @@
>>  #include "util/namespaces.h"
>>  #include "util/util.h"
>>  
>> +#include <internal/lib.h>
>> +
>>  #include <linux/err.h>
>>  #include <subcmd/parse-options.h>
>>  #include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */
>> @@ -55,6 +57,7 @@ struct perf_inject {
>>  	struct list_head	samples;
>>  	struct itrace_synth_opts itrace_synth_opts;
>>  	char			event_copy[PERF_SAMPLE_MAX_SIZE];
>> +	struct perf_file_section secs[HEADER_FEAT_BITS];
>>  };
>>  
>>  struct event_entry {
>> @@ -763,6 +766,120 @@ static int parse_vm_time_correlation(const struct option *opt, const char *str,
>>  	return inject->itrace_synth_opts.vm_tm_corr_args ? 0 : -ENOMEM;
>>  }
>>  
>> +static int save_section_info_cb(struct perf_file_section *section,
>> +				struct perf_header *ph __maybe_unused,
>> +				int feat, int fd __maybe_unused, void *data)
>> +{
>> +	struct perf_inject *inject = data;
>> +
>> +	inject->secs[feat] = *section;
>> +	return 0;
>> +}
>> +
>> +static int save_section_info(struct perf_inject *inject)
>> +{
>> +	struct perf_header *header = &inject->session->header;
>> +	int fd = perf_data__fd(inject->session->data);
>> +
>> +	return perf_header__process_sections(header, fd, inject, save_section_info_cb);
>> +}
>> +
>> +static bool keep_feat(int feat)
>> +{
>> +	switch (feat) {
>> +	/* Keep original information that describes the machine or software */
>> +	case HEADER_TRACING_DATA:
>> +	case HEADER_HOSTNAME:
>> +	case HEADER_OSRELEASE:
>> +	case HEADER_VERSION:
>> +	case HEADER_ARCH:
>> +	case HEADER_NRCPUS:
>> +	case HEADER_CPUDESC:
>> +	case HEADER_CPUID:
>> +	case HEADER_TOTAL_MEM:
>> +	case HEADER_CPU_TOPOLOGY:
>> +	case HEADER_NUMA_TOPOLOGY:
>> +	case HEADER_PMU_MAPPINGS:
>> +	case HEADER_CACHE:
>> +	case HEADER_MEM_TOPOLOGY:
>> +	case HEADER_CLOCKID:
>> +	case HEADER_BPF_PROG_INFO:
>> +	case HEADER_BPF_BTF:
>> +	case HEADER_CPU_PMU_CAPS:
>> +	case HEADER_CLOCK_DATA:
>> +	case HEADER_HYBRID_TOPOLOGY:
>> +	case HEADER_HYBRID_CPU_PMU_CAPS:
>> +		return true;
>> +	/* Information that can be updated */
>> +	case HEADER_BUILD_ID:
>> +	case HEADER_CMDLINE:
>> +	case HEADER_EVENT_DESC:
>> +	case HEADER_BRANCH_STACK:
>> +	case HEADER_GROUP_DESC:
>> +	case HEADER_AUXTRACE:
>> +	case HEADER_STAT:
>> +	case HEADER_SAMPLE_TIME:
>> +	case HEADER_DIR_FORMAT:
>> +	case HEADER_COMPRESSED:
>> +	default:
>> +		return false;
>> +	};
>> +}
>> +
>> +static int read_file(int fd, u64 offs, void *buf, size_t sz)
>> +{
>> +	ssize_t ret = preadn(fd, buf, sz, offs);
>> +
>> +	if (ret < 0)
>> +		return -errno;
>> +	if ((size_t)ret != sz)
>> +		return -EINVAL;
>> +	return 0;
>> +}
>> +
>> +static int feat_copy(struct perf_inject *inject, int feat, struct feat_writer *fw)
>> +{
>> +	int fd = perf_data__fd(inject->session->data);
>> +	u64 offs = inject->secs[feat].offset;
>> +	size_t sz = inject->secs[feat].size;
>> +	void *buf = malloc(sz);
>> +	int ret;
>> +
>> +	if (!buf)
>> +		return -ENOMEM;
>> +
>> +	ret = read_file(fd, offs, buf, sz);
>> +	if (ret)
>> +		goto out_free;
>> +
>> +	ret = fw->write(fw, buf, sz);
>> +out_free:
>> +	free(buf);
>> +	return ret;
>> +}
>> +
>> +struct inject_fc {
>> +	struct feat_copier fc;
>> +	struct perf_inject *inject;
>> +};
>> +
>> +static int feat_copy_cb(struct feat_copier *fc, int feat, struct feat_writer *fw)
>> +{
>> +	struct inject_fc *inj_fc = container_of(fc, struct inject_fc, fc);
>> +	struct perf_inject *inject = inj_fc->inject;
>> +	int ret;
>> +
>> +	if (!inject->secs[feat].offset ||
>> +	    !keep_feat(feat))
>> +		return 0;
>> +
>> +	ret = feat_copy(inject, feat, fw);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	return 1; /* Feature section copied */
>> +}
>> +
>>  static int output_fd(struct perf_inject *inject)
>>  {
>>  	return inject->in_place_update ? -1 : perf_data__fd(&inject->output);
>> @@ -848,6 +965,11 @@ static int __cmd_inject(struct perf_inject *inject)
>>  		return ret;
>>  
>>  	if (!inject->is_pipe && !inject->in_place_update) {
>> +		struct inject_fc inj_fc = {
>> +			.fc.copy = feat_copy_cb,
>> +			.inject = inject,
>> +		};
>> +
>>  		if (inject->build_ids)
>>  			perf_header__set_feat(&session->header,
>>  					      HEADER_BUILD_ID);
>> @@ -872,7 +994,7 @@ static int __cmd_inject(struct perf_inject *inject)
>>  		}
>>  		session->header.data_offset = output_data_offset;
>>  		session->header.data_size = inject->bytes_written;
>> -		perf_session__write_header(session, session->evlist, fd, true);
>> +		perf_session__inject_header(session, session->evlist, fd, &inj_fc.fc);
>>  	}
>>  
>>  	return ret;
>> @@ -1037,6 +1159,11 @@ int cmd_inject(int argc, const char **argv)
>>  	if (zstd_init(&(inject.session->zstd_data), 0) < 0)
>>  		pr_warning("Decompression initialization failed.\n");
>>  
>> +	/* Save original section info before feature bits change */
>> +	ret = save_section_info(&inject);
>> +	if (ret)
>> +		goto out_delete;
>> +
>>  	if (!data.is_pipe && inject.output.is_pipe) {
>>  		ret = perf_header__write_pipe(perf_data__fd(&inject.output));
>>  		if (ret < 0) {
>> diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
>> index b0c57a130d1e..53332da100e8 100644
>> --- a/tools/perf/util/header.c
>> +++ b/tools/perf/util/header.c
>> @@ -3686,6 +3686,14 @@ int perf_session__write_header(struct perf_session *session,
>>  	return perf_session__do_write_header(session, evlist, fd, at_exit, NULL);
>>  }
>>  
>> +int perf_session__inject_header(struct perf_session *session,
>> +				struct evlist *evlist,
>> +				int fd,
>> +				struct feat_copier *fc)
>> +{
>> +	return perf_session__do_write_header(session, evlist, fd, true, fc);
>> +}
>> +
>>  static int perf_header__getbuffer64(struct perf_header *header,
>>  				    int fd, void *buf, size_t size)
>>  {
>> diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
>> index e76ab02d5541..08563c1f1bff 100644
>> --- a/tools/perf/util/header.h
>> +++ b/tools/perf/util/header.h
>> @@ -131,6 +131,11 @@ struct feat_copier {
>>  	int (*copy)(struct feat_copier *fc, int feat, struct feat_writer *fw);
>>  };
>>  
>> +int perf_session__inject_header(struct perf_session *session,
>> +				struct evlist *evlist,
>> +				int fd,
>> +				struct feat_copier *fc);
>> +
>>  void perf_header__set_feat(struct perf_header *header, int feat);
>>  void perf_header__clear_feat(struct perf_header *header, int feat);
>>  bool perf_header__has_feat(const struct perf_header *header, int feat);
>> -- 
>> 2.25.1
>>


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 0/5] perf inject: Minor improvements
  2022-05-23  8:16 ` [PATCH 0/5] perf inject: Minor improvements Jiri Olsa
@ 2022-05-23 13:12   ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 12+ messages in thread
From: Arnaldo Carvalho de Melo @ 2022-05-23 13:12 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: Adrian Hunter, Namhyung Kim, linux-kernel

Em Mon, May 23, 2022 at 10:16:56AM +0200, Jiri Olsa escreveu:
> On Fri, May 20, 2022 at 04:23:59PM +0300, Adrian Hunter wrote:
> > Hi
> > 
> > Here are patches for 2 minor improvements for perf inject:
> > 1. Keep some features sections from input file
> > 2. Keep a copy of kcore_dir
> > 
> > 
> > Adrian Hunter (5):
> >       perf header: Add ability to keep feature sections
> >       libperf: Add preadn()
> >       perf inject: Keep some features sections from input file
> >       perf data: Add has_kcore_dir()
> >       perf inject: Keep a copy of kcore_dir
> 
> LGTM
> 
> Acked-by: Jiri Olsa <jolsa@kernel.org>

Thanks, applied.

- Arnaldo

 
> thanks,
> jirka
> 
> > 
> >  tools/lib/perf/include/internal/lib.h |   2 +
> >  tools/lib/perf/lib.c                  |  20 +++++
> >  tools/perf/builtin-inject.c           | 162 +++++++++++++++++++++++++++++++++-
> >  tools/perf/util/data.c                |  14 +++
> >  tools/perf/util/data.h                |   1 +
> >  tools/perf/util/header.c              |  62 +++++++++++--
> >  tools/perf/util/header.h              |  15 ++++
> >  7 files changed, 264 insertions(+), 12 deletions(-)
> > 
> > 
> > Regards
> > Adrian

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2022-05-23 13:12 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-20 13:23 [PATCH 0/5] perf inject: Minor improvements Adrian Hunter
2022-05-20 13:24 ` [PATCH 1/5] perf header: Add ability to keep feature sections Adrian Hunter
2022-05-20 13:24 ` [PATCH 2/5] libperf: Add preadn() Adrian Hunter
2022-05-20 13:55   ` David Laight
2022-05-20 15:56   ` [PATCH V2 " Adrian Hunter
2022-05-20 13:24 ` [PATCH 3/5] perf inject: Keep some features sections from input file Adrian Hunter
2022-05-23  8:14   ` Jiri Olsa
2022-05-23  9:23     ` Adrian Hunter
2022-05-20 13:24 ` [PATCH 4/5] perf data: Add has_kcore_dir() Adrian Hunter
2022-05-20 13:24 ` [PATCH 5/5] perf inject: Keep a copy of kcore_dir Adrian Hunter
2022-05-23  8:16 ` [PATCH 0/5] perf inject: Minor improvements Jiri Olsa
2022-05-23 13:12   ` Arnaldo Carvalho de Melo

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.