All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCHv3 00/20] perf record: Add support to store data in directory
@ 2019-02-24 19:06 Jiri Olsa
  2019-02-24 19:06 ` [PATCH 01/20] perf tools: Add depth checking to rm_rf Jiri Olsa
                   ` (19 more replies)
  0 siblings, 20 replies; 32+ messages in thread
From: Jiri Olsa @ 2019-02-24 19:06 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Adrian Hunter, Andi Kleen, Stephane Eranian,
	Alexey Budankov

hi,
this patchset adds the --dir option to record command (and all
the other record command that overload cmd_record) that allows
the data to be stored in directory with multiple data files.

It's next step for multiple threads implementation in record.
It's now possible to make directory data via --dir option, like:

  $ perf record --dir perf bench sched messaging
  $ ls -l perf.data
  total 344
  -rw-------. 1 jolsa jolsa 43864 Jan 20 22:26 data.0
  -rw-------. 1 jolsa jolsa 30464 Jan 20 22:26 data.1
  -rw-------. 1 jolsa jolsa 53816 Jan 20 22:26 data.2
  -rw-------. 1 jolsa jolsa 30368 Jan 20 22:26 data.3
  -rw-------. 1 jolsa jolsa 40088 Jan 20 22:26 data.4
  -rw-------. 1 jolsa jolsa 42592 Jan 20 22:26 data.5
  -rw-------. 1 jolsa jolsa 56136 Jan 20 22:26 data.6
  -rw-------. 1 jolsa jolsa 25992 Jan 20 22:26 data.7
  -rw-------. 1 jolsa jolsa  8832 Jan 20 22:26 header

There's a data file created for every cpu and it's storing
data for those cpu maps. The report command will read it
transparently, sort it and display as single file data.

There's new DIR_FORMAT feature to describe directory data
layout/format. In future we can describe different data files
layout according to special needs.

It's possible to transform directory data into standard
perf.data file via simple inject command:
    
  $ perf inject -o perf.data.file -i perf.data

The old perf fails over the directory data with following message:
  $ perf report
  incompatible file format (rerun with -v to learn more)

I'm now testing the record threads support, so I'd like to
have some agreement on the directory data support before.

v3 changes:
  - add rm_rf_perf_data to safely remove file/directory perf data
  - allocation fix in perf_data__create_dir

v2 changes:
  - rm_rf changes are already accepted with requested changes
  - updated doc/man plus adding perf.data-directory-format.txt
    to describe directory format/layout
  - the --switch-output options now works over directory data
  - data rollback is not part of this patchset, updated my TODO though ;-)
  - added --output-dir option to combine -o and --dir
  - added DIR_FORMAT feature to describe directory data
  - disabling directory output for aio for now

It's also available in here:
  git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
  perf/dir

thanks,
jirka


---
Jiri Olsa (20):
      perf tools: Add depth checking to rm_rf
      perf tools: Add pattern name checking to rm_rf
      perf tools: Add rm_rf_perf_data function
      perf data: Move size to struct perf_data_file
      perf data: Add global path holder
      perf data: Make check_backup work over directories
      perf data: Fail check_backup in case of error
      perf data: Add perf_data__(create_dir|close_dir) functions
      perf data: Add perf_data__open_dir_data function
      perf data: Add directory support
      perf data: Don't store auxtrace index for directory data file
      perf data: Add perf_data__update_dir function
      perf data: Make perf_data__size to work over directory
      perf header: Add DIR_FORMAT feature to describe directory data
      perf session: Add process callback to reader object
      perf session: Add __perf_session__process_dir_events function
      perf session: Add path to reader object
      perf record: Add --dir option to store data in directory
      perf record: Add --output-dir option to store data in directory
      perf record: Describe perf.data directory format

 tools/lib/subcmd/parse-options.h                        |   4 ++
 tools/perf/Documentation/perf-record.txt                |   6 +++
 tools/perf/Documentation/perf.data-directory-format.txt |  54 ++++++++++++++++++++
 tools/perf/builtin-annotate.c                           |   4 +-
 tools/perf/builtin-buildid-cache.c                      |   4 +-
 tools/perf/builtin-buildid-list.c                       |   8 ++-
 tools/perf/builtin-c2c.c                                |   4 +-
 tools/perf/builtin-diff.c                               |  12 ++---
 tools/perf/builtin-evlist.c                             |   4 +-
 tools/perf/builtin-inject.c                             |  10 ++--
 tools/perf/builtin-kmem.c                               |   2 +-
 tools/perf/builtin-kvm.c                                |   8 ++-
 tools/perf/builtin-lock.c                               |   8 ++-
 tools/perf/builtin-mem.c                                |   8 ++-
 tools/perf/builtin-record.c                             | 104 ++++++++++++++++++++++++++++++++++-----
 tools/perf/builtin-report.c                             |   6 +--
 tools/perf/builtin-sched.c                              |  16 +++---
 tools/perf/builtin-script.c                             |  12 ++---
 tools/perf/builtin-stat.c                               |   6 +--
 tools/perf/builtin-timechart.c                          |   8 ++-
 tools/perf/builtin-trace.c                              |   8 ++-
 tools/perf/util/data-convert-bt.c                       |   2 +-
 tools/perf/util/data.c                                  | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 tools/perf/util/data.h                                  |  26 +++++++---
 tools/perf/util/header.c                                |  44 ++++++++++++++++-
 tools/perf/util/header.h                                |   5 ++
 tools/perf/util/mmap.h                                  |  23 ++++-----
 tools/perf/util/session.c                               | 125 +++++++++++++++++++++++++++++++++++++++++++---
 tools/perf/util/util.c                                  |  55 ++++++++++++++++++++-
 tools/perf/util/util.h                                  |   1 +
 30 files changed, 700 insertions(+), 134 deletions(-)
 create mode 100644 tools/perf/Documentation/perf.data-directory-format.txt

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

* [PATCH 01/20] perf tools: Add depth checking to rm_rf
  2019-02-24 19:06 [PATCHv3 00/20] perf record: Add support to store data in directory Jiri Olsa
@ 2019-02-24 19:06 ` Jiri Olsa
  2019-02-28  8:00   ` [tip:perf/core] " tip-bot for Jiri Olsa
  2019-02-24 19:06 ` [PATCH 02/20] perf tools: Add pattern name " Jiri Olsa
                   ` (18 subsequent siblings)
  19 siblings, 1 reply; 32+ messages in thread
From: Jiri Olsa @ 2019-02-24 19:06 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Adrian Hunter, Andi Kleen, Stephane Eranian,
	Alexey Budankov

Adding depth argument to rm_rf (and renaming it to rm_rf_depth)
to specify the depth we will go searching for files to remove.

It will be used to specify single depth for perf.data directory
removal in following patch.

Link: http://lkml.kernel.org/n/tip-sylld4txjlqjc18nzhitaokc@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/util.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 3ee410fc047a..bcf436892155 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -117,7 +117,12 @@ int mkdir_p(char *path, mode_t mode)
 	return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
 }
 
-int rm_rf(const char *path)
+/*
+ * The depth specify how deep the removal will go.
+ * 0       - will remove only files under the 'path' directory
+ * 1 .. x  - will dive in x-level deep under the 'path' directory
+ */
+static int rm_rf_depth(const char *path, int depth)
 {
 	DIR *dir;
 	int ret;
@@ -155,7 +160,7 @@ int rm_rf(const char *path)
 		}
 
 		if (S_ISDIR(statbuf.st_mode))
-			ret = rm_rf(namebuf);
+			ret = depth ? rm_rf_depth(namebuf, depth - 1) : 0;
 		else
 			ret = unlink(namebuf);
 	}
@@ -167,6 +172,11 @@ int rm_rf(const char *path)
 	return rmdir(path);
 }
 
+int rm_rf(const char *path)
+{
+	return rm_rf_depth(path, INT_MAX);
+}
+
 /* A filter which removes dot files */
 bool lsdir_no_dot_filter(const char *name __maybe_unused, struct dirent *d)
 {
-- 
2.17.2


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

* [PATCH 02/20] perf tools: Add pattern name checking to rm_rf
  2019-02-24 19:06 [PATCHv3 00/20] perf record: Add support to store data in directory Jiri Olsa
  2019-02-24 19:06 ` [PATCH 01/20] perf tools: Add depth checking to rm_rf Jiri Olsa
@ 2019-02-24 19:06 ` Jiri Olsa
  2019-02-28  8:00   ` [tip:perf/core] " tip-bot for Jiri Olsa
  2019-02-24 19:06 ` [PATCH 03/20] perf tools: Add rm_rf_perf_data function Jiri Olsa
                   ` (17 subsequent siblings)
  19 siblings, 1 reply; 32+ messages in thread
From: Jiri Olsa @ 2019-02-24 19:06 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Adrian Hunter, Andi Kleen, Stephane Eranian,
	Alexey Budankov

Adding pattern argument to rm_rf_depth (and renaming it to
rm_rf_depth_pat) to specify the name pattern files need to
match inside the directory. The function fails if we find
different file to remove.

Link: http://lkml.kernel.org/n/tip-vnqs7ut0pnmrpih05xca6cvv@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/util.c | 36 +++++++++++++++++++++++++++++++++---
 1 file changed, 33 insertions(+), 3 deletions(-)

diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index bcf436892155..02b7a38f98ce 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -21,6 +21,7 @@
 #include <linux/time64.h>
 #include <unistd.h>
 #include "strlist.h"
+#include "string2.h"
 
 /*
  * XXX We need to find a better place for these things...
@@ -117,12 +118,38 @@ int mkdir_p(char *path, mode_t mode)
 	return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
 }
 
+static bool match_pat(char *file, const char **pat)
+{
+	int i = 0;
+
+	if (!pat)
+		return true;
+
+	while (pat[i]) {
+		if (strglobmatch(file, pat[i]))
+			return true;
+
+		i++;
+	}
+
+	return false;
+}
+
 /*
  * The depth specify how deep the removal will go.
  * 0       - will remove only files under the 'path' directory
  * 1 .. x  - will dive in x-level deep under the 'path' directory
+ *
+ * If specified the pat is array of string patterns ended with NULL,
+ * which are checked upon every file/directory found. Only matching
+ * ones are removed.
+ *
+ * The function returns:
+ *    0 on success
+ *   -1 on removal failure with errno set
+ *   -2 on pattern failure
  */
-static int rm_rf_depth(const char *path, int depth)
+static int rm_rf_depth_pat(const char *path, int depth, const char **pat)
 {
 	DIR *dir;
 	int ret;
@@ -149,6 +176,9 @@ static int rm_rf_depth(const char *path, int depth)
 		if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
 			continue;
 
+		if (!match_pat(d->d_name, pat))
+			return -2;
+
 		scnprintf(namebuf, sizeof(namebuf), "%s/%s",
 			  path, d->d_name);
 
@@ -160,7 +190,7 @@ static int rm_rf_depth(const char *path, int depth)
 		}
 
 		if (S_ISDIR(statbuf.st_mode))
-			ret = depth ? rm_rf_depth(namebuf, depth - 1) : 0;
+			ret = depth ? rm_rf_depth_pat(namebuf, depth - 1, pat) : 0;
 		else
 			ret = unlink(namebuf);
 	}
@@ -174,7 +204,7 @@ static int rm_rf_depth(const char *path, int depth)
 
 int rm_rf(const char *path)
 {
-	return rm_rf_depth(path, INT_MAX);
+	return rm_rf_depth_pat(path, INT_MAX, NULL);
 }
 
 /* A filter which removes dot files */
-- 
2.17.2


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

* [PATCH 03/20] perf tools: Add rm_rf_perf_data function
  2019-02-24 19:06 [PATCHv3 00/20] perf record: Add support to store data in directory Jiri Olsa
  2019-02-24 19:06 ` [PATCH 01/20] perf tools: Add depth checking to rm_rf Jiri Olsa
  2019-02-24 19:06 ` [PATCH 02/20] perf tools: Add pattern name " Jiri Olsa
@ 2019-02-24 19:06 ` Jiri Olsa
  2019-02-28  8:01   ` [tip:perf/core] " tip-bot for Jiri Olsa
  2019-02-24 19:06 ` [PATCH 04/20] perf data: Move size to struct perf_data_file Jiri Olsa
                   ` (16 subsequent siblings)
  19 siblings, 1 reply; 32+ messages in thread
From: Jiri Olsa @ 2019-02-24 19:06 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Adrian Hunter, Andi Kleen, Stephane Eranian,
	Alexey Budankov

To remove perf.data including the directory,
with checking on expected files and no other
directories inside.

Link: http://lkml.kernel.org/n/tip-co7i8qqliinktjw1limudw73@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/util.c | 11 +++++++++++
 tools/perf/util/util.h |  1 +
 2 files changed, 12 insertions(+)

diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 02b7a38f98ce..706818693086 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -202,6 +202,17 @@ static int rm_rf_depth_pat(const char *path, int depth, const char **pat)
 	return rmdir(path);
 }
 
+int rm_rf_perf_data(const char *path)
+{
+	const char *pat[] = {
+		"header",
+		"data.*",
+		NULL,
+	};
+
+	return rm_rf_depth_pat(path, 0, pat);
+}
+
 int rm_rf(const char *path)
 {
 	return rm_rf_depth_pat(path, INT_MAX, NULL);
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index ece040b799f6..01c538027c6f 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -31,6 +31,7 @@ struct strlist;
 
 int mkdir_p(char *path, mode_t mode);
 int rm_rf(const char *path);
+int rm_rf_perf_data(const char *path);
 struct strlist *lsdir(const char *name, bool (*filter)(const char *, struct dirent *));
 bool lsdir_no_dot_filter(const char *name, struct dirent *d);
 int copyfile(const char *from, const char *to);
-- 
2.17.2


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

* [PATCH 04/20] perf data: Move size to struct perf_data_file
  2019-02-24 19:06 [PATCHv3 00/20] perf record: Add support to store data in directory Jiri Olsa
                   ` (2 preceding siblings ...)
  2019-02-24 19:06 ` [PATCH 03/20] perf tools: Add rm_rf_perf_data function Jiri Olsa
@ 2019-02-24 19:06 ` Jiri Olsa
  2019-02-24 19:06 ` [PATCH 05/20] perf data: Add global path holder Jiri Olsa
                   ` (15 subsequent siblings)
  19 siblings, 0 replies; 32+ messages in thread
From: Jiri Olsa @ 2019-02-24 19:06 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Adrian Hunter, Andi Kleen, Stephane Eranian,
	Alexey Budankov

We are about to add support for multiple files,
so we need each file to keep its size.

Link: http://lkml.kernel.org/n/tip-gcf5gtwxds3ggegu6evl0jvn@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/builtin-record.c | 5 ++---
 tools/perf/util/data.c      | 2 +-
 tools/perf/util/data.h      | 4 ++--
 3 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 6c3719ac901d..e5e9900c9039 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -660,10 +660,9 @@ static int process_sample_event(struct perf_tool *tool,
 
 static int process_buildids(struct record *rec)
 {
-	struct perf_data *data = &rec->data;
 	struct perf_session *session = rec->session;
 
-	if (data->size == 0)
+	if (perf_data__size(&rec->data) == 0)
 		return 0;
 
 	/*
@@ -851,7 +850,7 @@ record__finish_output(struct record *rec)
 		return;
 
 	rec->session->header.data_size += rec->bytes_written;
-	data->size = lseek(perf_data__fd(data), 0, SEEK_CUR);
+	data->file.size = lseek(perf_data__fd(data), 0, SEEK_CUR);
 
 	if (!rec->no_buildid) {
 		process_buildids(rec);
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index d8cfc19ddb10..09eceda17fc2 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -82,7 +82,7 @@ static int open_file_read(struct perf_data *data)
 		goto out_close;
 	}
 
-	data->size = st.st_size;
+	data->file.size = st.st_size;
 	return fd;
 
  out_close:
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
index 4828f7feea89..85f9c0dbf982 100644
--- a/tools/perf/util/data.h
+++ b/tools/perf/util/data.h
@@ -12,13 +12,13 @@ enum perf_data_mode {
 struct perf_data_file {
 	const char	*path;
 	int		 fd;
+	unsigned long	 size;
 };
 
 struct perf_data {
 	struct perf_data_file	 file;
 	bool			 is_pipe;
 	bool			 force;
-	unsigned long		 size;
 	enum perf_data_mode	 mode;
 };
 
@@ -44,7 +44,7 @@ static inline int perf_data__fd(struct perf_data *data)
 
 static inline unsigned long perf_data__size(struct perf_data *data)
 {
-	return data->size;
+	return data->file.size;
 }
 
 int perf_data__open(struct perf_data *data);
-- 
2.17.2


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

* [PATCH 05/20] perf data: Add global path holder
  2019-02-24 19:06 [PATCHv3 00/20] perf record: Add support to store data in directory Jiri Olsa
                   ` (3 preceding siblings ...)
  2019-02-24 19:06 ` [PATCH 04/20] perf data: Move size to struct perf_data_file Jiri Olsa
@ 2019-02-24 19:06 ` Jiri Olsa
  2019-02-24 19:06 ` [PATCH 06/20] perf data: Make check_backup work over directories Jiri Olsa
                   ` (14 subsequent siblings)
  19 siblings, 0 replies; 32+ messages in thread
From: Jiri Olsa @ 2019-02-24 19:06 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Adrian Hunter, Andi Kleen, Stephane Eranian,
	Alexey Budankov

Adding path to the struct perf_data. It will keep the
configured path for the data (const char*). The path
in struct perf_data_file is now dynamically allocated
(duped) from it.

This scheme is useful/used in following patches where
struct perf_data::path holds the 'configure' directory
path and struct perf_data_file::path holds the allocated
path for specific files.

Also it actually makes the code little simpler.

Link: http://lkml.kernel.org/n/tip-ww4tdzfaub4vlv9xxkxvwx9q@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/builtin-annotate.c      |  4 +--
 tools/perf/builtin-buildid-cache.c |  4 +--
 tools/perf/builtin-buildid-list.c  |  8 +++---
 tools/perf/builtin-c2c.c           |  4 +--
 tools/perf/builtin-diff.c          | 12 ++++-----
 tools/perf/builtin-evlist.c        |  4 +--
 tools/perf/builtin-inject.c        | 10 +++-----
 tools/perf/builtin-kmem.c          |  2 +-
 tools/perf/builtin-kvm.c           |  8 +++---
 tools/perf/builtin-lock.c          |  8 +++---
 tools/perf/builtin-mem.c           |  8 +++---
 tools/perf/builtin-record.c        |  6 ++---
 tools/perf/builtin-report.c        |  6 ++---
 tools/perf/builtin-sched.c         | 16 +++++-------
 tools/perf/builtin-script.c        | 12 ++++-----
 tools/perf/builtin-stat.c          |  6 ++---
 tools/perf/builtin-timechart.c     |  8 +++---
 tools/perf/builtin-trace.c         |  8 +++---
 tools/perf/util/data-convert-bt.c  |  2 +-
 tools/perf/util/data.c             | 39 +++++++++++++++++++++---------
 tools/perf/util/data.h             |  3 ++-
 21 files changed, 86 insertions(+), 92 deletions(-)

diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 7f3c3fea67b4..67f9d9ffacfb 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -441,7 +441,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
 	}
 
 	if (total_nr_samples == 0) {
-		ui__error("The %s file has no samples!\n", session->data->file.path);
+		ui__error("The %s data has no samples!\n", session->data->path);
 		goto out;
 	}
 
@@ -578,7 +578,7 @@ int cmd_annotate(int argc, const char **argv)
 	if (quiet)
 		perf_quiet_option();
 
-	data.file.path = input_name;
+	data.path = input_name;
 
 	annotate.session = perf_session__new(&data, false, &annotate.tool);
 	if (annotate.session == NULL)
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index 115110a4796a..10457b10e568 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -416,8 +416,8 @@ int cmd_buildid_cache(int argc, const char **argv)
 		nsi = nsinfo__new(ns_id);
 
 	if (missing_filename) {
-		data.file.path = missing_filename;
-		data.force     = force;
+		data.path  = missing_filename;
+		data.force = force;
 
 		session = perf_session__new(&data, false, NULL);
 		if (session == NULL)
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index 78abbe8d9d5f..f403e19488b5 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -52,11 +52,9 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
 {
 	struct perf_session *session;
 	struct perf_data data = {
-		.file      = {
-			.path = input_name,
-		},
-		.mode      = PERF_DATA_MODE_READ,
-		.force     = force,
+		.path  = input_name,
+		.mode  = PERF_DATA_MODE_READ,
+		.force = force,
 	};
 
 	symbol__elf_init();
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c
index efaaab23c6fd..4272763a5e96 100644
--- a/tools/perf/builtin-c2c.c
+++ b/tools/perf/builtin-c2c.c
@@ -2750,8 +2750,8 @@ static int perf_c2c__report(int argc, const char **argv)
 	if (!input_name || !strlen(input_name))
 		input_name = "perf.data";
 
-	data.file.path = input_name;
-	data.force     = symbol_conf.force;
+	data.path  = input_name;
+	data.force = symbol_conf.force;
 
 	err = setup_display(display);
 	if (err)
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 751e1971456b..58fe0e88215c 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -708,7 +708,7 @@ static void data__fprintf(void)
 
 	data__for_each_file(i, d)
 		fprintf(stdout, "#  [%d] %s %s\n",
-			d->idx, d->data.file.path,
+			d->idx, d->data.path,
 			!d->idx ? "(Baseline)" : "");
 
 	fprintf(stdout, "#\n");
@@ -779,14 +779,14 @@ static int __cmd_diff(void)
 	data__for_each_file(i, d) {
 		d->session = perf_session__new(&d->data, false, &tool);
 		if (!d->session) {
-			pr_err("Failed to open %s\n", d->data.file.path);
+			pr_err("Failed to open %s\n", d->data.path);
 			ret = -1;
 			goto out_delete;
 		}
 
 		ret = perf_session__process_events(d->session);
 		if (ret) {
-			pr_err("Failed to process %s\n", d->data.file.path);
+			pr_err("Failed to process %s\n", d->data.path);
 			goto out_delete;
 		}
 
@@ -1289,9 +1289,9 @@ static int data_init(int argc, const char **argv)
 	data__for_each_file(i, d) {
 		struct perf_data *data = &d->data;
 
-		data->file.path = use_default ? defaults[i] : argv[i];
-		data->mode      = PERF_DATA_MODE_READ,
-		data->force     = force,
+		data->path  = use_default ? defaults[i] : argv[i];
+		data->mode  = PERF_DATA_MODE_READ,
+		data->force = force,
 
 		d->idx  = i;
 	}
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index e06e822ce634..6e4f63b0da4a 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -23,9 +23,7 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details
 	struct perf_session *session;
 	struct perf_evsel *pos;
 	struct perf_data data = {
-		.file      = {
-			.path = file_name,
-		},
+		.path      = file_name,
 		.mode      = PERF_DATA_MODE_READ,
 		.force     = details->force,
 	};
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 9bb1f35d5cb7..24086b7f1b14 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -770,10 +770,8 @@ int cmd_inject(int argc, const char **argv)
 		.input_name  = "-",
 		.samples = LIST_HEAD_INIT(inject.samples),
 		.output = {
-			.file      = {
-				.path = "-",
-			},
-			.mode      = PERF_DATA_MODE_WRITE,
+			.path = "-",
+			.mode = PERF_DATA_MODE_WRITE,
 		},
 	};
 	struct perf_data data = {
@@ -786,7 +784,7 @@ int cmd_inject(int argc, const char **argv)
 			    "Inject build-ids into the output stream"),
 		OPT_STRING('i', "input", &inject.input_name, "file",
 			   "input file name"),
-		OPT_STRING('o', "output", &inject.output.file.path, "file",
+		OPT_STRING('o', "output", &inject.output.path, "file",
 			   "output file name"),
 		OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
 			    "Merge sched-stat and sched-switch for getting events "
@@ -834,7 +832,7 @@ int cmd_inject(int argc, const char **argv)
 
 	inject.tool.ordered_events = inject.sched_stat;
 
-	data.file.path = inject.input_name;
+	data.path = inject.input_name;
 	inject.session = perf_session__new(&data, true, &inject.tool);
 	if (inject.session == NULL)
 		return -1;
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index b80ec0883537..fa520f4b8095 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -1949,7 +1949,7 @@ int cmd_kmem(int argc, const char **argv)
 		return __cmd_record(argc, argv);
 	}
 
-	data.file.path = input_name;
+	data.path = input_name;
 
 	kmem_session = session = perf_session__new(&data, false, &perf_kmem);
 	if (session == NULL)
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 3d4cbc4e87c7..dbb6f737a3e2 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -1080,11 +1080,9 @@ static int read_events(struct perf_kvm_stat *kvm)
 		.ordered_events		= true,
 	};
 	struct perf_data file = {
-		.file      = {
-			.path = kvm->file_name,
-		},
-		.mode      = PERF_DATA_MODE_READ,
-		.force     = kvm->force,
+		.path  = kvm->file_name,
+		.mode  = PERF_DATA_MODE_READ,
+		.force = kvm->force,
 	};
 
 	kvm->tool = eops;
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 6e0189df2b3b..b9810a8d350a 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -866,11 +866,9 @@ static int __cmd_report(bool display_info)
 		.ordered_events	 = true,
 	};
 	struct perf_data data = {
-		.file      = {
-			.path = input_name,
-		},
-		.mode      = PERF_DATA_MODE_READ,
-		.force     = force,
+		.path  = input_name,
+		.mode  = PERF_DATA_MODE_READ,
+		.force = force,
 	};
 
 	session = perf_session__new(&data, false, &eops);
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index ba7e8d87dec3..f45c8b502f63 100644
--- a/tools/perf/builtin-mem.c
+++ b/tools/perf/builtin-mem.c
@@ -239,11 +239,9 @@ static int process_sample_event(struct perf_tool *tool,
 static int report_raw_events(struct perf_mem *mem)
 {
 	struct perf_data data = {
-		.file      = {
-			.path = input_name,
-		},
-		.mode      = PERF_DATA_MODE_READ,
-		.force     = mem->force,
+		.path  = input_name,
+		.mode  = PERF_DATA_MODE_READ,
+		.force = mem->force,
 	};
 	int ret;
 	struct perf_session *session = perf_session__new(&data, false,
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index e5e9900c9039..f3f7f3100336 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -918,7 +918,7 @@ record__switch_output(struct record *rec, bool at_exit)
 
 	if (!quiet)
 		fprintf(stderr, "[ perf record: Dump %s.%s ]\n",
-			data->file.path, timestamp);
+			data->path, timestamp);
 
 	/* Output tracking events */
 	if (!at_exit) {
@@ -1461,7 +1461,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
 
 		fprintf(stderr,	"[ perf record: Captured and wrote %.3f MB %s%s%s ]\n",
 			perf_data__size(data) / 1024.0 / 1024.0,
-			data->file.path, postfix, samples);
+			data->path, postfix, samples);
 	}
 
 out_delete_session:
@@ -1862,7 +1862,7 @@ static struct option __record_options[] = {
 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
 		    "list of cpus to monitor"),
 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
-	OPT_STRING('o', "output", &record.data.file.path, "file",
+	OPT_STRING('o', "output", &record.data.path, "file",
 		    "output file name"),
 	OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
 			&record.opts.no_inherit_set,
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 2e8c74d6430c..1532ebde6c4b 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -899,7 +899,7 @@ static int __cmd_report(struct report *rep)
 		rep->nr_entries += evsel__hists(pos)->nr_entries;
 
 	if (rep->nr_entries == 0) {
-		ui__error("The %s file has no samples!\n", data->file.path);
+		ui__error("The %s data has no samples!\n", data->path);
 		return 0;
 	}
 
@@ -1207,8 +1207,8 @@ int cmd_report(int argc, const char **argv)
 			input_name = "perf.data";
 	}
 
-	data.file.path = input_name;
-	data.force     = symbol_conf.force;
+	data.path  = input_name;
+	data.force = symbol_conf.force;
 
 repeat:
 	session = perf_session__new(&data, false, &report.tool);
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 640558e9352e..275f2d92a7bf 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1785,11 +1785,9 @@ static int perf_sched__read_events(struct perf_sched *sched)
 	};
 	struct perf_session *session;
 	struct perf_data data = {
-		.file      = {
-			.path = input_name,
-		},
-		.mode      = PERF_DATA_MODE_READ,
-		.force     = sched->force,
+		.path  = input_name,
+		.mode  = PERF_DATA_MODE_READ,
+		.force = sched->force,
 	};
 	int rc = -1;
 
@@ -2958,11 +2956,9 @@ static int perf_sched__timehist(struct perf_sched *sched)
 		{ "sched:sched_migrate_task", timehist_migrate_task_event, },
 	};
 	struct perf_data data = {
-		.file      = {
-			.path = input_name,
-		},
-		.mode      = PERF_DATA_MODE_READ,
-		.force     = sched->force,
+		.path  = input_name,
+		.mode  = PERF_DATA_MODE_READ,
+		.force = sched->force,
 	};
 
 	struct perf_session *session;
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 373ea151dc60..5b1543f42290 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -2951,10 +2951,8 @@ int find_scripts(char **scripts_array, char **scripts_path_array)
 	DIR *scripts_dir, *lang_dir;
 	struct perf_session *session;
 	struct perf_data data = {
-		.file      = {
-			.path = input_name,
-		},
-		.mode      = PERF_DATA_MODE_READ,
+		.path = input_name,
+		.mode = PERF_DATA_MODE_READ,
 	};
 	char *temp;
 	int i = 0;
@@ -3427,8 +3425,8 @@ int cmd_script(int argc, const char **argv)
 	argc = parse_options_subcommand(argc, argv, options, script_subcommands, script_usage,
 			     PARSE_OPT_STOP_AT_NON_OPTION);
 
-	data.file.path = input_name;
-	data.force     = symbol_conf.force;
+	data.path  = input_name;
+	data.force = symbol_conf.force;
 
 	if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) {
 		rec_script_path = get_script_path(argv[1], RECORD_SUFFIX);
@@ -3654,7 +3652,7 @@ int cmd_script(int argc, const char **argv)
 			goto out_delete;
 		}
 
-		input = open(data.file.path, O_RDONLY);	/* input_name */
+		input = open(data.path, O_RDONLY);	/* input_name */
 		if (input < 0) {
 			err = -errno;
 			perror("failed to open file");
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index bb24f9c17f9a..7b8f09b0b8bf 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -1322,7 +1322,7 @@ static int __cmd_record(int argc, const char **argv)
 			     PARSE_OPT_STOP_AT_NON_OPTION);
 
 	if (output_name)
-		data->file.path = output_name;
+		data->path = output_name;
 
 	if (stat_config.run_count != 1 || forever) {
 		pr_err("Cannot use -r option with perf stat record.\n");
@@ -1523,8 +1523,8 @@ static int __cmd_report(int argc, const char **argv)
 			input_name = "perf.data";
 	}
 
-	perf_stat.data.file.path = input_name;
-	perf_stat.data.mode      = PERF_DATA_MODE_READ;
+	perf_stat.data.path = input_name;
+	perf_stat.data.mode = PERF_DATA_MODE_READ;
 
 	session = perf_session__new(&perf_stat.data, false, &perf_stat.tool);
 	if (session == NULL)
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 775b99833e51..9b98687a27b9 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -1602,11 +1602,9 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name)
 		{ "syscalls:sys_exit_select",		process_exit_poll },
 	};
 	struct perf_data data = {
-		.file      = {
-			.path = input_name,
-		},
-		.mode      = PERF_DATA_MODE_READ,
-		.force     = tchart->force,
+		.path  = input_name,
+		.mode  = PERF_DATA_MODE_READ,
+		.force = tchart->force,
 	};
 
 	struct perf_session *session = perf_session__new(&data, false,
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 1a11fe656afc..f5b3a1e9c1dd 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -3154,11 +3154,9 @@ static int trace__replay(struct trace *trace)
 		{ "probe:vfs_getname",	     trace__vfs_getname, },
 	};
 	struct perf_data data = {
-		.file      = {
-			.path = input_name,
-		},
-		.mode      = PERF_DATA_MODE_READ,
-		.force     = trace->force,
+		.path  = input_name,
+		.mode  = PERF_DATA_MODE_READ,
+		.force = trace->force,
 	};
 	struct perf_session *session;
 	struct perf_evsel *evsel;
diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c
index 2a36fab76994..ea742a254aa5 100644
--- a/tools/perf/util/data-convert-bt.c
+++ b/tools/perf/util/data-convert-bt.c
@@ -1650,7 +1650,7 @@ int bt_convert__perf2ctf(const char *input, const char *path,
 
 	fprintf(stderr,
 		"[ perf data convert: Converted '%s' into CTF data '%s' ]\n",
-		data.file.path, path);
+		data.path, path);
 
 	fprintf(stderr,
 		"[ perf data convert: Converted and wrote %.3f MB (%" PRIu64 " samples",
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index 09eceda17fc2..e16d06ed1100 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -19,11 +19,11 @@ static bool check_pipe(struct perf_data *data)
 	int fd = perf_data__is_read(data) ?
 		 STDIN_FILENO : STDOUT_FILENO;
 
-	if (!data->file.path) {
+	if (!data->path) {
 		if (!fstat(fd, &st) && S_ISFIFO(st.st_mode))
 			is_pipe = true;
 	} else {
-		if (!strcmp(data->file.path, "-"))
+		if (!strcmp(data->path, "-"))
 			is_pipe = true;
 	}
 
@@ -37,13 +37,13 @@ static int check_backup(struct perf_data *data)
 {
 	struct stat st;
 
-	if (!stat(data->file.path, &st) && st.st_size) {
+	if (!stat(data->path, &st) && st.st_size) {
 		/* TODO check errors properly */
 		char oldname[PATH_MAX];
 		snprintf(oldname, sizeof(oldname), "%s.old",
-			 data->file.path);
+			 data->path);
 		unlink(oldname);
-		rename(data->file.path, oldname);
+		rename(data->path, oldname);
 	}
 
 	return 0;
@@ -115,8 +115,22 @@ static int open_file(struct perf_data *data)
 	fd = perf_data__is_read(data) ?
 	     open_file_read(data) : open_file_write(data);
 
+	if (fd < 0) {
+		free(data->file.path);
+		return -1;
+	}
+
 	data->file.fd = fd;
-	return fd < 0 ? -1 : 0;
+	return 0;
+}
+
+static int open_file_dup(struct perf_data *data)
+{
+	data->file.path = strdup(data->path);
+	if (!data->file.path)
+		return -ENOMEM;
+
+	return open_file(data);
 }
 
 int perf_data__open(struct perf_data *data)
@@ -124,14 +138,15 @@ int perf_data__open(struct perf_data *data)
 	if (check_pipe(data))
 		return 0;
 
-	if (!data->file.path)
-		data->file.path = "perf.data";
+	if (!data->path)
+		data->path = "perf.data";
 
-	return open_file(data);
+	return open_file_dup(data);
 }
 
 void perf_data__close(struct perf_data *data)
 {
+	free(data->file.path);
 	close(data->file.fd);
 }
 
@@ -159,15 +174,15 @@ int perf_data__switch(struct perf_data *data,
 	if (perf_data__is_read(data))
 		return -EINVAL;
 
-	if (asprintf(&new_filepath, "%s.%s", data->file.path, postfix) < 0)
+	if (asprintf(&new_filepath, "%s.%s", data->path, postfix) < 0)
 		return -ENOMEM;
 
 	/*
 	 * Only fire a warning, don't return error, continue fill
 	 * original file.
 	 */
-	if (rename(data->file.path, new_filepath))
-		pr_warning("Failed to rename %s to %s\n", data->file.path, new_filepath);
+	if (rename(data->path, new_filepath))
+		pr_warning("Failed to rename %s to %s\n", data->path, new_filepath);
 
 	if (!at_exit) {
 		close(data->file.fd);
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
index 85f9c0dbf982..2bce28117ccf 100644
--- a/tools/perf/util/data.h
+++ b/tools/perf/util/data.h
@@ -10,12 +10,13 @@ enum perf_data_mode {
 };
 
 struct perf_data_file {
-	const char	*path;
+	char		*path;
 	int		 fd;
 	unsigned long	 size;
 };
 
 struct perf_data {
+	const char		*path;
 	struct perf_data_file	 file;
 	bool			 is_pipe;
 	bool			 force;
-- 
2.17.2


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

* [PATCH 06/20] perf data: Make check_backup work over directories
  2019-02-24 19:06 [PATCHv3 00/20] perf record: Add support to store data in directory Jiri Olsa
                   ` (4 preceding siblings ...)
  2019-02-24 19:06 ` [PATCH 05/20] perf data: Add global path holder Jiri Olsa
@ 2019-02-24 19:06 ` Jiri Olsa
  2019-02-28  8:02   ` [tip:perf/core] " tip-bot for Jiri Olsa
  2019-02-24 19:06 ` [PATCH 07/20] perf data: Fail check_backup in case of error Jiri Olsa
                   ` (13 subsequent siblings)
  19 siblings, 1 reply; 32+ messages in thread
From: Jiri Olsa @ 2019-02-24 19:06 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Adrian Hunter, Andi Kleen, Stephane Eranian,
	Alexey Budankov

Changing check_backup to call rm_rf_perf_data instead of unlink to
work over directory paths. Also moving the call earlier in the code,
before we fork for file/dir, so it can backup also directory data.

Link: http://lkml.kernel.org/n/tip-j4lwm20en1yk1hsaqb8zpxkr@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/data.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index e16d06ed1100..bbf9a299615e 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -37,12 +37,15 @@ static int check_backup(struct perf_data *data)
 {
 	struct stat st;
 
+	if (perf_data__is_read(data))
+		return 0;
+
 	if (!stat(data->path, &st) && st.st_size) {
 		/* TODO check errors properly */
 		char oldname[PATH_MAX];
 		snprintf(oldname, sizeof(oldname), "%s.old",
 			 data->path);
-		unlink(oldname);
+		rm_rf_perf_data(oldname);
 		rename(data->path, oldname);
 	}
 
@@ -95,9 +98,6 @@ static int open_file_write(struct perf_data *data)
 	int fd;
 	char sbuf[STRERR_BUFSIZE];
 
-	if (check_backup(data))
-		return -1;
-
 	fd = open(data->file.path, O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC,
 		  S_IRUSR|S_IWUSR);
 
@@ -141,6 +141,9 @@ int perf_data__open(struct perf_data *data)
 	if (!data->path)
 		data->path = "perf.data";
 
+	if (check_backup(data))
+		return -1;
+
 	return open_file_dup(data);
 }
 
-- 
2.17.2


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

* [PATCH 07/20] perf data: Fail check_backup in case of error
  2019-02-24 19:06 [PATCHv3 00/20] perf record: Add support to store data in directory Jiri Olsa
                   ` (5 preceding siblings ...)
  2019-02-24 19:06 ` [PATCH 06/20] perf data: Make check_backup work over directories Jiri Olsa
@ 2019-02-24 19:06 ` Jiri Olsa
  2019-02-28  8:02   ` [tip:perf/core] " tip-bot for Jiri Olsa
  2019-02-24 19:06 ` [PATCH 08/20] perf data: Add perf_data__(create_dir|close_dir) functions Jiri Olsa
                   ` (12 subsequent siblings)
  19 siblings, 1 reply; 32+ messages in thread
From: Jiri Olsa @ 2019-02-24 19:06 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Adrian Hunter, Andi Kleen, Stephane Eranian,
	Alexey Budankov

And display the error message from removing
the old data file:

  $ perf record ls
  Can't remove old data: Permission denied (perf.data.old)
  Perf session creation failed.

  $ perf record ls
  Can't remove old data: Unknown file found (perf.data.old)
  Perf session creation failed.

Not sure how to make fail the rename (after we successfully
remove the destination file/dir) to show the message,
anyway let's have it there.

Link: http://lkml.kernel.org/n/tip-6k0tikvlyugms7xxqs794jxz@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/data.c | 21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index bbf9a299615e..d008c3973012 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -41,12 +41,27 @@ static int check_backup(struct perf_data *data)
 		return 0;
 
 	if (!stat(data->path, &st) && st.st_size) {
-		/* TODO check errors properly */
 		char oldname[PATH_MAX];
+		int ret;
+
 		snprintf(oldname, sizeof(oldname), "%s.old",
 			 data->path);
-		rm_rf_perf_data(oldname);
-		rename(data->path, oldname);
+
+		ret = rm_rf_perf_data(oldname);
+		if (ret) {
+			pr_err("Can't remove old data: %s (%s)\n",
+			       ret == -2 ?
+			       "Unknown file found" : strerror(errno),
+			       oldname);
+			return -1;
+		}
+
+		if (rename(data->path, oldname)) {
+			pr_err("Can't move data: %s (%s to %s)\n",
+			       strerror(errno),
+			       data->path, oldname);
+			return -1;
+		}
 	}
 
 	return 0;
-- 
2.17.2


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

* [PATCH 08/20] perf data: Add perf_data__(create_dir|close_dir) functions
  2019-02-24 19:06 [PATCHv3 00/20] perf record: Add support to store data in directory Jiri Olsa
                   ` (6 preceding siblings ...)
  2019-02-24 19:06 ` [PATCH 07/20] perf data: Fail check_backup in case of error Jiri Olsa
@ 2019-02-24 19:06 ` Jiri Olsa
  2019-02-28  8:03   ` [tip:perf/core] " tip-bot for Jiri Olsa
  2019-02-24 19:06 ` [PATCH 09/20] perf data: Add perf_data__open_dir_data function Jiri Olsa
                   ` (11 subsequent siblings)
  19 siblings, 1 reply; 32+ messages in thread
From: Jiri Olsa @ 2019-02-24 19:06 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Adrian Hunter, Andi Kleen, Stephane Eranian,
	Alexey Budankov

Adding perf_data__create_dir to create nr files inside
struct perf_data path directory:
  int perf_data__create_dir(struct perf_data *data, int nr);

and function to close that data:
  void perf_data__close_dir(struct perf_data *data);

Link: http://lkml.kernel.org/n/tip-kl4s1f13cg6wycrg367p85qm@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/data.c | 47 ++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/data.h |  8 +++++++
 2 files changed, 55 insertions(+)

diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index d008c3973012..005b3909d1dc 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -7,11 +7,58 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <string.h>
+#include <asm/bug.h>
 
 #include "data.h"
 #include "util.h"
 #include "debug.h"
 
+static void close_dir(struct perf_data_file *files, int nr)
+{
+	while (--nr >= 1) {
+		close(files[nr].fd);
+		free(files[nr].path);
+	}
+	free(files);
+}
+
+void perf_data__close_dir(struct perf_data *data)
+{
+	close_dir(data->dir.files, data->dir.nr);
+}
+
+int perf_data__create_dir(struct perf_data *data, int nr)
+{
+	struct perf_data_file *files = NULL;
+	int i, ret = -1;
+
+	files = zalloc(nr * sizeof(*files));
+	if (!files)
+		return -ENOMEM;
+
+	data->dir.files = files;
+	data->dir.nr    = nr;
+
+	for (i = 0; i < nr; i++) {
+		struct perf_data_file *file = &files[i];
+
+		if (asprintf(&file->path, "%s/data.%d", data->path, i) < 0)
+			goto out_err;
+
+		ret = open(file->path, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
+		if (ret < 0)
+			goto out_err;
+
+		file->fd = ret;
+	}
+
+	return 0;
+
+out_err:
+	close_dir(files, i);
+	return ret;
+}
+
 static bool check_pipe(struct perf_data *data)
 {
 	struct stat st;
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
index 2bce28117ccf..2d0d015a7d4d 100644
--- a/tools/perf/util/data.h
+++ b/tools/perf/util/data.h
@@ -21,6 +21,11 @@ struct perf_data {
 	bool			 is_pipe;
 	bool			 force;
 	enum perf_data_mode	 mode;
+
+	struct {
+		struct perf_data_file	*files;
+		int			 nr;
+	} dir;
 };
 
 static inline bool perf_data__is_read(struct perf_data *data)
@@ -64,4 +69,7 @@ ssize_t perf_data_file__write(struct perf_data_file *file,
 int perf_data__switch(struct perf_data *data,
 			   const char *postfix,
 			   size_t pos, bool at_exit);
+
+int perf_data__create_dir(struct perf_data *data, int nr);
+void perf_data__close_dir(struct perf_data *data);
 #endif /* __PERF_DATA_H */
-- 
2.17.2


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

* [PATCH 09/20] perf data: Add perf_data__open_dir_data function
  2019-02-24 19:06 [PATCHv3 00/20] perf record: Add support to store data in directory Jiri Olsa
                   ` (7 preceding siblings ...)
  2019-02-24 19:06 ` [PATCH 08/20] perf data: Add perf_data__(create_dir|close_dir) functions Jiri Olsa
@ 2019-02-24 19:06 ` Jiri Olsa
  2019-02-28  8:04   ` [tip:perf/core] " tip-bot for Jiri Olsa
  2019-02-24 19:06 ` [PATCH 10/20] perf data: Add directory support Jiri Olsa
                   ` (10 subsequent siblings)
  19 siblings, 1 reply; 32+ messages in thread
From: Jiri Olsa @ 2019-02-24 19:06 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Adrian Hunter, Andi Kleen, Stephane Eranian,
	Alexey Budankov

Adding perf_data__open_dir_data to open files inside
struct perf_data path directory:
   static int perf_data__open_dir(struct perf_data *data);

Link: http://lkml.kernel.org/n/tip-sv97z5mh9j273mz2cthzaq4n@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/data.c | 59 ++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/data.h |  1 +
 2 files changed, 60 insertions(+)

diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index 005b3909d1dc..7bd5ddeb7a41 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -8,6 +8,8 @@
 #include <unistd.h>
 #include <string.h>
 #include <asm/bug.h>
+#include <sys/types.h>
+#include <dirent.h>
 
 #include "data.h"
 #include "util.h"
@@ -59,6 +61,63 @@ int perf_data__create_dir(struct perf_data *data, int nr)
 	return ret;
 }
 
+int perf_data__open_dir(struct perf_data *data)
+{
+	struct perf_data_file *files = NULL;
+	struct dirent *dent;
+	int ret = -1;
+	DIR *dir;
+	int nr = 0;
+
+	dir = opendir(data->path);
+	if (!dir)
+		return -EINVAL;
+
+	while ((dent = readdir(dir)) != NULL) {
+		struct perf_data_file *file;
+		char path[PATH_MAX];
+		struct stat st;
+
+		snprintf(path, sizeof(path), "%s/%s", data->path, dent->d_name);
+		if (stat(path, &st))
+			continue;
+
+		if (!S_ISREG(st.st_mode) || strncmp(dent->d_name, "data", 4))
+			continue;
+
+		ret = -ENOMEM;
+
+		file = realloc(files, (nr + 1) * sizeof(*files));
+		if (!file)
+			goto out_err;
+
+		files = file;
+		file = &files[nr++];
+
+		file->path = strdup(path);
+		if (!file->path)
+			goto out_err;
+
+		ret = open(file->path, O_RDONLY);
+		if (ret < 0)
+			goto out_err;
+
+		file->fd = ret;
+		file->size = st.st_size;
+	}
+
+	if (!files)
+		return -EINVAL;
+
+	data->dir.files = files;
+	data->dir.nr    = nr;
+	return 0;
+
+out_err:
+	close_dir(files, nr);
+	return ret;
+}
+
 static bool check_pipe(struct perf_data *data)
 {
 	struct stat st;
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
index 2d0d015a7d4d..14b47be2bd69 100644
--- a/tools/perf/util/data.h
+++ b/tools/perf/util/data.h
@@ -71,5 +71,6 @@ int perf_data__switch(struct perf_data *data,
 			   size_t pos, bool at_exit);
 
 int perf_data__create_dir(struct perf_data *data, int nr);
+int perf_data__open_dir(struct perf_data *data);
 void perf_data__close_dir(struct perf_data *data);
 #endif /* __PERF_DATA_H */
-- 
2.17.2


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

* [PATCH 10/20] perf data: Add directory support
  2019-02-24 19:06 [PATCHv3 00/20] perf record: Add support to store data in directory Jiri Olsa
                   ` (8 preceding siblings ...)
  2019-02-24 19:06 ` [PATCH 09/20] perf data: Add perf_data__open_dir_data function Jiri Olsa
@ 2019-02-24 19:06 ` Jiri Olsa
  2019-02-25 13:45   ` Arnaldo Carvalho de Melo
  2019-02-24 19:06 ` [PATCH 11/20] perf data: Don't store auxtrace index for directory data file Jiri Olsa
                   ` (9 subsequent siblings)
  19 siblings, 1 reply; 32+ messages in thread
From: Jiri Olsa @ 2019-02-24 19:06 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Adrian Hunter, Andi Kleen, Stephane Eranian,
	Alexey Budankov

Adding support to have directory as perf.data.

The caller needs to set 'struct perf_data::is_dir flag
and the path will be treated as directory.

The 'struct perf_data::file' is initialized and open
as 'path/header' file.

Adding check to direcory interface functions to check
on is_dir flag.

Link: http://lkml.kernel.org/n/tip-pvot1aywiem9epgqpfi1agaj@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/data.c    | 41 ++++++++++++++++++++++++++++++++++++++-
 tools/perf/util/data.h    |  6 ++++++
 tools/perf/util/session.c |  4 ++++
 3 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index 7bd5ddeb7a41..72ac4dbb5c69 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -34,6 +34,9 @@ int perf_data__create_dir(struct perf_data *data, int nr)
 	struct perf_data_file *files = NULL;
 	int i, ret = -1;
 
+	if (WARN_ON(!data->is_dir))
+		return -EINVAL;
+
 	files = zalloc(nr * sizeof(*files));
 	if (!files)
 		return -ENOMEM;
@@ -69,6 +72,9 @@ int perf_data__open_dir(struct perf_data *data)
 	DIR *dir;
 	int nr = 0;
 
+	if (WARN_ON(!data->is_dir))
+		return -EINVAL;
+
 	dir = opendir(data->path);
 	if (!dir)
 		return -EINVAL;
@@ -173,6 +179,16 @@ static int check_backup(struct perf_data *data)
 	return 0;
 }
 
+static bool is_dir(struct perf_data *data)
+{
+	struct stat st;
+
+	if (stat(data->path, &st))
+		return false;
+
+	return (st.st_mode & S_IFMT) == S_IFDIR;
+}
+
 static int open_file_read(struct perf_data *data)
 {
 	struct stat st;
@@ -254,6 +270,22 @@ static int open_file_dup(struct perf_data *data)
 	return open_file(data);
 }
 
+static int open_dir(struct perf_data *data)
+{
+	if (perf_data__is_write(data) &&
+	    mkdir(data->path, S_IRWXU) < 0)
+		return -1;
+
+	/*
+	 * So far we open only the header, so we
+	 * can read the data version and layout.
+	 */
+	if (asprintf(&data->file.path, "%s/header", data->path) < 0)
+		return -ENOMEM;
+
+	return open_file(data);
+}
+
 int perf_data__open(struct perf_data *data)
 {
 	if (check_pipe(data))
@@ -265,11 +297,18 @@ int perf_data__open(struct perf_data *data)
 	if (check_backup(data))
 		return -1;
 
-	return open_file_dup(data);
+	if (perf_data__is_read(data))
+		data->is_dir = is_dir(data);
+
+	return perf_data__is_dir(data) ?
+	       open_dir(data) : open_file_dup(data);
 }
 
 void perf_data__close(struct perf_data *data)
 {
+	if (perf_data__is_dir(data))
+		perf_data__close_dir(data);
+
 	free(data->file.path);
 	close(data->file.fd);
 }
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
index 14b47be2bd69..06aefeda311f 100644
--- a/tools/perf/util/data.h
+++ b/tools/perf/util/data.h
@@ -19,6 +19,7 @@ struct perf_data {
 	const char		*path;
 	struct perf_data_file	 file;
 	bool			 is_pipe;
+	bool			 is_dir;
 	bool			 force;
 	enum perf_data_mode	 mode;
 
@@ -43,6 +44,11 @@ static inline int perf_data__is_pipe(struct perf_data *data)
 	return data->is_pipe;
 }
 
+static inline bool perf_data__is_dir(struct perf_data *data)
+{
+	return data->is_dir;
+}
+
 static inline int perf_data__fd(struct perf_data *data)
 {
 	return data->file.fd;
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index c764bbc91009..9991e9a8bc12 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -152,6 +152,10 @@ struct perf_session *perf_session__new(struct perf_data *data,
 			}
 
 			perf_evlist__init_trace_event_sample_raw(session->evlist);
+
+			/* Open the directory data. */
+			if (data->is_dir && perf_data__open_dir(data))
+				goto out_close;
 		}
 	} else  {
 		session->machines.host.env = &perf_env;
-- 
2.17.2


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

* [PATCH 11/20] perf data: Don't store auxtrace index for directory data file
  2019-02-24 19:06 [PATCHv3 00/20] perf record: Add support to store data in directory Jiri Olsa
                   ` (9 preceding siblings ...)
  2019-02-24 19:06 ` [PATCH 10/20] perf data: Add directory support Jiri Olsa
@ 2019-02-24 19:06 ` Jiri Olsa
  2019-02-24 19:06 ` [PATCH 12/20] perf data: Add perf_data__update_dir function Jiri Olsa
                   ` (8 subsequent siblings)
  19 siblings, 0 replies; 32+ messages in thread
From: Jiri Olsa @ 2019-02-24 19:06 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Adrian Hunter, Andi Kleen, Stephane Eranian,
	Alexey Budankov

We can't store auxtrace index when we store to multiple files,
because we keep only offset for it, not the file.

The auxtrace data will be processed correctly in the 'pipe' mode.

Link: http://lkml.kernel.org/n/tip-og11od5s6nfxuf0ftxyu8m6k@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/builtin-record.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index f3f7f3100336..e983c8d71a79 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -392,7 +392,7 @@ static int record__process_auxtrace(struct perf_tool *tool,
 	size_t padding;
 	u8 pad[8] = {0};
 
-	if (!perf_data__is_pipe(data)) {
+	if (!perf_data__is_pipe(data) && !perf_data__is_dir(data)) {
 		off_t file_offset;
 		int fd = perf_data__fd(data);
 		int err;
-- 
2.17.2


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

* [PATCH 12/20] perf data: Add perf_data__update_dir function
  2019-02-24 19:06 [PATCHv3 00/20] perf record: Add support to store data in directory Jiri Olsa
                   ` (10 preceding siblings ...)
  2019-02-24 19:06 ` [PATCH 11/20] perf data: Don't store auxtrace index for directory data file Jiri Olsa
@ 2019-02-24 19:06 ` Jiri Olsa
  2019-02-24 19:06 ` [PATCH 13/20] perf data: Make perf_data__size to work over directory Jiri Olsa
                   ` (7 subsequent siblings)
  19 siblings, 0 replies; 32+ messages in thread
From: Jiri Olsa @ 2019-02-24 19:06 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Adrian Hunter, Andi Kleen, Stephane Eranian,
	Alexey Budankov

Adding perf_data__update_dir function to update
size for every file within the perf.data directory.

Link: http://lkml.kernel.org/n/tip-3ii12l48u4tyvrzxo1797w7e@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/data.c | 20 ++++++++++++++++++++
 tools/perf/util/data.h |  1 +
 2 files changed, 21 insertions(+)

diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index 72ac4dbb5c69..54e4f01aeb2f 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -124,6 +124,26 @@ int perf_data__open_dir(struct perf_data *data)
 	return ret;
 }
 
+int perf_data__update_dir(struct perf_data *data)
+{
+	int i;
+
+	if (WARN_ON(!data->is_dir))
+		return -EINVAL;
+
+	for (i = 0; i < data->dir.nr; i++) {
+		struct perf_data_file *file = &data->dir.files[i];
+		struct stat st;
+
+		if (fstat(file->fd, &st))
+			return -1;
+
+		file->size = st.st_size;
+	}
+
+	return 0;
+}
+
 static bool check_pipe(struct perf_data *data)
 {
 	struct stat st;
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
index 06aefeda311f..0deeb1af9f54 100644
--- a/tools/perf/util/data.h
+++ b/tools/perf/util/data.h
@@ -79,4 +79,5 @@ int perf_data__switch(struct perf_data *data,
 int perf_data__create_dir(struct perf_data *data, int nr);
 int perf_data__open_dir(struct perf_data *data);
 void perf_data__close_dir(struct perf_data *data);
+int perf_data__update_dir(struct perf_data *data);
 #endif /* __PERF_DATA_H */
-- 
2.17.2


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

* [PATCH 13/20] perf data: Make perf_data__size to work over directory
  2019-02-24 19:06 [PATCHv3 00/20] perf record: Add support to store data in directory Jiri Olsa
                   ` (11 preceding siblings ...)
  2019-02-24 19:06 ` [PATCH 12/20] perf data: Add perf_data__update_dir function Jiri Olsa
@ 2019-02-24 19:06 ` Jiri Olsa
  2019-02-24 19:06 ` [PATCH 14/20] perf header: Add DIR_FORMAT feature to describe directory data Jiri Olsa
                   ` (6 subsequent siblings)
  19 siblings, 0 replies; 32+ messages in thread
From: Jiri Olsa @ 2019-02-24 19:06 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Adrian Hunter, Andi Kleen, Stephane Eranian,
	Alexey Budankov

Making perf_data__size to return proper size
for directory data.

Link: http://lkml.kernel.org/n/tip-t4dm8cctat2ginmy2bb08xe8@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/data.c | 17 +++++++++++++++++
 tools/perf/util/data.h |  6 +-----
 2 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index 54e4f01aeb2f..90bda7718bbd 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -385,3 +385,20 @@ int perf_data__switch(struct perf_data *data,
 	free(new_filepath);
 	return ret;
 }
+
+unsigned long perf_data__size(struct perf_data *data)
+{
+	u64 size = data->file.size;
+	int i;
+
+	if (!data->is_dir)
+		return size;
+
+	for (i = 0; i < data->dir.nr; i++) {
+		struct perf_data_file *file = &data->dir.files[i];
+
+		size += file->size;
+	}
+
+	return size;
+}
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
index 0deeb1af9f54..d342469bdfda 100644
--- a/tools/perf/util/data.h
+++ b/tools/perf/util/data.h
@@ -54,11 +54,6 @@ static inline int perf_data__fd(struct perf_data *data)
 	return data->file.fd;
 }
 
-static inline unsigned long perf_data__size(struct perf_data *data)
-{
-	return data->file.size;
-}
-
 int perf_data__open(struct perf_data *data);
 void perf_data__close(struct perf_data *data);
 ssize_t perf_data__write(struct perf_data *data,
@@ -80,4 +75,5 @@ int perf_data__create_dir(struct perf_data *data, int nr);
 int perf_data__open_dir(struct perf_data *data);
 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);
 #endif /* __PERF_DATA_H */
-- 
2.17.2


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

* [PATCH 14/20] perf header: Add DIR_FORMAT feature to describe directory data
  2019-02-24 19:06 [PATCHv3 00/20] perf record: Add support to store data in directory Jiri Olsa
                   ` (12 preceding siblings ...)
  2019-02-24 19:06 ` [PATCH 13/20] perf data: Make perf_data__size to work over directory Jiri Olsa
@ 2019-02-24 19:06 ` Jiri Olsa
  2019-02-24 19:06 ` [PATCH 15/20] perf session: Add process callback to reader object Jiri Olsa
                   ` (5 subsequent siblings)
  19 siblings, 0 replies; 32+ messages in thread
From: Jiri Olsa @ 2019-02-24 19:06 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Adrian Hunter, Andi Kleen, Stephane Eranian,
	Alexey Budankov

The data files layout is described by HEADER_DIR_FORMAT
feature.  Currently it holds only version number (1):

     uint64_t version;

The current version holds only version value (1) means
that data files:
  - follow the 'data.*' name format
  - contain raw events data in standard perf format as
    read from kernel (and need to be sorted)

Future versions are expected to describe different data
files layout according to special needs.

Link: http://lkml.kernel.org/n/tip-6l53s3oabwr1r4n6wke21d8g@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/builtin-record.c |  2 ++
 tools/perf/util/data.c      | 10 +++++++--
 tools/perf/util/data.h      |  1 +
 tools/perf/util/header.c    | 44 ++++++++++++++++++++++++++++++++++++-
 tools/perf/util/header.h    |  5 +++++
 5 files changed, 59 insertions(+), 3 deletions(-)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index e983c8d71a79..a468d882e74f 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -837,6 +837,8 @@ static void record__init_features(struct record *rec)
 	if (!(rec->opts.use_clockid && rec->opts.clockid_res_ns))
 		perf_header__clear_feat(&session->header, HEADER_CLOCKID);
 
+	perf_header__clear_feat(&session->header, HEADER_DIR_FORMAT);
+
 	perf_header__clear_feat(&session->header, HEADER_STAT);
 }
 
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index 90bda7718bbd..b196325ee855 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -14,6 +14,7 @@
 #include "data.h"
 #include "util.h"
 #include "debug.h"
+#include "header.h"
 
 static void close_dir(struct perf_data_file *files, int nr)
 {
@@ -41,8 +42,9 @@ int perf_data__create_dir(struct perf_data *data, int nr)
 	if (!files)
 		return -ENOMEM;
 
-	data->dir.files = files;
-	data->dir.nr    = nr;
+	data->dir.version = PERF_DIR_VERSION;
+	data->dir.files   = files;
+	data->dir.nr      = nr;
 
 	for (i = 0; i < nr; i++) {
 		struct perf_data_file *file = &files[i];
@@ -75,6 +77,10 @@ int perf_data__open_dir(struct perf_data *data)
 	if (WARN_ON(!data->is_dir))
 		return -EINVAL;
 
+	/* The version is provided by DIR_FORMAT feature. */
+	if (WARN_ON(data->dir.version != PERF_DIR_VERSION))
+		return -1;
+
 	dir = opendir(data->path);
 	if (!dir)
 		return -EINVAL;
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
index d342469bdfda..6aef8746469f 100644
--- a/tools/perf/util/data.h
+++ b/tools/perf/util/data.h
@@ -24,6 +24,7 @@ struct perf_data {
 	enum perf_data_mode	 mode;
 
 	struct {
+		u64			 version;
 		struct perf_data_file	*files;
 		int			 nr;
 	} dir;
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index a2323d777dae..4adfbcdc551a 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -867,6 +867,21 @@ static int write_clockid(struct feat_fd *ff,
 			sizeof(ff->ph->env.clockid_res_ns));
 }
 
+static int write_dir_format(struct feat_fd *ff,
+			    struct perf_evlist *evlist __maybe_unused)
+{
+	struct perf_session *session;
+	struct perf_data *data;
+
+	session = container_of(ff->ph, struct perf_session, header);
+	data = session->data;
+
+	if (WARN_ON(!perf_data__is_dir(data)))
+		return -1;
+
+	return do_write(ff, &data->dir.version, sizeof(data->dir.version));
+}
+
 static int cpu_cache_level__sort(const void *a, const void *b)
 {
 	struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a;
@@ -1347,6 +1362,17 @@ static void print_clockid(struct feat_fd *ff, FILE *fp)
 		ff->ph->env.clockid_res_ns * 1000);
 }
 
+static void print_dir_format(struct feat_fd *ff, FILE *fp)
+{
+	struct perf_session *session;
+	struct perf_data *data;
+
+	session = container_of(ff->ph, struct perf_session, header);
+	data = session->data;
+
+	fprintf(fp, "# directory data version : %"PRIu64"\n", data->dir.version);
+}
+
 static void free_event_desc(struct perf_evsel *events)
 {
 	struct perf_evsel *evsel;
@@ -2379,6 +2405,21 @@ static int process_clockid(struct feat_fd *ff,
 	return 0;
 }
 
+static int process_dir_format(struct feat_fd *ff,
+			      void *_data __maybe_unused)
+{
+	struct perf_session *session;
+	struct perf_data *data;
+
+	session = container_of(ff->ph, struct perf_session, header);
+	data = session->data;
+
+	if (WARN_ON(!perf_data__is_dir(data)))
+		return -1;
+
+	return do_read_u64(ff, &data->dir.version);
+}
+
 struct feature_ops {
 	int (*write)(struct feat_fd *ff, struct perf_evlist *evlist);
 	void (*print)(struct feat_fd *ff, FILE *fp);
@@ -2438,7 +2479,8 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
 	FEAT_OPN(CACHE,		cache,		true),
 	FEAT_OPR(SAMPLE_TIME,	sample_time,	false),
 	FEAT_OPR(MEM_TOPOLOGY,	mem_topology,	true),
-	FEAT_OPR(CLOCKID,       clockid,        false)
+	FEAT_OPR(CLOCKID,	clockid,	false),
+	FEAT_OPN(DIR_FORMAT,	dir_format,	false)
 };
 
 struct header_print_data {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 0d553ddca0a3..6a231340238d 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -39,6 +39,7 @@ enum {
 	HEADER_SAMPLE_TIME,
 	HEADER_MEM_TOPOLOGY,
 	HEADER_CLOCKID,
+	HEADER_DIR_FORMAT,
 	HEADER_LAST_FEATURE,
 	HEADER_FEAT_BITS	= 256,
 };
@@ -48,6 +49,10 @@ enum perf_header_version {
 	PERF_HEADER_VERSION_2,
 };
 
+enum perf_dir_version {
+	PERF_DIR_VERSION	= 1,
+};
+
 struct perf_file_section {
 	u64 offset;
 	u64 size;
-- 
2.17.2


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

* [PATCH 15/20] perf session: Add process callback to reader object
  2019-02-24 19:06 [PATCHv3 00/20] perf record: Add support to store data in directory Jiri Olsa
                   ` (13 preceding siblings ...)
  2019-02-24 19:06 ` [PATCH 14/20] perf header: Add DIR_FORMAT feature to describe directory data Jiri Olsa
@ 2019-02-24 19:06 ` Jiri Olsa
  2019-02-24 19:06 ` [PATCH 16/20] perf session: Add __perf_session__process_dir_events function Jiri Olsa
                   ` (4 subsequent siblings)
  19 siblings, 0 replies; 32+ messages in thread
From: Jiri Olsa @ 2019-02-24 19:06 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Adrian Hunter, Andi Kleen, Stephane Eranian,
	Alexey Budankov

Adding callback function to reader object so
callers can process data in different ways.

Link: http://lkml.kernel.org/n/tip-8g1islzz6xkl36tz0z1nkuff@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/session.c | 23 +++++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)

diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 9991e9a8bc12..90cec49903b9 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1849,10 +1849,17 @@ fetch_mmaped_event(struct perf_session *session,
 #define NUM_MMAPS 128
 #endif
 
+struct reader;
+
+typedef s64 (*reader_cb_t)(struct perf_session *session,
+			   union perf_event *event,
+			   u64 file_offset);
+
 struct reader {
-	int	fd;
-	u64	data_size;
-	u64	data_offset;
+	int		 fd;
+	u64		 data_size;
+	u64		 data_offset;
+	reader_cb_t	 process;
 };
 
 static int
@@ -1923,7 +1930,7 @@ reader__process_events(struct reader *rd, struct perf_session *session,
 	size = event->header.size;
 
 	if (size < sizeof(struct perf_event_header) ||
-	    (skip = perf_session__process_event(session, event, file_pos)) < 0) {
+	    (skip = rd->process(session, event, file_pos)) < 0) {
 		pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
 		       file_offset + head, event->header.size,
 		       event->header.type);
@@ -1949,12 +1956,20 @@ reader__process_events(struct reader *rd, struct perf_session *session,
 	return err;
 }
 
+static s64 process_simple(struct perf_session *session,
+			  union perf_event *event,
+			  u64 file_offset)
+{
+	return perf_session__process_event(session, event, file_offset);
+}
+
 static int __perf_session__process_events(struct perf_session *session)
 {
 	struct reader rd = {
 		.fd		= perf_data__fd(session->data),
 		.data_size	= session->header.data_size,
 		.data_offset	= session->header.data_offset,
+		.process	= process_simple,
 	};
 	struct ordered_events *oe = &session->ordered_events;
 	struct perf_tool *tool = session->tool;
-- 
2.17.2


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

* [PATCH 16/20] perf session: Add __perf_session__process_dir_events function
  2019-02-24 19:06 [PATCHv3 00/20] perf record: Add support to store data in directory Jiri Olsa
                   ` (14 preceding siblings ...)
  2019-02-24 19:06 ` [PATCH 15/20] perf session: Add process callback to reader object Jiri Olsa
@ 2019-02-24 19:06 ` Jiri Olsa
  2019-02-24 19:06 ` [PATCH 17/20] perf session: Add path to reader object Jiri Olsa
                   ` (3 subsequent siblings)
  19 siblings, 0 replies; 32+ messages in thread
From: Jiri Olsa @ 2019-02-24 19:06 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Adrian Hunter, Andi Kleen, Stephane Eranian,
	Alexey Budankov

Adding __perf_session__process_dir_events function
to process events over the directory data.

All directory events are pushed into sessions ordered
data and flushed for processing.

Link: http://lkml.kernel.org/n/tip-n3zl0wo3z18tatv5x7epmjrh@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/session.c | 88 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 86 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 90cec49903b9..1f183bd1a208 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1878,8 +1878,6 @@ reader__process_events(struct reader *rd, struct perf_session *session,
 	file_offset = page_offset;
 	head = rd->data_offset - page_offset;
 
-	ui_progress__init_size(prog, data_size, "Processing events...");
-
 	data_size += rd->data_offset;
 
 	mmap_size = MMAP_SIZE;
@@ -2008,6 +2006,89 @@ static int __perf_session__process_events(struct perf_session *session)
 	return err;
 }
 
+static s64 process_index(struct perf_session *session,
+			 union perf_event *event,
+			 u64 file_offset)
+{
+	struct perf_evlist *evlist = session->evlist;
+	u64 timestamp;
+	s64 ret;
+
+	if (session->header.needs_swap)
+		event_swap(event, perf_evlist__sample_id_all(evlist));
+
+	if (event->header.type >= PERF_RECORD_HEADER_MAX)
+		return -EINVAL;
+
+	events_stats__inc(&evlist->stats, event->header.type);
+
+	if (event->header.type >= PERF_RECORD_USER_TYPE_START)
+		return perf_session__process_user_event(session, event, file_offset);
+
+	ret = perf_evlist__parse_sample_timestamp(evlist, event, &timestamp);
+	if (ret)
+		return ret;
+
+	return ordered_events__queue(&session->ordered_events, event,
+				     timestamp, file_offset);
+}
+
+static int __perf_session__process_dir_events(struct perf_session *session)
+{
+	struct perf_data *data = session->data;
+	struct perf_tool *tool = session->tool;
+	struct reader rd = {
+		.fd		= perf_data__fd(session->data),
+		.data_size	= session->header.data_size,
+		.data_offset	= session->header.data_offset,
+		.process	= process_simple,
+	};
+	int i, ret = 0;
+	struct ui_progress prog;
+	u64 total_size = perf_data__size(session->data);
+
+	perf_tool__fill_defaults(tool);
+
+	ui_progress__init_size(&prog, total_size, "Processing events...");
+
+	/* Read data from the header file.. */
+	ret = reader__process_events(&rd, session, &prog);
+	if (ret)
+		goto out_err;
+
+	/* ... and continue with data files. */
+	for (i = 0; i < data->dir.nr ; i++) {
+		struct perf_data_file *file = &data->dir.files[i];
+
+		if (file->size == 0)
+			continue;
+
+		rd = (struct reader) {
+			.fd		= file->fd,
+			.data_size	= file->size,
+			.data_offset	= 0,
+			.process	= process_index,
+		};
+
+		ret = reader__process_events(&rd, session, &prog);
+		if (ret)
+			goto out_err;
+	}
+
+	ret = ordered_events__flush(&session->ordered_events, OE_FLUSH__FINAL);
+
+out_err:
+	if (!tool->no_warn)
+		perf_session__warn_about_errors(session);
+
+	/*
+	 * We may switching perf.data output, make ordered_events
+	 * reusable.
+	 */
+	ordered_events__reinit(&session->ordered_events);
+	return ret;
+}
+
 int perf_session__process_events(struct perf_session *session)
 {
 	if (perf_session__register_idle_thread(session) < 0)
@@ -2016,6 +2097,9 @@ int perf_session__process_events(struct perf_session *session)
 	if (perf_data__is_pipe(session->data))
 		return __perf_session__process_pipe_events(session);
 
+	if (perf_data__is_dir(session->data))
+		return __perf_session__process_dir_events(session);
+
 	return __perf_session__process_events(session);
 }
 
-- 
2.17.2


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

* [PATCH 17/20] perf session: Add path to reader object
  2019-02-24 19:06 [PATCHv3 00/20] perf record: Add support to store data in directory Jiri Olsa
                   ` (15 preceding siblings ...)
  2019-02-24 19:06 ` [PATCH 16/20] perf session: Add __perf_session__process_dir_events function Jiri Olsa
@ 2019-02-24 19:06 ` Jiri Olsa
  2019-02-24 19:06 ` [PATCH 18/20] perf record: Add --dir option to store data in directory Jiri Olsa
                   ` (2 subsequent siblings)
  19 siblings, 0 replies; 32+ messages in thread
From: Jiri Olsa @ 2019-02-24 19:06 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Adrian Hunter, Andi Kleen, Stephane Eranian,
	Alexey Budankov

Adding path to reader object, so we can display file
the processing fails for (string in [] brackets).

  $ perf report --stdio
  0x5e0 [perf.data/data.3] [0xa200]: failed to process type: -1577027574

Link: http://lkml.kernel.org/n/tip-4bjnoy4sln7adqtd3505q29q@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/session.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 1f183bd1a208..c2bc0c58112a 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1860,6 +1860,7 @@ struct reader {
 	u64		 data_size;
 	u64		 data_offset;
 	reader_cb_t	 process;
+	char		*path;
 };
 
 static int
@@ -1874,6 +1875,8 @@ reader__process_events(struct reader *rd, struct perf_session *session,
 	union perf_event *event;
 	s64 skip;
 
+	pr_debug("reader processing %s\n", rd->path);
+
 	page_offset = page_size * (rd->data_offset / page_size);
 	file_offset = page_offset;
 	head = rd->data_offset - page_offset;
@@ -1929,8 +1932,8 @@ reader__process_events(struct reader *rd, struct perf_session *session,
 
 	if (size < sizeof(struct perf_event_header) ||
 	    (skip = rd->process(session, event, file_pos)) < 0) {
-		pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
-		       file_offset + head, event->header.size,
+		pr_err("%#" PRIx64 " [%s] [%#x]: failed to process type: %d\n",
+		       file_offset + head, rd->path, event->header.size,
 		       event->header.type);
 		err = -EINVAL;
 		goto out;
@@ -1968,6 +1971,7 @@ static int __perf_session__process_events(struct perf_session *session)
 		.data_size	= session->header.data_size,
 		.data_offset	= session->header.data_offset,
 		.process	= process_simple,
+		.path		= session->data->file.path,
 	};
 	struct ordered_events *oe = &session->ordered_events;
 	struct perf_tool *tool = session->tool;
@@ -2042,6 +2046,7 @@ static int __perf_session__process_dir_events(struct perf_session *session)
 		.data_size	= session->header.data_size,
 		.data_offset	= session->header.data_offset,
 		.process	= process_simple,
+		.path		= session->data->file.path,
 	};
 	int i, ret = 0;
 	struct ui_progress prog;
@@ -2068,6 +2073,7 @@ static int __perf_session__process_dir_events(struct perf_session *session)
 			.data_size	= file->size,
 			.data_offset	= 0,
 			.process	= process_index,
+			.path		= file->path,
 		};
 
 		ret = reader__process_events(&rd, session, &prog);
-- 
2.17.2


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

* [PATCH 18/20] perf record: Add --dir option to store data in directory
  2019-02-24 19:06 [PATCHv3 00/20] perf record: Add support to store data in directory Jiri Olsa
                   ` (16 preceding siblings ...)
  2019-02-24 19:06 ` [PATCH 17/20] perf session: Add path to reader object Jiri Olsa
@ 2019-02-24 19:06 ` Jiri Olsa
  2019-02-24 19:06 ` [PATCH 19/20] perf record: Add --output-dir " Jiri Olsa
  2019-02-24 19:06 ` [PATCH 20/20] perf record: Describe perf.data directory format Jiri Olsa
  19 siblings, 0 replies; 32+ messages in thread
From: Jiri Olsa @ 2019-02-24 19:06 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Adrian Hunter, Andi Kleen, Stephane Eranian,
	Alexey Budankov

Adding --dir option to store data in directory. It's next
step for multiple threads in record. It's now possible to
make directory data via --dir option, like:

  $ perf record --dir perf bench sched messaging
  $ ls -l perf.data
  total 344
  -rw-------. 1 jolsa jolsa 43864 Jan 20 22:26 data.0
  -rw-------. 1 jolsa jolsa 30464 Jan 20 22:26 data.1
  -rw-------. 1 jolsa jolsa 53816 Jan 20 22:26 data.2
  -rw-------. 1 jolsa jolsa 30368 Jan 20 22:26 data.3
  -rw-------. 1 jolsa jolsa 40088 Jan 20 22:26 data.4
  -rw-------. 1 jolsa jolsa 42592 Jan 20 22:26 data.5
  -rw-------. 1 jolsa jolsa 56136 Jan 20 22:26 data.6
  -rw-------. 1 jolsa jolsa 25992 Jan 20 22:26 data.7
  -rw-------. 1 jolsa jolsa  8832 Jan 20 22:26 header

There's a data file created for every cpu and it's storing
data for those cpu maps.

It's possible to transform directory data into standard
perf.data file via following inject command:

  $ perf inject -o perf.data.file -i perf.data

The --dir option enabled DIR_FORMAT feature to be stored
in header file to indicate the directory layout.

Don't allow to use --dir with --aio yet. It needs
to be investigated first.

Link: http://lkml.kernel.org/n/tip-0kjm8wpglzu2tm18tpagfm4d@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/Documentation/perf-record.txt |  3 +
 tools/perf/builtin-record.c              | 80 ++++++++++++++++++++++--
 tools/perf/util/mmap.h                   | 23 +++----
 3 files changed, 90 insertions(+), 16 deletions(-)

diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 8f0c2be34848..445b7a4eb130 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -524,6 +524,9 @@ config terms. For example: 'cycles/overwrite/' and 'instructions/no-overwrite/'.
 
 Implies --tail-synthesize.
 
+--dir::
+Store data into directory with one data file for cpu.
+
 SEE ALSO
 --------
 linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index a468d882e74f..26981be13aa0 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -112,10 +112,13 @@ static bool switch_output_time(struct record *rec)
 	       trigger_is_ready(&switch_output_trigger);
 }
 
-static int record__write(struct record *rec, struct perf_mmap *map __maybe_unused,
+static int record__write(struct record *rec, struct perf_mmap *map,
 			 void *bf, size_t size)
 {
-	struct perf_data_file *file = &rec->session->data->file;
+	struct perf_data_file *file = &rec->data.file;
+
+	if (map && map->file)
+		file = map->file;
 
 	if (perf_data_file__write(file, bf, size) < 0) {
 		pr_err("failed to write perf data, error: %m\n");
@@ -124,6 +127,15 @@ static int record__write(struct record *rec, struct perf_mmap *map __maybe_unuse
 
 	rec->bytes_written += size;
 
+	/*
+	 * Update header file size manualy, data files size are
+	 * ok to be updated by stat command, but header files
+	 * contains more stuff, so we need to track data size
+	 * manualy.
+	 */
+	if (file == &rec->data.file)
+		rec->session->header.data_size += size;
+
 	if (switch_output_size(rec))
 		trigger_hit(&switch_output_trigger);
 
@@ -247,6 +259,7 @@ static int record__aio_pushfn(void *to, struct aiocb *cblock, void *bf, size_t s
 	ret = record__aio_write(cblock, trace_fd, bf, size, off);
 	if (!ret) {
 		rec->bytes_written += size;
+		rec->session->header.data_size += size;
 		if (switch_output_size(rec))
 			trigger_hit(&switch_output_trigger);
 	}
@@ -564,6 +577,25 @@ static int record__mmap_evlist(struct record *rec,
 	return 0;
 }
 
+static int record__mmap_dir_data(struct record *rec)
+{
+	struct perf_evlist *evlist = rec->evlist;
+	struct perf_data *data = &rec->data;
+	int i, ret, nr = evlist->nr_mmaps;
+
+	ret = perf_data__create_dir(data, nr);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < nr; i++) {
+		struct perf_mmap *map = &evlist->mmap[i];
+
+		map->file = &data->dir.files[i];
+	}
+
+	return 0;
+}
+
 static int record__mmap(struct record *rec)
 {
 	return record__mmap_evlist(rec, rec->evlist);
@@ -793,8 +825,12 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli
 	/*
 	 * Mark the round finished in case we wrote
 	 * at least one event.
+	 *
+	 * No need for round events in directory mode,
+	 * because per-cpu files/maps have sorted data
+	 * from kernel.
 	 */
-	if (bytes_written != rec->bytes_written)
+	if (!perf_data__is_dir(&rec->data) && bytes_written != rec->bytes_written)
 		rc = record__write(rec, NULL, &finished_round_event, sizeof(finished_round_event));
 
 	if (overwrite)
@@ -837,7 +873,8 @@ static void record__init_features(struct record *rec)
 	if (!(rec->opts.use_clockid && rec->opts.clockid_res_ns))
 		perf_header__clear_feat(&session->header, HEADER_CLOCKID);
 
-	perf_header__clear_feat(&session->header, HEADER_DIR_FORMAT);
+	if (!perf_data__is_dir(session->data))
+		perf_header__clear_feat(&session->header, HEADER_DIR_FORMAT);
 
 	perf_header__clear_feat(&session->header, HEADER_STAT);
 }
@@ -851,9 +888,11 @@ record__finish_output(struct record *rec)
 	if (data->is_pipe)
 		return;
 
-	rec->session->header.data_size += rec->bytes_written;
 	data->file.size = lseek(perf_data__fd(data), 0, SEEK_CUR);
 
+	if (perf_data__is_dir(data))
+		perf_data__update_dir(data);
+
 	if (!rec->no_buildid) {
 		process_buildids(rec);
 
@@ -924,6 +963,12 @@ record__switch_output(struct record *rec, bool at_exit)
 
 	/* Output tracking events */
 	if (!at_exit) {
+		if (perf_data__is_dir(data)) {
+			err = record__mmap_dir_data(rec);
+			if (err)
+				return -1;
+		}
+
 		record__synthesize(rec, false);
 
 		/*
@@ -1173,11 +1218,23 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
 	if (data->is_pipe && rec->evlist->nr_entries == 1)
 		rec->opts.sample_id = true;
 
+	if (data->is_pipe && perf_data__is_dir(data)) {
+		pr_err("Directory output is not allowed for pipe output\n");
+		err = -1;
+		goto out_child;
+	}
+
 	if (record__open(rec) != 0) {
 		err = -1;
 		goto out_child;
 	}
 
+	if (perf_data__is_dir(data)) {
+		err = record__mmap_dir_data(rec);
+		if (err)
+			goto out_child;
+	}
+
 	err = bpf__apply_obj_config();
 	if (err) {
 		char errbuf[BUFSIZ];
@@ -1983,6 +2040,8 @@ static struct option __record_options[] = {
 	OPT_CALLBACK(0, "affinity", &record.opts, "node|cpu",
 		     "Set affinity mask of trace reading thread to NUMA node cpu mask or cpu of processed mmap buffer",
 		     record__parse_affinity),
+	OPT_BOOLEAN(0, "dir", &record.data.is_dir,
+		    "Store data into directory perf.data"),
 	OPT_END()
 };
 
@@ -2134,6 +2193,17 @@ int cmd_record(int argc, const char **argv)
 		goto out;
 	}
 
+	if (perf_data__is_dir(&rec->data)) {
+		if (!rec->opts.sample_time) {
+			pr_err("Sample timestamp is required for indexing\n");
+			goto out;
+		}
+		if (record__aio_enabled(rec)) {
+			pr_err("Cannot use both --dir and --aio yet.\n");
+			goto out;
+		}
+	}
+
 	if (rec->opts.target.tid && !rec->opts.no_inherit_set)
 		rec->opts.no_inherit = true;
 
diff --git a/tools/perf/util/mmap.h b/tools/perf/util/mmap.h
index e566c19b242b..3e8595a8d6ce 100644
--- a/tools/perf/util/mmap.h
+++ b/tools/perf/util/mmap.h
@@ -19,17 +19,18 @@ struct aiocb;
  * @refcnt - e.g. code using PERF_EVENT_IOC_SET_OUTPUT to share this
  */
 struct perf_mmap {
-	void		 *base;
-	int		 mask;
-	int		 fd;
-	int		 cpu;
-	refcount_t	 refcnt;
-	u64		 prev;
-	u64		 start;
-	u64		 end;
-	bool		 overwrite;
-	struct auxtrace_mmap auxtrace_mmap;
-	char		 event_copy[PERF_SAMPLE_MAX_SIZE] __aligned(8);
+	void			 *base;
+	int			 mask;
+	int			 fd;
+	int			 cpu;
+	refcount_t		 refcnt;
+	u64			 prev;
+	u64			 start;
+	u64			 end;
+	bool			 overwrite;
+	struct auxtrace_mmap	 auxtrace_mmap;
+	struct perf_data_file	*file;
+	char			 event_copy[PERF_SAMPLE_MAX_SIZE] __aligned(8);
 #ifdef HAVE_AIO_SUPPORT
 	struct {
 		void		 **data;
-- 
2.17.2


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

* [PATCH 19/20] perf record: Add --output-dir option to store data in directory
  2019-02-24 19:06 [PATCHv3 00/20] perf record: Add support to store data in directory Jiri Olsa
                   ` (17 preceding siblings ...)
  2019-02-24 19:06 ` [PATCH 18/20] perf record: Add --dir option to store data in directory Jiri Olsa
@ 2019-02-24 19:06 ` Jiri Olsa
  2019-02-24 19:06 ` [PATCH 20/20] perf record: Describe perf.data directory format Jiri Olsa
  19 siblings, 0 replies; 32+ messages in thread
From: Jiri Olsa @ 2019-02-24 19:06 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Adrian Hunter, Andi Kleen, Stephane Eranian,
	Alexey Budankov

Adding --output-dir option to mimic -o and --dir options.
following commands do the same:

  $ perf record -o perf.dir.data --dir ...
  $ perf record --output-dir perf.dir.data ...

User cannot use both -o and output-dir together,
error is displayed.

Link: http://lkml.kernel.org/n/tip-76ldd2ss6vjvlnjgwy7wxfzt@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/lib/subcmd/parse-options.h         |  4 ++++
 tools/perf/Documentation/perf-record.txt |  3 +++
 tools/perf/builtin-record.c              | 13 +++++++++++--
 3 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/tools/lib/subcmd/parse-options.h b/tools/lib/subcmd/parse-options.h
index af9def589863..8a3be77a3346 100644
--- a/tools/lib/subcmd/parse-options.h
+++ b/tools/lib/subcmd/parse-options.h
@@ -146,6 +146,10 @@ struct option {
 	  .value = check_vtype(v, const char **), .argh = (a), .help = (h), \
 	  .flags = PARSE_OPT_OPTARG, .defval = (intptr_t)(d), \
 	  .set = check_vtype(os, bool *)}
+#define OPT_STRING_SET(s, l, v, os, a, h) \
+	{ .type = OPTION_STRING, .short_name = (s), .long_name = (l), \
+	  .value = check_vtype(v, const char **), .argh = (a), .help = (h), \
+	  .set = check_vtype(os, bool *)}
 #define OPT_STRING_NOEMPTY(s, l, v, a, h)   { .type = OPTION_STRING,  .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), .argh = (a), .help = (h), .flags = PARSE_OPT_NOEMPTY}
 #define OPT_DATE(s, l, v, h) \
 	{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb }
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 445b7a4eb130..aac609887fb7 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -527,6 +527,9 @@ Implies --tail-synthesize.
 --dir::
 Store data into directory with one data file for cpu.
 
+--output-dir::
+Same as --dir option, can't be used together with -o option.
+
 SEE ALSO
 --------
 linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 26981be13aa0..115316e94b34 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -80,6 +80,7 @@ struct record {
 	bool			buildid_all;
 	bool			timestamp_filename;
 	bool			timestamp_boundary;
+	bool			output_is_file;
 	struct switch_output	switch_output;
 	unsigned long long	samples;
 	cpu_set_t		affinity_mask;
@@ -1921,8 +1922,10 @@ static struct option __record_options[] = {
 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
 		    "list of cpus to monitor"),
 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
-	OPT_STRING('o', "output", &record.data.path, "file",
-		    "output file name"),
+	OPT_STRING_SET('o', "output", &record.data.path, &record.output_is_file,
+		       "file", "output file name"),
+	OPT_STRING_SET(0, "output-dir", &record.data.path, &record.data.is_dir,
+		       "file", "output directory name"),
 	OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
 			&record.opts.no_inherit_set,
 			"child tasks do not inherit counters"),
@@ -2101,6 +2104,12 @@ int cmd_record(int argc, const char **argv)
 			"cgroup monitoring only available in system-wide mode");
 
 	}
+
+	if (perf_data__is_dir(&rec->data) && record.output_is_file) {
+		ui__error("cannot use both -o and --output-dir\n");
+		return -EINVAL;
+	}
+
 	if (rec->opts.record_switch_events &&
 	    !perf_can_record_switch_events()) {
 		ui__error("kernel does not support recording context switch events\n");
-- 
2.17.2


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

* [PATCH 20/20] perf record: Describe perf.data directory format
  2019-02-24 19:06 [PATCHv3 00/20] perf record: Add support to store data in directory Jiri Olsa
                   ` (18 preceding siblings ...)
  2019-02-24 19:06 ` [PATCH 19/20] perf record: Add --output-dir " Jiri Olsa
@ 2019-02-24 19:06 ` Jiri Olsa
  19 siblings, 0 replies; 32+ messages in thread
From: Jiri Olsa @ 2019-02-24 19:06 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Adrian Hunter, Andi Kleen, Stephane Eranian,
	Alexey Budankov

Adding perf.data-directory-format.txt to describe the
directory data layout.

Link: http://lkml.kernel.org/n/tip-1c8u1thx63v2ldwfdas4xc5d@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 .../perf.data-directory-format.txt            | 54 +++++++++++++++++++
 1 file changed, 54 insertions(+)
 create mode 100644 tools/perf/Documentation/perf.data-directory-format.txt

diff --git a/tools/perf/Documentation/perf.data-directory-format.txt b/tools/perf/Documentation/perf.data-directory-format.txt
new file mode 100644
index 000000000000..bbd6d31b10c8
--- /dev/null
+++ b/tools/perf/Documentation/perf.data-directory-format.txt
@@ -0,0 +1,54 @@
+perf.data directory format
+
+DISCLAIMER This is not ABI yet and is subject to possible change
+           in following versions of perf. We will remove this
+           disclaimer once the directory format soaks in.
+
+
+This document describes the on-disk perf.data format, generated
+by perf record with --dir option and consumed by the other perf
+tools.
+
+The directory perf.data is created by perf record command by
+using the --dir option:
+
+  $ perf record --dir perf bench sched messaging
+  $ ls -l perf.data
+      total 344
+      -rw-------. 1 jolsa jolsa 43864 Jan 20 22:26 data.0
+      -rw-------. 1 jolsa jolsa 30464 Jan 20 22:26 data.1
+      -rw-------. 1 jolsa jolsa 53816 Jan 20 22:26 data.2
+      -rw-------. 1 jolsa jolsa 30368 Jan 20 22:26 data.3
+      -rw-------. 1 jolsa jolsa 40088 Jan 20 22:26 data.4
+      -rw-------. 1 jolsa jolsa 42592 Jan 20 22:26 data.5
+      -rw-------. 1 jolsa jolsa 56136 Jan 20 22:26 data.6
+      -rw-------. 1 jolsa jolsa 25992 Jan 20 22:26 data.7
+      -rw-------. 1 jolsa jolsa  8832 Jan 20 22:26 header
+
+The header file keeps the standard perf.data file header,
+and the data.* files keep data.
+
+header file
+-----------
+The header file following the standard format describe in
+Documentation/perf.data-file-format doc. Including its data
+portion that is used to store manually synthesized events.
+
+data file
+---------
+The data files layout is described by HEADER_DIR_FORMAT feature.
+Currently it holds only version number (1):
+
+  HEADER_DIR_FORMAT = 24
+
+  struct {
+     uint64_t version;
+  }
+
+The current only only version value 1 means that data files:
+  - follow the 'data.*' format
+  - contain raw events data in standard perf format as read
+    from kernel (and need to be sorted)
+
+Future versions are expected to describe different data files
+layout according to special needs.
-- 
2.17.2


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

* Re: [PATCH 10/20] perf data: Add directory support
  2019-02-24 19:06 ` [PATCH 10/20] perf data: Add directory support Jiri Olsa
@ 2019-02-25 13:45   ` Arnaldo Carvalho de Melo
  2019-02-25 13:56     ` Jiri Olsa
  0 siblings, 1 reply; 32+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-02-25 13:45 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Adrian Hunter, Andi Kleen, Stephane Eranian,
	Alexey Budankov

Em Sun, Feb 24, 2019 at 08:06:46PM +0100, Jiri Olsa escreveu:
> Adding support to have directory as perf.data.
> 
> The caller needs to set 'struct perf_data::is_dir flag
> and the path will be treated as directory.
> 
> The 'struct perf_data::file' is initialized and open
> as 'path/header' file.
> 
> Adding check to direcory interface functions to check
> on is_dir flag.
> 
> Link: http://lkml.kernel.org/n/tip-pvot1aywiem9epgqpfi1agaj@git.kernel.org
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> ---
>  tools/perf/util/data.c    | 41 ++++++++++++++++++++++++++++++++++++++-
>  tools/perf/util/data.h    |  6 ++++++
>  tools/perf/util/session.c |  4 ++++
>  3 files changed, 50 insertions(+), 1 deletion(-)
> 
> diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
> index 7bd5ddeb7a41..72ac4dbb5c69 100644
> --- a/tools/perf/util/data.c
> +++ b/tools/perf/util/data.c
> @@ -34,6 +34,9 @@ int perf_data__create_dir(struct perf_data *data, int nr)
>  	struct perf_data_file *files = NULL;
>  	int i, ret = -1;
>  
> +	if (WARN_ON(!data->is_dir))
> +		return -EINVAL;
> +
>  	files = zalloc(nr * sizeof(*files));
>  	if (!files)
>  		return -ENOMEM;
> @@ -69,6 +72,9 @@ int perf_data__open_dir(struct perf_data *data)
>  	DIR *dir;
>  	int nr = 0;
>  
> +	if (WARN_ON(!data->is_dir))
> +		return -EINVAL;
> +
>  	dir = opendir(data->path);
>  	if (!dir)
>  		return -EINVAL;
> @@ -173,6 +179,16 @@ static int check_backup(struct perf_data *data)
>  	return 0;
>  }
>  
> +static bool is_dir(struct perf_data *data)
> +{
> +	struct stat st;
> +
> +	if (stat(data->path, &st))
> +		return false;
> +
> +	return (st.st_mode & S_IFMT) == S_IFDIR;
> +}
> +
>  static int open_file_read(struct perf_data *data)
>  {
>  	struct stat st;
> @@ -254,6 +270,22 @@ static int open_file_dup(struct perf_data *data)
>  	return open_file(data);
>  }
>  
> +static int open_dir(struct perf_data *data)
> +{
> +	if (perf_data__is_write(data) &&
> +	    mkdir(data->path, S_IRWXU) < 0)
> +		return -1;
> +
> +	/*
> +	 * So far we open only the header, so we
> +	 * can read the data version and layout.
> +	 */
> +	if (asprintf(&data->file.path, "%s/header", data->path) < 0)
> +		return -ENOMEM;

so, if this fails, then we should unwind the mkdir, if it was
performed, so that we leave things as they were before calling
open_dir(), right?

I processed everything up to here.

- Arnaldo

> +
> +	return open_file(data);
> +}
> +
>  int perf_data__open(struct perf_data *data)
>  {
>  	if (check_pipe(data))
> @@ -265,11 +297,18 @@ int perf_data__open(struct perf_data *data)
>  	if (check_backup(data))
>  		return -1;
>  
> -	return open_file_dup(data);
> +	if (perf_data__is_read(data))
> +		data->is_dir = is_dir(data);
> +
> +	return perf_data__is_dir(data) ?
> +	       open_dir(data) : open_file_dup(data);
>  }
>  
>  void perf_data__close(struct perf_data *data)
>  {
> +	if (perf_data__is_dir(data))
> +		perf_data__close_dir(data);
> +
>  	free(data->file.path);
>  	close(data->file.fd);
>  }
> diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
> index 14b47be2bd69..06aefeda311f 100644
> --- a/tools/perf/util/data.h
> +++ b/tools/perf/util/data.h
> @@ -19,6 +19,7 @@ struct perf_data {
>  	const char		*path;
>  	struct perf_data_file	 file;
>  	bool			 is_pipe;
> +	bool			 is_dir;
>  	bool			 force;
>  	enum perf_data_mode	 mode;
>  
> @@ -43,6 +44,11 @@ static inline int perf_data__is_pipe(struct perf_data *data)
>  	return data->is_pipe;
>  }
>  
> +static inline bool perf_data__is_dir(struct perf_data *data)
> +{
> +	return data->is_dir;
> +}
> +
>  static inline int perf_data__fd(struct perf_data *data)
>  {
>  	return data->file.fd;
> diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
> index c764bbc91009..9991e9a8bc12 100644
> --- a/tools/perf/util/session.c
> +++ b/tools/perf/util/session.c
> @@ -152,6 +152,10 @@ struct perf_session *perf_session__new(struct perf_data *data,
>  			}
>  
>  			perf_evlist__init_trace_event_sample_raw(session->evlist);
> +
> +			/* Open the directory data. */
> +			if (data->is_dir && perf_data__open_dir(data))
> +				goto out_close;
>  		}
>  	} else  {
>  		session->machines.host.env = &perf_env;
> -- 
> 2.17.2

-- 

- Arnaldo

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

* Re: [PATCH 10/20] perf data: Add directory support
  2019-02-25 13:45   ` Arnaldo Carvalho de Melo
@ 2019-02-25 13:56     ` Jiri Olsa
  2019-02-25 15:07       ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 32+ messages in thread
From: Jiri Olsa @ 2019-02-25 13:56 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Adrian Hunter, Andi Kleen, Stephane Eranian,
	Alexey Budankov

On Mon, Feb 25, 2019 at 10:45:48AM -0300, Arnaldo Carvalho de Melo wrote:
> Em Sun, Feb 24, 2019 at 08:06:46PM +0100, Jiri Olsa escreveu:
> > Adding support to have directory as perf.data.
> > 
> > The caller needs to set 'struct perf_data::is_dir flag
> > and the path will be treated as directory.
> > 
> > The 'struct perf_data::file' is initialized and open
> > as 'path/header' file.
> > 
> > Adding check to direcory interface functions to check
> > on is_dir flag.
> > 
> > Link: http://lkml.kernel.org/n/tip-pvot1aywiem9epgqpfi1agaj@git.kernel.org
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> > ---
> >  tools/perf/util/data.c    | 41 ++++++++++++++++++++++++++++++++++++++-
> >  tools/perf/util/data.h    |  6 ++++++
> >  tools/perf/util/session.c |  4 ++++
> >  3 files changed, 50 insertions(+), 1 deletion(-)
> > 
> > diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
> > index 7bd5ddeb7a41..72ac4dbb5c69 100644
> > --- a/tools/perf/util/data.c
> > +++ b/tools/perf/util/data.c
> > @@ -34,6 +34,9 @@ int perf_data__create_dir(struct perf_data *data, int nr)
> >  	struct perf_data_file *files = NULL;
> >  	int i, ret = -1;
> >  
> > +	if (WARN_ON(!data->is_dir))
> > +		return -EINVAL;
> > +
> >  	files = zalloc(nr * sizeof(*files));
> >  	if (!files)
> >  		return -ENOMEM;
> > @@ -69,6 +72,9 @@ int perf_data__open_dir(struct perf_data *data)
> >  	DIR *dir;
> >  	int nr = 0;
> >  
> > +	if (WARN_ON(!data->is_dir))
> > +		return -EINVAL;
> > +
> >  	dir = opendir(data->path);
> >  	if (!dir)
> >  		return -EINVAL;
> > @@ -173,6 +179,16 @@ static int check_backup(struct perf_data *data)
> >  	return 0;
> >  }
> >  
> > +static bool is_dir(struct perf_data *data)
> > +{
> > +	struct stat st;
> > +
> > +	if (stat(data->path, &st))
> > +		return false;
> > +
> > +	return (st.st_mode & S_IFMT) == S_IFDIR;
> > +}
> > +
> >  static int open_file_read(struct perf_data *data)
> >  {
> >  	struct stat st;
> > @@ -254,6 +270,22 @@ static int open_file_dup(struct perf_data *data)
> >  	return open_file(data);
> >  }
> >  
> > +static int open_dir(struct perf_data *data)
> > +{
> > +	if (perf_data__is_write(data) &&
> > +	    mkdir(data->path, S_IRWXU) < 0)
> > +		return -1;
> > +
> > +	/*
> > +	 * So far we open only the header, so we
> > +	 * can read the data version and layout.
> > +	 */
> > +	if (asprintf(&data->file.path, "%s/header", data->path) < 0)
> > +		return -ENOMEM;
> 
> so, if this fails, then we should unwind the mkdir, if it was
> performed, so that we leave things as they were before calling
> open_dir(), right?

I think we need to some global solution on this,
currently we also leve halfway screwed perf.data
if we fail in the middle

I think maybe we need to add something on upper (session)
layer to cleanup if we screw up

jirka

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

* Re: [PATCH 10/20] perf data: Add directory support
  2019-02-25 13:56     ` Jiri Olsa
@ 2019-02-25 15:07       ` Arnaldo Carvalho de Melo
  2019-02-25 15:36         ` Jiri Olsa
  0 siblings, 1 reply; 32+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-02-25 15:07 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Jiri Olsa, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Adrian Hunter, Andi Kleen, Stephane Eranian,
	Alexey Budankov

Em Mon, Feb 25, 2019 at 02:56:51PM +0100, Jiri Olsa escreveu:
> On Mon, Feb 25, 2019 at 10:45:48AM -0300, Arnaldo Carvalho de Melo wrote:
> > Em Sun, Feb 24, 2019 at 08:06:46PM +0100, Jiri Olsa escreveu:
> > > Adding support to have directory as perf.data.
> > > 
> > > The caller needs to set 'struct perf_data::is_dir flag
> > > and the path will be treated as directory.
> > > 
> > > The 'struct perf_data::file' is initialized and open
> > > as 'path/header' file.
> > > 
> > > Adding check to direcory interface functions to check
> > > on is_dir flag.
> > > 
> > > Link: http://lkml.kernel.org/n/tip-pvot1aywiem9epgqpfi1agaj@git.kernel.org
> > > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> > > ---
> > >  tools/perf/util/data.c    | 41 ++++++++++++++++++++++++++++++++++++++-
> > >  tools/perf/util/data.h    |  6 ++++++
> > >  tools/perf/util/session.c |  4 ++++
> > >  3 files changed, 50 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
> > > index 7bd5ddeb7a41..72ac4dbb5c69 100644
> > > --- a/tools/perf/util/data.c
> > > +++ b/tools/perf/util/data.c
> > > @@ -34,6 +34,9 @@ int perf_data__create_dir(struct perf_data *data, int nr)
> > >  	struct perf_data_file *files = NULL;
> > >  	int i, ret = -1;
> > >  
> > > +	if (WARN_ON(!data->is_dir))
> > > +		return -EINVAL;
> > > +
> > >  	files = zalloc(nr * sizeof(*files));
> > >  	if (!files)
> > >  		return -ENOMEM;
> > > @@ -69,6 +72,9 @@ int perf_data__open_dir(struct perf_data *data)
> > >  	DIR *dir;
> > >  	int nr = 0;
> > >  
> > > +	if (WARN_ON(!data->is_dir))
> > > +		return -EINVAL;
> > > +
> > >  	dir = opendir(data->path);
> > >  	if (!dir)
> > >  		return -EINVAL;
> > > @@ -173,6 +179,16 @@ static int check_backup(struct perf_data *data)
> > >  	return 0;
> > >  }
> > >  
> > > +static bool is_dir(struct perf_data *data)
> > > +{
> > > +	struct stat st;
> > > +
> > > +	if (stat(data->path, &st))
> > > +		return false;
> > > +
> > > +	return (st.st_mode & S_IFMT) == S_IFDIR;
> > > +}
> > > +
> > >  static int open_file_read(struct perf_data *data)
> > >  {
> > >  	struct stat st;
> > > @@ -254,6 +270,22 @@ static int open_file_dup(struct perf_data *data)
> > >  	return open_file(data);
> > >  }
> > >  
> > > +static int open_dir(struct perf_data *data)
> > > +{
> > > +	if (perf_data__is_write(data) &&
> > > +	    mkdir(data->path, S_IRWXU) < 0)
> > > +		return -1;
> > > +
> > > +	/*
> > > +	 * So far we open only the header, so we
> > > +	 * can read the data version and layout.
> > > +	 */
> > > +	if (asprintf(&data->file.path, "%s/header", data->path) < 0)
> > > +		return -ENOMEM;
> > 
> > so, if this fails, then we should unwind the mkdir, if it was
> > performed, so that we leave things as they were before calling
> > open_dir(), right?
> 
> I think we need to some global solution on this,

If we don't add more, that would be a good thing :-)

The other parts also need to be investigated to see what is best in that
case, but here, undoing the mkdir() if the asprintf() fails is the right
thing to do :-)

- Arnaldo

> currently we also leve halfway screwed perf.data
> if we fail in the middle
> 
> I think maybe we need to add something on upper (session)
> layer to cleanup if we screw up

B

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

* Re: [PATCH 10/20] perf data: Add directory support
  2019-02-25 15:07       ` Arnaldo Carvalho de Melo
@ 2019-02-25 15:36         ` Jiri Olsa
  0 siblings, 0 replies; 32+ messages in thread
From: Jiri Olsa @ 2019-02-25 15:36 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Adrian Hunter, Andi Kleen, Stephane Eranian,
	Alexey Budankov

On Mon, Feb 25, 2019 at 12:07:22PM -0300, Arnaldo Carvalho de Melo wrote:

SNIP

> > > > +}
> > > > +
> > > >  static int open_file_read(struct perf_data *data)
> > > >  {
> > > >  	struct stat st;
> > > > @@ -254,6 +270,22 @@ static int open_file_dup(struct perf_data *data)
> > > >  	return open_file(data);
> > > >  }
> > > >  
> > > > +static int open_dir(struct perf_data *data)
> > > > +{
> > > > +	if (perf_data__is_write(data) &&
> > > > +	    mkdir(data->path, S_IRWXU) < 0)
> > > > +		return -1;
> > > > +
> > > > +	/*
> > > > +	 * So far we open only the header, so we
> > > > +	 * can read the data version and layout.
> > > > +	 */
> > > > +	if (asprintf(&data->file.path, "%s/header", data->path) < 0)
> > > > +		return -ENOMEM;
> > > 
> > > so, if this fails, then we should unwind the mkdir, if it was
> > > performed, so that we leave things as they were before calling
> > > open_dir(), right?
> > 
> > I think we need to some global solution on this,
> 
> If we don't add more, that would be a good thing :-)
> 
> The other parts also need to be investigated to see what is best in that
> case, but here, undoing the mkdir() if the asprintf() fails is the right
> thing to do :-)

true ;-) will resend

thanks,
jirka

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

* [tip:perf/core] perf tools: Add depth checking to rm_rf
  2019-02-24 19:06 ` [PATCH 01/20] perf tools: Add depth checking to rm_rf Jiri Olsa
@ 2019-02-28  8:00   ` tip-bot for Jiri Olsa
  0 siblings, 0 replies; 32+ messages in thread
From: tip-bot for Jiri Olsa @ 2019-02-28  8:00 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: adrian.hunter, ak, linux-kernel, tglx, alexander.shishkin,
	eranian, alexey.budankov, mingo, peterz, jolsa, namhyung, hpa,
	acme

Commit-ID:  05a486593977bfcf71de6bf5cad6d045c18829c6
Gitweb:     https://git.kernel.org/tip/05a486593977bfcf71de6bf5cad6d045c18829c6
Author:     Jiri Olsa <jolsa@kernel.org>
AuthorDate: Sun, 24 Feb 2019 20:06:37 +0100
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Mon, 25 Feb 2019 10:32:11 -0300

perf tools: Add depth checking to rm_rf

Adding depth argument to rm_rf (and renaming it to rm_rf_depth) to
specify the depth we will go searching for files to remove.

It will be used to specify single depth for perf.data directory removal
in following patch.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexey Budankov <alexey.budankov@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/20190224190656.30163-2-jolsa@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/util.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 3ee410fc047a..bcf436892155 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -117,7 +117,12 @@ int mkdir_p(char *path, mode_t mode)
 	return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
 }
 
-int rm_rf(const char *path)
+/*
+ * The depth specify how deep the removal will go.
+ * 0       - will remove only files under the 'path' directory
+ * 1 .. x  - will dive in x-level deep under the 'path' directory
+ */
+static int rm_rf_depth(const char *path, int depth)
 {
 	DIR *dir;
 	int ret;
@@ -155,7 +160,7 @@ int rm_rf(const char *path)
 		}
 
 		if (S_ISDIR(statbuf.st_mode))
-			ret = rm_rf(namebuf);
+			ret = depth ? rm_rf_depth(namebuf, depth - 1) : 0;
 		else
 			ret = unlink(namebuf);
 	}
@@ -167,6 +172,11 @@ int rm_rf(const char *path)
 	return rmdir(path);
 }
 
+int rm_rf(const char *path)
+{
+	return rm_rf_depth(path, INT_MAX);
+}
+
 /* A filter which removes dot files */
 bool lsdir_no_dot_filter(const char *name __maybe_unused, struct dirent *d)
 {

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

* [tip:perf/core] perf tools: Add pattern name checking to rm_rf
  2019-02-24 19:06 ` [PATCH 02/20] perf tools: Add pattern name " Jiri Olsa
@ 2019-02-28  8:00   ` tip-bot for Jiri Olsa
  0 siblings, 0 replies; 32+ messages in thread
From: tip-bot for Jiri Olsa @ 2019-02-28  8:00 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: adrian.hunter, alexander.shishkin, alexey.budankov, eranian,
	linux-kernel, ak, namhyung, peterz, mingo, tglx, jolsa, hpa,
	acme

Commit-ID:  cdb6b0235f170a5ffcd74731178efc064bd4d24a
Gitweb:     https://git.kernel.org/tip/cdb6b0235f170a5ffcd74731178efc064bd4d24a
Author:     Jiri Olsa <jolsa@kernel.org>
AuthorDate: Sun, 24 Feb 2019 20:06:38 +0100
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Mon, 25 Feb 2019 10:33:04 -0300

perf tools: Add pattern name checking to rm_rf

Add pattern argument to rm_rf_depth() (and rename it to rm_rf_depth_pat())
to specify the name pattern files need to match inside the directory.

The function fails if we find different file to remove.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexey Budankov <alexey.budankov@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/20190224190656.30163-3-jolsa@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/util.c | 36 +++++++++++++++++++++++++++++++++---
 1 file changed, 33 insertions(+), 3 deletions(-)

diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index bcf436892155..02b7a38f98ce 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -21,6 +21,7 @@
 #include <linux/time64.h>
 #include <unistd.h>
 #include "strlist.h"
+#include "string2.h"
 
 /*
  * XXX We need to find a better place for these things...
@@ -117,12 +118,38 @@ int mkdir_p(char *path, mode_t mode)
 	return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
 }
 
+static bool match_pat(char *file, const char **pat)
+{
+	int i = 0;
+
+	if (!pat)
+		return true;
+
+	while (pat[i]) {
+		if (strglobmatch(file, pat[i]))
+			return true;
+
+		i++;
+	}
+
+	return false;
+}
+
 /*
  * The depth specify how deep the removal will go.
  * 0       - will remove only files under the 'path' directory
  * 1 .. x  - will dive in x-level deep under the 'path' directory
+ *
+ * If specified the pat is array of string patterns ended with NULL,
+ * which are checked upon every file/directory found. Only matching
+ * ones are removed.
+ *
+ * The function returns:
+ *    0 on success
+ *   -1 on removal failure with errno set
+ *   -2 on pattern failure
  */
-static int rm_rf_depth(const char *path, int depth)
+static int rm_rf_depth_pat(const char *path, int depth, const char **pat)
 {
 	DIR *dir;
 	int ret;
@@ -149,6 +176,9 @@ static int rm_rf_depth(const char *path, int depth)
 		if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
 			continue;
 
+		if (!match_pat(d->d_name, pat))
+			return -2;
+
 		scnprintf(namebuf, sizeof(namebuf), "%s/%s",
 			  path, d->d_name);
 
@@ -160,7 +190,7 @@ static int rm_rf_depth(const char *path, int depth)
 		}
 
 		if (S_ISDIR(statbuf.st_mode))
-			ret = depth ? rm_rf_depth(namebuf, depth - 1) : 0;
+			ret = depth ? rm_rf_depth_pat(namebuf, depth - 1, pat) : 0;
 		else
 			ret = unlink(namebuf);
 	}
@@ -174,7 +204,7 @@ static int rm_rf_depth(const char *path, int depth)
 
 int rm_rf(const char *path)
 {
-	return rm_rf_depth(path, INT_MAX);
+	return rm_rf_depth_pat(path, INT_MAX, NULL);
 }
 
 /* A filter which removes dot files */

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

* [tip:perf/core] perf tools: Add rm_rf_perf_data function
  2019-02-24 19:06 ` [PATCH 03/20] perf tools: Add rm_rf_perf_data function Jiri Olsa
@ 2019-02-28  8:01   ` tip-bot for Jiri Olsa
  0 siblings, 0 replies; 32+ messages in thread
From: tip-bot for Jiri Olsa @ 2019-02-28  8:01 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: alexander.shishkin, alexey.budankov, mingo, acme, namhyung,
	peterz, adrian.hunter, hpa, jolsa, ak, linux-kernel, eranian,
	tglx

Commit-ID:  c69e4c37b37c816c7dbd307a6e7d2d2a5cfe8788
Gitweb:     https://git.kernel.org/tip/c69e4c37b37c816c7dbd307a6e7d2d2a5cfe8788
Author:     Jiri Olsa <jolsa@kernel.org>
AuthorDate: Sun, 24 Feb 2019 20:06:39 +0100
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Mon, 25 Feb 2019 10:33:51 -0300

perf tools: Add rm_rf_perf_data function

To remove perf.data including the directory, with checking on expected
files and no other directories inside.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Suggested-by: Andi Kleen <ak@linux.intel.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexey Budankov <alexey.budankov@linux.intel.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/20190224190656.30163-4-jolsa@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/util.c | 11 +++++++++++
 tools/perf/util/util.h |  1 +
 2 files changed, 12 insertions(+)

diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 02b7a38f98ce..706818693086 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -202,6 +202,17 @@ static int rm_rf_depth_pat(const char *path, int depth, const char **pat)
 	return rmdir(path);
 }
 
+int rm_rf_perf_data(const char *path)
+{
+	const char *pat[] = {
+		"header",
+		"data.*",
+		NULL,
+	};
+
+	return rm_rf_depth_pat(path, 0, pat);
+}
+
 int rm_rf(const char *path)
 {
 	return rm_rf_depth_pat(path, INT_MAX, NULL);
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index ece040b799f6..01c538027c6f 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -31,6 +31,7 @@ struct strlist;
 
 int mkdir_p(char *path, mode_t mode);
 int rm_rf(const char *path);
+int rm_rf_perf_data(const char *path);
 struct strlist *lsdir(const char *name, bool (*filter)(const char *, struct dirent *));
 bool lsdir_no_dot_filter(const char *name, struct dirent *d);
 int copyfile(const char *from, const char *to);

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

* [tip:perf/core] perf data: Make check_backup work over directories
  2019-02-24 19:06 ` [PATCH 06/20] perf data: Make check_backup work over directories Jiri Olsa
@ 2019-02-28  8:02   ` tip-bot for Jiri Olsa
  0 siblings, 0 replies; 32+ messages in thread
From: tip-bot for Jiri Olsa @ 2019-02-28  8:02 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: adrian.hunter, hpa, jolsa, tglx, alexey.budankov, peterz, mingo,
	eranian, namhyung, ak, acme, alexander.shishkin, linux-kernel

Commit-ID:  5021fc4e8c7c3be6f8735eff76fb2520485fcec4
Gitweb:     https://git.kernel.org/tip/5021fc4e8c7c3be6f8735eff76fb2520485fcec4
Author:     Jiri Olsa <jolsa@kernel.org>
AuthorDate: Sun, 24 Feb 2019 20:06:42 +0100
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Mon, 25 Feb 2019 10:35:19 -0300

perf data: Make check_backup work over directories

Change check_backup() to call rm_rf_perf_data() instead of unlink() to
work over directory paths.

Also move the call earlier in the code, before we fork for file/dir, so
it can backup also directory data.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexey Budankov <alexey.budankov@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/20190224190656.30163-7-jolsa@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/data.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index e16d06ed1100..bbf9a299615e 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -37,12 +37,15 @@ static int check_backup(struct perf_data *data)
 {
 	struct stat st;
 
+	if (perf_data__is_read(data))
+		return 0;
+
 	if (!stat(data->path, &st) && st.st_size) {
 		/* TODO check errors properly */
 		char oldname[PATH_MAX];
 		snprintf(oldname, sizeof(oldname), "%s.old",
 			 data->path);
-		unlink(oldname);
+		rm_rf_perf_data(oldname);
 		rename(data->path, oldname);
 	}
 
@@ -95,9 +98,6 @@ static int open_file_write(struct perf_data *data)
 	int fd;
 	char sbuf[STRERR_BUFSIZE];
 
-	if (check_backup(data))
-		return -1;
-
 	fd = open(data->file.path, O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC,
 		  S_IRUSR|S_IWUSR);
 
@@ -141,6 +141,9 @@ int perf_data__open(struct perf_data *data)
 	if (!data->path)
 		data->path = "perf.data";
 
+	if (check_backup(data))
+		return -1;
+
 	return open_file_dup(data);
 }
 

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

* [tip:perf/core] perf data: Fail check_backup in case of error
  2019-02-24 19:06 ` [PATCH 07/20] perf data: Fail check_backup in case of error Jiri Olsa
@ 2019-02-28  8:02   ` tip-bot for Jiri Olsa
  0 siblings, 0 replies; 32+ messages in thread
From: tip-bot for Jiri Olsa @ 2019-02-28  8:02 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: linux-kernel, alexey.budankov, ak, acme, eranian, hpa, namhyung,
	tglx, adrian.hunter, peterz, alexander.shishkin, jolsa, mingo

Commit-ID:  ccb7a71dcea071c7fd68192909c4e54561c88043
Gitweb:     https://git.kernel.org/tip/ccb7a71dcea071c7fd68192909c4e54561c88043
Author:     Jiri Olsa <jolsa@kernel.org>
AuthorDate: Sun, 24 Feb 2019 20:06:43 +0100
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Mon, 25 Feb 2019 10:37:01 -0300

perf data: Fail check_backup in case of error

And display the error message from removing the old data file:

  $ perf record ls
  Can't remove old data: Permission denied (perf.data.old)
  Perf session creation failed.

  $ perf record ls
  Can't remove old data: Unknown file found (perf.data.old)
  Perf session creation failed.

Not sure how to make fail the rename (after we successfully remove the
destination file/dir) to show the message, anyway let's have it there.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexey Budankov <alexey.budankov@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/20190224190656.30163-8-jolsa@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/data.c | 21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index bbf9a299615e..d008c3973012 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -41,12 +41,27 @@ static int check_backup(struct perf_data *data)
 		return 0;
 
 	if (!stat(data->path, &st) && st.st_size) {
-		/* TODO check errors properly */
 		char oldname[PATH_MAX];
+		int ret;
+
 		snprintf(oldname, sizeof(oldname), "%s.old",
 			 data->path);
-		rm_rf_perf_data(oldname);
-		rename(data->path, oldname);
+
+		ret = rm_rf_perf_data(oldname);
+		if (ret) {
+			pr_err("Can't remove old data: %s (%s)\n",
+			       ret == -2 ?
+			       "Unknown file found" : strerror(errno),
+			       oldname);
+			return -1;
+		}
+
+		if (rename(data->path, oldname)) {
+			pr_err("Can't move data: %s (%s to %s)\n",
+			       strerror(errno),
+			       data->path, oldname);
+			return -1;
+		}
 	}
 
 	return 0;

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

* [tip:perf/core] perf data: Add perf_data__(create_dir|close_dir) functions
  2019-02-24 19:06 ` [PATCH 08/20] perf data: Add perf_data__(create_dir|close_dir) functions Jiri Olsa
@ 2019-02-28  8:03   ` tip-bot for Jiri Olsa
  0 siblings, 0 replies; 32+ messages in thread
From: tip-bot for Jiri Olsa @ 2019-02-28  8:03 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: tglx, namhyung, eranian, adrian.hunter, jolsa, mingo, peterz,
	hpa, alexey.budankov, alexander.shishkin, ak, acme, linux-kernel

Commit-ID:  145520631130bd64820b591775733256473eac62
Gitweb:     https://git.kernel.org/tip/145520631130bd64820b591775733256473eac62
Author:     Jiri Olsa <jolsa@kernel.org>
AuthorDate: Sun, 24 Feb 2019 20:06:44 +0100
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Mon, 25 Feb 2019 10:42:05 -0300

perf data: Add perf_data__(create_dir|close_dir) functions

Add perf_data__create_dir() to create nr files inside 'struct perf_data'
path directory:

  int perf_data__create_dir(struct perf_data *data, int nr);

and function to close that data:

  void perf_data__close_dir(struct perf_data *data);

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexey Budankov <alexey.budankov@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/20190224190656.30163-9-jolsa@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/data.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/data.h |  8 ++++++++
 2 files changed, 55 insertions(+)

diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index d008c3973012..005b3909d1dc 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -7,11 +7,58 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <string.h>
+#include <asm/bug.h>
 
 #include "data.h"
 #include "util.h"
 #include "debug.h"
 
+static void close_dir(struct perf_data_file *files, int nr)
+{
+	while (--nr >= 1) {
+		close(files[nr].fd);
+		free(files[nr].path);
+	}
+	free(files);
+}
+
+void perf_data__close_dir(struct perf_data *data)
+{
+	close_dir(data->dir.files, data->dir.nr);
+}
+
+int perf_data__create_dir(struct perf_data *data, int nr)
+{
+	struct perf_data_file *files = NULL;
+	int i, ret = -1;
+
+	files = zalloc(nr * sizeof(*files));
+	if (!files)
+		return -ENOMEM;
+
+	data->dir.files = files;
+	data->dir.nr    = nr;
+
+	for (i = 0; i < nr; i++) {
+		struct perf_data_file *file = &files[i];
+
+		if (asprintf(&file->path, "%s/data.%d", data->path, i) < 0)
+			goto out_err;
+
+		ret = open(file->path, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
+		if (ret < 0)
+			goto out_err;
+
+		file->fd = ret;
+	}
+
+	return 0;
+
+out_err:
+	close_dir(files, i);
+	return ret;
+}
+
 static bool check_pipe(struct perf_data *data)
 {
 	struct stat st;
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
index 2bce28117ccf..2d0d015a7d4d 100644
--- a/tools/perf/util/data.h
+++ b/tools/perf/util/data.h
@@ -21,6 +21,11 @@ struct perf_data {
 	bool			 is_pipe;
 	bool			 force;
 	enum perf_data_mode	 mode;
+
+	struct {
+		struct perf_data_file	*files;
+		int			 nr;
+	} dir;
 };
 
 static inline bool perf_data__is_read(struct perf_data *data)
@@ -64,4 +69,7 @@ ssize_t perf_data_file__write(struct perf_data_file *file,
 int perf_data__switch(struct perf_data *data,
 			   const char *postfix,
 			   size_t pos, bool at_exit);
+
+int perf_data__create_dir(struct perf_data *data, int nr);
+void perf_data__close_dir(struct perf_data *data);
 #endif /* __PERF_DATA_H */

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

* [tip:perf/core] perf data: Add perf_data__open_dir_data function
  2019-02-24 19:06 ` [PATCH 09/20] perf data: Add perf_data__open_dir_data function Jiri Olsa
@ 2019-02-28  8:04   ` tip-bot for Jiri Olsa
  0 siblings, 0 replies; 32+ messages in thread
From: tip-bot for Jiri Olsa @ 2019-02-28  8:04 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: eranian, jolsa, alexey.budankov, tglx, adrian.hunter, acme, ak,
	peterz, mingo, hpa, linux-kernel, namhyung, alexander.shishkin

Commit-ID:  eb6176709b235b96511c7b4745c30412568395c7
Gitweb:     https://git.kernel.org/tip/eb6176709b235b96511c7b4745c30412568395c7
Author:     Jiri Olsa <jolsa@kernel.org>
AuthorDate: Sun, 24 Feb 2019 20:06:45 +0100
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Mon, 25 Feb 2019 10:43:07 -0300

perf data: Add perf_data__open_dir_data function

Add perf_data__open_dir_data to open files inside 'struct perf_data'
path directory:

   static int perf_data__open_dir(struct perf_data *data);

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexey Budankov <alexey.budankov@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/20190224190656.30163-10-jolsa@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/data.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/data.h |  1 +
 2 files changed, 60 insertions(+)

diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index 005b3909d1dc..7bd5ddeb7a41 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -8,6 +8,8 @@
 #include <unistd.h>
 #include <string.h>
 #include <asm/bug.h>
+#include <sys/types.h>
+#include <dirent.h>
 
 #include "data.h"
 #include "util.h"
@@ -59,6 +61,63 @@ out_err:
 	return ret;
 }
 
+int perf_data__open_dir(struct perf_data *data)
+{
+	struct perf_data_file *files = NULL;
+	struct dirent *dent;
+	int ret = -1;
+	DIR *dir;
+	int nr = 0;
+
+	dir = opendir(data->path);
+	if (!dir)
+		return -EINVAL;
+
+	while ((dent = readdir(dir)) != NULL) {
+		struct perf_data_file *file;
+		char path[PATH_MAX];
+		struct stat st;
+
+		snprintf(path, sizeof(path), "%s/%s", data->path, dent->d_name);
+		if (stat(path, &st))
+			continue;
+
+		if (!S_ISREG(st.st_mode) || strncmp(dent->d_name, "data", 4))
+			continue;
+
+		ret = -ENOMEM;
+
+		file = realloc(files, (nr + 1) * sizeof(*files));
+		if (!file)
+			goto out_err;
+
+		files = file;
+		file = &files[nr++];
+
+		file->path = strdup(path);
+		if (!file->path)
+			goto out_err;
+
+		ret = open(file->path, O_RDONLY);
+		if (ret < 0)
+			goto out_err;
+
+		file->fd = ret;
+		file->size = st.st_size;
+	}
+
+	if (!files)
+		return -EINVAL;
+
+	data->dir.files = files;
+	data->dir.nr    = nr;
+	return 0;
+
+out_err:
+	close_dir(files, nr);
+	return ret;
+}
+
 static bool check_pipe(struct perf_data *data)
 {
 	struct stat st;
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
index 2d0d015a7d4d..14b47be2bd69 100644
--- a/tools/perf/util/data.h
+++ b/tools/perf/util/data.h
@@ -71,5 +71,6 @@ int perf_data__switch(struct perf_data *data,
 			   size_t pos, bool at_exit);
 
 int perf_data__create_dir(struct perf_data *data, int nr);
+int perf_data__open_dir(struct perf_data *data);
 void perf_data__close_dir(struct perf_data *data);
 #endif /* __PERF_DATA_H */

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

end of thread, other threads:[~2019-02-28  8:05 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-24 19:06 [PATCHv3 00/20] perf record: Add support to store data in directory Jiri Olsa
2019-02-24 19:06 ` [PATCH 01/20] perf tools: Add depth checking to rm_rf Jiri Olsa
2019-02-28  8:00   ` [tip:perf/core] " tip-bot for Jiri Olsa
2019-02-24 19:06 ` [PATCH 02/20] perf tools: Add pattern name " Jiri Olsa
2019-02-28  8:00   ` [tip:perf/core] " tip-bot for Jiri Olsa
2019-02-24 19:06 ` [PATCH 03/20] perf tools: Add rm_rf_perf_data function Jiri Olsa
2019-02-28  8:01   ` [tip:perf/core] " tip-bot for Jiri Olsa
2019-02-24 19:06 ` [PATCH 04/20] perf data: Move size to struct perf_data_file Jiri Olsa
2019-02-24 19:06 ` [PATCH 05/20] perf data: Add global path holder Jiri Olsa
2019-02-24 19:06 ` [PATCH 06/20] perf data: Make check_backup work over directories Jiri Olsa
2019-02-28  8:02   ` [tip:perf/core] " tip-bot for Jiri Olsa
2019-02-24 19:06 ` [PATCH 07/20] perf data: Fail check_backup in case of error Jiri Olsa
2019-02-28  8:02   ` [tip:perf/core] " tip-bot for Jiri Olsa
2019-02-24 19:06 ` [PATCH 08/20] perf data: Add perf_data__(create_dir|close_dir) functions Jiri Olsa
2019-02-28  8:03   ` [tip:perf/core] " tip-bot for Jiri Olsa
2019-02-24 19:06 ` [PATCH 09/20] perf data: Add perf_data__open_dir_data function Jiri Olsa
2019-02-28  8:04   ` [tip:perf/core] " tip-bot for Jiri Olsa
2019-02-24 19:06 ` [PATCH 10/20] perf data: Add directory support Jiri Olsa
2019-02-25 13:45   ` Arnaldo Carvalho de Melo
2019-02-25 13:56     ` Jiri Olsa
2019-02-25 15:07       ` Arnaldo Carvalho de Melo
2019-02-25 15:36         ` Jiri Olsa
2019-02-24 19:06 ` [PATCH 11/20] perf data: Don't store auxtrace index for directory data file Jiri Olsa
2019-02-24 19:06 ` [PATCH 12/20] perf data: Add perf_data__update_dir function Jiri Olsa
2019-02-24 19:06 ` [PATCH 13/20] perf data: Make perf_data__size to work over directory Jiri Olsa
2019-02-24 19:06 ` [PATCH 14/20] perf header: Add DIR_FORMAT feature to describe directory data Jiri Olsa
2019-02-24 19:06 ` [PATCH 15/20] perf session: Add process callback to reader object Jiri Olsa
2019-02-24 19:06 ` [PATCH 16/20] perf session: Add __perf_session__process_dir_events function Jiri Olsa
2019-02-24 19:06 ` [PATCH 17/20] perf session: Add path to reader object Jiri Olsa
2019-02-24 19:06 ` [PATCH 18/20] perf record: Add --dir option to store data in directory Jiri Olsa
2019-02-24 19:06 ` [PATCH 19/20] perf record: Add --output-dir " Jiri Olsa
2019-02-24 19:06 ` [PATCH 20/20] perf record: Describe perf.data directory format Jiri Olsa

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.