All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCHSET 00/19] perf tools: Introduce new 'ftrace' command (v3)
@ 2013-06-26  7:14 Namhyung Kim
  2013-06-26  7:14 ` [PATCH 01/19] perf util: Move debugfs/tracing helper functions to util.c Namhyung Kim
                   ` (18 more replies)
  0 siblings, 19 replies; 43+ messages in thread
From: Namhyung Kim @ 2013-06-26  7:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, Namhyung Kim, LKML,
	Steven Rostedt, Frederic Weisbecker, Jiri Olsa, David Ahern,
	Stephane Eranian

Hello,

This patchset implements a front-end tool for kernel's ftrace.  It
uses function_graph tracer by default and normal function tracer is
also supported.  (Of course you need to enable those tracers in your
kernel first.)

v3 changes:
 * fix a bug related to pager and forked workload
 * add --clock (-c) option to live and record sub-commands
 * use 'perf' clock if available (Steven)
 * tidy up the output of show sub-command

I pushed it out to 'perf/ftrace-v3' branch on my tree at:

  git://git.kernel.org/pub/scm/linux/kernel/git/namhyung/linux-perf.git


Note that this patchset is based on my previous work.

  https://lkml.org/lkml/2013/6/4/45

Any comments are welcome, thanks,
Namhyung


Namhyung Kim (19):
  perf util: Move debugfs/tracing helper functions to util.c
  perf util: Use evsel->name to get tracepoint_paths
  perf util: Save pid-cmdline mapping into tracing header
  perf util: Add more debug message on failure path
  perf tools: Introduce new 'ftrace' tool
  perf ftrace: Add support for --pid option
  perf ftrace: Add support for -a and -C option
  perf ftrace: Split "live" sub-command
  perf ftrace: Add 'record' sub-command
  perf ftrace: Add 'show' sub-command
  perf ftrace: Add 'report' sub-command
  perf evlist: Enhance perf_evlist__start_workload()
  perf ftrace: Use pager for displaying result
  perf ftrace: Cleanup using ftrace_setup/teardown()
  perf tools: Add document for perf-ftrace command
  perf ftrace: Add a signal handler for SIGSEGV
  perf ftrace: Add --clock option
  perf ftrace: Show leaf-functions as oneliner
  perf ftrace: Tidy up the function graph output of 'show' subcommand

 tools/perf/Documentation/perf-ftrace.txt |  114 ++
 tools/perf/Makefile                      |    1 +
 tools/perf/builtin-ftrace.c              | 1759 ++++++++++++++++++++++++++++++
 tools/perf/builtin.h                     |    1 +
 tools/perf/command-list.txt              |    1 +
 tools/perf/perf.c                        |    1 +
 tools/perf/util/cpumap.c                 |   45 +
 tools/perf/util/cpumap.h                 |    1 +
 tools/perf/util/evlist.c                 |   10 +-
 tools/perf/util/header.c                 |    4 +-
 tools/perf/util/parse-events.c           |   23 +
 tools/perf/util/parse-events.h           |    1 +
 tools/perf/util/trace-event-info.c       |  107 +-
 tools/perf/util/trace-event-parse.c      |   17 +
 tools/perf/util/trace-event-read.c       |   77 +-
 tools/perf/util/trace-event.h            |    1 +
 tools/perf/util/util.c                   |   59 +
 tools/perf/util/util.h                   |    3 +
 18 files changed, 2150 insertions(+), 75 deletions(-)
 create mode 100644 tools/perf/Documentation/perf-ftrace.txt
 create mode 100644 tools/perf/builtin-ftrace.c


Following is the original description and example.
-----
It consists of 4 subcommands: live, record, show and report.

'perf ftrace live' just triggers ftrace and relay kernel buffer
contents to stdout.  It does no processing in the tool side.

'perf ftrace record' starts ftrace and saves its result to per-cpu
files and a perf.header file in the perf.data.dir directory.
Recording was done by multiple threads (a thread per cpu) in order not
to miss events overrun.  The perf.header file is compatible to current
perf.data file and contains useful information and sample data.

The sample data were synthesized for each recorded cpu to provide more
information - I'm not sure it's really needed though.

Once you had run 'perf ftrace record', you could play with other
subcommands.

'perf ftrace show' displays function traces like 'live' subcommand or
trace-cmd does.  It's not useful than them at this time but it could
be improved soon.

'perf ftrace report' displays usual 'perf report' style output from
the function trace data.  You can see which function is called most
frequently for example.  Currently it uses 1 as a period value for
each entry but we might use funcgraph_exit->calltime to get proper
overhead later.

Example below:

  # perf ftrace record sleep 0.1
  # ls -l perf.data.dir
  total 5568
  -rw-r--r--. 1 root root 3514375 Apr 23 16:43 perf.header
  -rw-r--r--. 1 root root   90112 Apr 23 16:43 trace-cpu0.buf
  -rw-r--r--. 1 root root       0 Apr 23 16:43 trace-cpu1.buf
  -rw-r--r--. 1 root root 2093056 Apr 23 16:43 trace-cpu2.buf
  -rw-r--r--. 1 root root       0 Apr 23 16:43 trace-cpu3.buf

  # perf ftrace show
  overriding event (11) ftrace:funcgraph_entry with new print handler
  overriding event (10) ftrace:funcgraph_exit with new print handler
    0)   0.065 us |  __fsnotify_parent();
    0)            |  fsnotify() {
    0)   0.060 us |    __srcu_read_lock();
    0)   0.040 us |    __srcu_read_unlock();
    0)   0.652 us |  }
    0)   0.040 us |  fput();
    0)            |  __audit_syscall_exit() {
    0)            |    path_put() {
    0)   0.037 us |      dput();
    0)   0.032 us |      mntput();
    0)   0.563 us |    }
    0)   0.035 us |    unroll_tree_refs();
    0)   0.035 us |    kfree();
    0)   1.284 us |  }
    0)            |  __audit_syscall_entry() {
    0)   0.029 us |    current_kernel_time();
    0)   0.239 us |  }
    0)            |  sys_write() {
    0)   0.155 us |    fget_light();
    0)            |    vfs_write() {
    0)            |      rw_verify_area() {
    0)            |        security_file_permission() {
    0)            |          selinux_file_permission() {
    0)            |            file_has_perm() {
    0)            |              inode_has_perm.isra.31.constprop.61() {
    0)   0.181 us |                avc_has_perm_flags();
    0)   0.405 us |              }
    0)   0.629 us |            }
    0)   1.024 us |          }
    0)   1.247 us |        }
    0)   1.596 us |      }
    0)            |      do_sync_write() {

  # perf ftrace report
  # ========
  # captured on: Tue Apr 23 16:43:52 2013
  # hostname : sejong.aot.lge.com
  # os release : 3.6.11-5.fc17.x86_64
  # perf version : 3.9.rc8.gceb5f8
  # arch : x86_64
  # nrcpus online : 12
  # nrcpus avail : 12
  # cpudesc : Intel(R) Core(TM) i7-3930K CPU @ 3.20GHz
  # cpuid : GenuineIntel,6,45,7
  # total memory : 32901952 kB
  # cmdline : /home/namhyung/project/linux/tools/perf/perf ftrace record sleep 0.1 
  # event : name = ftrace:funcgraph_entry, type = 2, config = 0xb, config1 = 0x0,
  # event : name = ftrace:funcgraph_exit, type = 2, config = 0xa, config1 = 0x0,
  # HEADER_CPU_TOPOLOGY info available, use -I to display
  # HEADER_NUMA_TOPOLOGY info available, use -I to display
  # ========
  #
  # Samples: 22K of event 'ftrace:funcgraph_entry'
  # Event count (approx.): 22433
  #
  # Overhead  Command      Shared Object                          Symbol
  # ........  .......  .................  ..............................
  #
       7.90%    sleep  [kernel.kallsyms]  [k] _cond_resched                             
       4.57%    sleep  [kernel.kallsyms]  [k] ebitmap_get_bit                           
       3.50%    sleep  [kernel.kallsyms]  [k] __phys_addr                               
       3.12%    sleep  [kernel.kallsyms]  [k] _raw_spin_lock                            
       3.09%    sleep  [kernel.kallsyms]  [k] kmem_cache_free                           
       2.93%    sleep  [kernel.kallsyms]  [k] __slab_free                               
       2.86%    sleep  [kernel.kallsyms]  [k] __tlb_remove_page                         
       2.35%    sleep  [kernel.kallsyms]  [k] vm_normal_page                            
       2.33%    sleep  [kernel.kallsyms]  [k] page_remove_rmap                          
       1.87%    sleep  [kernel.kallsyms]  [k] mutex_unlock               


-- 
1.7.11.7


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

* [PATCH 01/19] perf util: Move debugfs/tracing helper functions to util.c
  2013-06-26  7:14 [PATCHSET 00/19] perf tools: Introduce new 'ftrace' command (v3) Namhyung Kim
@ 2013-06-26  7:14 ` Namhyung Kim
  2013-07-19  7:43   ` [tip:perf/core] perf util: Move debugfs/ tracing " tip-bot for Namhyung Kim
  2013-06-26  7:14 ` [PATCH 02/19] perf util: Use evsel->name to get tracepoint_paths Namhyung Kim
                   ` (17 subsequent siblings)
  18 siblings, 1 reply; 43+ messages in thread
From: Namhyung Kim @ 2013-06-26  7:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, Namhyung Kim, LKML,
	Steven Rostedt, Frederic Weisbecker, Jiri Olsa, David Ahern,
	Stephane Eranian

From: Namhyung Kim <namhyung.kim@lge.com>

Since they're generic helpers move them to util.c so that they can be
used by others.

Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/util/trace-event-info.c | 59 --------------------------------------
 tools/perf/util/util.c             | 59 ++++++++++++++++++++++++++++++++++++++
 tools/perf/util/util.h             |  3 ++
 3 files changed, 62 insertions(+), 59 deletions(-)

diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index e85cbcf298f3..ab18bf12d54a 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -46,65 +46,6 @@
 static int output_fd;
 
 
-static const char *find_debugfs(void)
-{
-	const char *path = perf_debugfs_mount(NULL);
-
-	if (!path)
-		pr_debug("Your kernel does not support the debugfs filesystem");
-
-	return path;
-}
-
-/*
- * Finds the path to the debugfs/tracing
- * Allocates the string and stores it.
- */
-static const char *find_tracing_dir(void)
-{
-	static char *tracing;
-	static int tracing_found;
-	const char *debugfs;
-
-	if (tracing_found)
-		return tracing;
-
-	debugfs = find_debugfs();
-	if (!debugfs)
-		return NULL;
-
-	tracing = malloc(strlen(debugfs) + 9);
-	if (!tracing)
-		return NULL;
-
-	sprintf(tracing, "%s/tracing", debugfs);
-
-	tracing_found = 1;
-	return tracing;
-}
-
-static char *get_tracing_file(const char *name)
-{
-	const char *tracing;
-	char *file;
-
-	tracing = find_tracing_dir();
-	if (!tracing)
-		return NULL;
-
-	file = malloc(strlen(tracing) + strlen(name) + 2);
-	if (!file)
-		return NULL;
-
-	sprintf(file, "%s/%s", tracing, name);
-	return file;
-}
-
-static void put_tracing_file(char *file)
-{
-	free(file);
-}
-
 int bigendian(void)
 {
 	unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0};
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 59d868add275..9a0658405760 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -269,3 +269,62 @@ void perf_debugfs_set_path(const char *mntpt)
 	snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt);
 	set_tracing_events_path(mntpt);
 }
+
+static const char *find_debugfs(void)
+{
+	const char *path = perf_debugfs_mount(NULL);
+
+	if (!path)
+		fprintf(stderr, "Your kernel does not support the debugfs filesystem");
+
+	return path;
+}
+
+/*
+ * Finds the path to the debugfs/tracing
+ * Allocates the string and stores it.
+ */
+const char *find_tracing_dir(void)
+{
+	static char *tracing;
+	static int tracing_found;
+	const char *debugfs;
+
+	if (tracing_found)
+		return tracing;
+
+	debugfs = find_debugfs();
+	if (!debugfs)
+		return NULL;
+
+	tracing = malloc(strlen(debugfs) + 9);
+	if (!tracing)
+		return NULL;
+
+	sprintf(tracing, "%s/tracing", debugfs);
+
+	tracing_found = 1;
+	return tracing;
+}
+
+char *get_tracing_file(const char *name)
+{
+	const char *tracing;
+	char *file;
+
+	tracing = find_tracing_dir();
+	if (!tracing)
+		return NULL;
+
+	file = malloc(strlen(tracing) + strlen(name) + 2);
+	if (!file)
+		return NULL;
+
+	sprintf(file, "%s/%s", tracing, name);
+	return file;
+}
+
+void put_tracing_file(char *file)
+{
+	free(file);
+}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 2732fad03908..cc1574edcd9a 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -80,6 +80,9 @@ extern char buildid_dir[];
 extern char tracing_events_path[];
 extern void perf_debugfs_set_path(const char *mountpoint);
 const char *perf_debugfs_mount(const char *mountpoint);
+const char *find_tracing_dir(void);
+char *get_tracing_file(const char *name);
+void put_tracing_file(char *file);
 
 /* On most systems <limits.h> would have given us this, but
  * not on some systems (e.g. GNU/Hurd).
-- 
1.7.11.7


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

* [PATCH 02/19] perf util: Use evsel->name to get tracepoint_paths
  2013-06-26  7:14 [PATCHSET 00/19] perf tools: Introduce new 'ftrace' command (v3) Namhyung Kim
  2013-06-26  7:14 ` [PATCH 01/19] perf util: Move debugfs/tracing helper functions to util.c Namhyung Kim
@ 2013-06-26  7:14 ` Namhyung Kim
  2013-07-19  7:44   ` [tip:perf/core] perf util: Use evsel-> name " tip-bot for Namhyung Kim
  2013-06-26  7:14 ` [PATCH 03/19] perf util: Save pid-cmdline mapping into tracing header Namhyung Kim
                   ` (16 subsequent siblings)
  18 siblings, 1 reply; 43+ messages in thread
From: Namhyung Kim @ 2013-06-26  7:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, Namhyung Kim, LKML,
	Steven Rostedt, Frederic Weisbecker, Jiri Olsa, David Ahern,
	Stephane Eranian

From: Namhyung Kim <namhyung.kim@lge.com>

Most tracepoint events already have their system and event name in
->name field so that searching whole event tracing directory for each
evsel to match given id is suboptimal.

Factor out this routine into tracepoint_name_to_path().  In case of en
invalid name, it'll try to find path using id again.

Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/util/parse-events.c     | 23 +++++++++++++++++++++++
 tools/perf/util/parse-events.h     |  1 +
 tools/perf/util/trace-event-info.c | 15 +++++++++++++++
 3 files changed, 39 insertions(+)

diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 6c8bb0fb189b..1ae166c9da79 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -217,6 +217,29 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
 	return NULL;
 }
 
+struct tracepoint_path *tracepoint_name_to_path(const char *name)
+{
+	struct tracepoint_path *path = zalloc(sizeof(*path));
+	char *str = strchr(name, ':');
+
+	if (path == NULL || str == NULL) {
+		free(path);
+		return NULL;
+	}
+
+	path->system = strndup(name, str - name);
+	path->name = strdup(str+1);
+
+	if (path->system == NULL || path->name == NULL) {
+		free(path->system);
+		free(path->name);
+		free(path);
+		path = NULL;
+	}
+
+	return path;
+}
+
 const char *event_type(int type)
 {
 	switch (type) {
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 8a4859315fd9..080f7cf25d99 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -23,6 +23,7 @@ struct tracepoint_path {
 };
 
 extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
+extern struct tracepoint_path *tracepoint_name_to_path(const char *name);
 extern bool have_tracepoints(struct list_head *evlist);
 
 const char *event_type(int type);
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index ab18bf12d54a..f3c9e551bd35 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -414,12 +414,27 @@ get_tracepoints_path(struct list_head *pattrs)
 		if (pos->attr.type != PERF_TYPE_TRACEPOINT)
 			continue;
 		++nr_tracepoints;
+
+		if (pos->name) {
+			ppath->next = tracepoint_name_to_path(pos->name);
+			if (ppath->next)
+				goto next;
+
+			if (strchr(pos->name, ':') == NULL)
+				goto try_id;
+
+			goto error;
+		}
+
+try_id:
 		ppath->next = tracepoint_id_to_path(pos->attr.config);
 		if (!ppath->next) {
+error:
 			pr_debug("No memory to alloc tracepoints list\n");
 			put_tracepoints_path(&path);
 			return NULL;
 		}
+next:
 		ppath = ppath->next;
 	}
 
-- 
1.7.11.7


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

* [PATCH 03/19] perf util: Save pid-cmdline mapping into tracing header
  2013-06-26  7:14 [PATCHSET 00/19] perf tools: Introduce new 'ftrace' command (v3) Namhyung Kim
  2013-06-26  7:14 ` [PATCH 01/19] perf util: Move debugfs/tracing helper functions to util.c Namhyung Kim
  2013-06-26  7:14 ` [PATCH 02/19] perf util: Use evsel->name to get tracepoint_paths Namhyung Kim
@ 2013-06-26  7:14 ` Namhyung Kim
  2013-06-26  7:14 ` [PATCH 04/19] perf util: Add more debug message on failure path Namhyung Kim
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 43+ messages in thread
From: Namhyung Kim @ 2013-06-26  7:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, Namhyung Kim, LKML,
	Steven Rostedt, Frederic Weisbecker, Jiri Olsa, David Ahern,
	Stephane Eranian

From: Namhyung Kim <namhyung.kim@lge.com>

Current trace info data lacks the saved cmdline mapping which is
needed for pevent to find out the comm of a task.  Add this and bump
up the version number so that perf can determine its presence when
reading.

This is mostly corresponding to trace.dat file version 6, but still
lacks 4 byte of number of cpus, and 10 bytes of type string - and I
think we don't need those anyway.

Cc: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/util/trace-event-info.c  | 33 ++++++++++++++++++++++++++++++++-
 tools/perf/util/trace-event-parse.c | 17 +++++++++++++++++
 tools/perf/util/trace-event-read.c  | 36 ++++++++++++++++++++++++++++++++++--
 tools/perf/util/trace-event.h       |  1 +
 4 files changed, 84 insertions(+), 3 deletions(-)

diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index f3c9e551bd35..48678ca4c4d6 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -41,7 +41,7 @@
 #include <lk/debugfs.h>
 #include "evsel.h"
 
-#define VERSION "0.5"
+#define VERSION "0.6"
 
 static int output_fd;
 
@@ -390,6 +390,34 @@ out:
 	return err;
 }
 
+static int record_saved_cmdline(void)
+{
+	unsigned int size;
+	char *path;
+	struct stat st;
+	int ret, err = 0;
+
+	path = get_tracing_file("saved_cmdlines");
+	if (!path) {
+		pr_debug("can't get tracing/saved_cmdline");
+		return -ENOMEM;
+	}
+
+	ret = stat(path, &st);
+	if (ret < 0) {
+		/* not found */
+		size = 0;
+		if (write(output_fd, &size, 8) != 8)
+			err = -EIO;
+		goto out;
+	}
+	err = record_file(path, 8);
+
+out:
+	put_tracing_file(path);
+	return err;
+}
+
 static void
 put_tracepoints_path(struct tracepoint_path *tps)
 {
@@ -550,6 +578,9 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
 	if (err)
 		goto out;
 	err = record_ftrace_printk();
+	if (err)
+		goto out;
+	err = record_saved_cmdline();
 
 out:
 	/*
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index fe7a27d67d2b..ef09e4720e04 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -232,6 +232,23 @@ void parse_ftrace_printk(struct pevent *pevent,
 	}
 }
 
+void parse_saved_cmdline(struct pevent *pevent,
+			 char *file, unsigned int size __maybe_unused)
+{
+	char *comm;
+	char *line;
+	char *next = NULL;
+	int pid;
+
+	line = strtok_r(file, "\n", &next);
+	while (line) {
+		sscanf(line, "%d %ms", &pid, &comm);
+		pevent_register_comm(pevent, comm, pid);
+		free(comm);
+		line = strtok_r(NULL, "\n", &next);
+	}
+}
+
 int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size)
 {
 	return pevent_parse_event(pevent, buf, size, "ftrace");
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index f2112270c663..e084e5e654b6 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -343,6 +343,31 @@ static int read_event_files(struct pevent *pevent)
 	return 0;
 }
 
+static int read_saved_cmdline(struct pevent *pevent)
+{
+	unsigned long long size;
+	char *buf;
+
+	/* it can have 0 size */
+	size = read8(pevent);
+	if (!size)
+		return 0;
+
+	buf = malloc(size + 1);
+	if (buf == NULL)
+		return -1;
+
+	if (do_read(buf, size) < 0) {
+		free(buf);
+		return -1;
+	}
+
+	parse_saved_cmdline(pevent, buf, size);
+
+	free(buf);
+	return 0;
+}
+
 ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
 {
 	char buf[BUFSIZ];
@@ -383,10 +408,11 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
 		return -1;
 	if (show_version)
 		printf("version = %s\n", version);
-	free(version);
 
-	if (do_read(buf, 1) < 0)
+	if (do_read(buf, 1) < 0) {
+		free(version);
 		return -1;
+	}
 	file_bigendian = buf[0];
 	host_bigendian = bigendian();
 
@@ -422,6 +448,11 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
 	err = read_ftrace_printk(pevent);
 	if (err)
 		goto out;
+	if (!strcmp(version, "0.6")) {
+		err = read_saved_cmdline(pevent);
+		if (err)
+			goto out;
+	}
 
 	size = trace_data_size;
 	repipe = false;
@@ -438,5 +469,6 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
 out:
 	if (pevent)
 		pevent_free(pevent);
+	free(version);
 	return size;
 }
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 669a64a660d7..bf02af200f9c 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -30,6 +30,7 @@ void *raw_field_ptr(struct event_format *event, const char *name, void *data);
 
 void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size);
 void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size);
+void parse_saved_cmdline(struct pevent *pevent, char *file, unsigned int size);
 
 ssize_t trace_report(int fd, struct pevent **pevent, bool repipe);
 
-- 
1.7.11.7


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

* [PATCH 04/19] perf util: Add more debug message on failure path
  2013-06-26  7:14 [PATCHSET 00/19] perf tools: Introduce new 'ftrace' command (v3) Namhyung Kim
                   ` (2 preceding siblings ...)
  2013-06-26  7:14 ` [PATCH 03/19] perf util: Save pid-cmdline mapping into tracing header Namhyung Kim
@ 2013-06-26  7:14 ` Namhyung Kim
  2013-06-26  7:14 ` [PATCH 05/19] perf tools: Introduce new 'ftrace' tool Namhyung Kim
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 43+ messages in thread
From: Namhyung Kim @ 2013-06-26  7:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, Namhyung Kim, LKML,
	Steven Rostedt, Frederic Weisbecker, Jiri Olsa, David Ahern,
	Stephane Eranian

From: Namhyung Kim <namhyung.kim@lge.com>

It's helpful for debugging on tracing features.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/util/header.c           |  4 ++-
 tools/perf/util/trace-event-read.c | 53 ++++++++++++++++++++++++++------------
 2 files changed, 39 insertions(+), 18 deletions(-)

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 738d3b8d9745..ef9207afd3b8 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -2755,8 +2755,10 @@ static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel,
 	}
 
 	event = pevent_find_event(pevent, evsel->attr.config);
-	if (event == NULL)
+	if (event == NULL) {
+		pr_debug("cannot find event format for %d\n", (int)evsel->attr.config);
 		return -1;
+	}
 
 	if (!evsel->name) {
 		snprintf(bf, sizeof(bf), "%s:%s", event->system, event->name);
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index e084e5e654b6..0e3b3f527320 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -262,39 +262,53 @@ static int read_header_files(struct pevent *pevent)
 
 static int read_ftrace_file(struct pevent *pevent, unsigned long long size)
 {
+	int ret;
 	char *buf;
 
 	buf = malloc(size);
-	if (buf == NULL)
+	if (buf == NULL) {
+		pr_debug("memory allocation failure\n");
 		return -1;
+	}
 
-	if (do_read(buf, size) < 0) {
-		free(buf);
-		return -1;
+	ret = do_read(buf, size);
+	if (ret < 0) {
+		pr_debug("error reading ftrace file.\n");
+		goto out;
 	}
 
-	parse_ftrace_file(pevent, buf, size);
+	ret = parse_ftrace_file(pevent, buf, size);
+	if (ret < 0)
+		pr_debug("error parsing ftrace file.\n");
+out:
 	free(buf);
-	return 0;
+	return ret;
 }
 
 static int read_event_file(struct pevent *pevent, char *sys,
 			    unsigned long long size)
 {
+	int ret;
 	char *buf;
 
 	buf = malloc(size);
-	if (buf == NULL)
+	if (buf == NULL) {
+		pr_debug("memory allocation failure\n");
 		return -1;
+	}
 
-	if (do_read(buf, size) < 0) {
+	ret = do_read(buf, size);
+	if (ret < 0) {
 		free(buf);
-		return -1;
+		goto out;
 	}
 
-	parse_event_file(pevent, buf, size, sys);
+	ret = parse_event_file(pevent, buf, size, sys);
+	if (ret < 0)
+		pr_debug("error parsing event file.\n");
+out:
 	free(buf);
-	return 0;
+	return ret;
 }
 
 static int read_ftrace_files(struct pevent *pevent)
@@ -347,6 +361,7 @@ static int read_saved_cmdline(struct pevent *pevent)
 {
 	unsigned long long size;
 	char *buf;
+	int ret;
 
 	/* it can have 0 size */
 	size = read8(pevent);
@@ -354,18 +369,22 @@ static int read_saved_cmdline(struct pevent *pevent)
 		return 0;
 
 	buf = malloc(size + 1);
-	if (buf == NULL)
+	if (buf == NULL) {
+		pr_debug("memory allocation failure\n");
 		return -1;
+	}
 
-	if (do_read(buf, size) < 0) {
-		free(buf);
-		return -1;
+	ret = do_read(buf, size);
+	if (ret < 0) {
+		pr_debug("error reading saved cmdlines\n");
+		goto out;
 	}
 
 	parse_saved_cmdline(pevent, buf, size);
-
+	ret = 0;
+out:
 	free(buf);
-	return 0;
+	return ret;
 }
 
 ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
-- 
1.7.11.7


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

* [PATCH 05/19] perf tools: Introduce new 'ftrace' tool
  2013-06-26  7:14 [PATCHSET 00/19] perf tools: Introduce new 'ftrace' command (v3) Namhyung Kim
                   ` (3 preceding siblings ...)
  2013-06-26  7:14 ` [PATCH 04/19] perf util: Add more debug message on failure path Namhyung Kim
@ 2013-06-26  7:14 ` Namhyung Kim
  2013-06-26 17:10   ` David Ahern
  2013-06-26  7:14 ` [PATCH 06/19] perf ftrace: Add support for --pid option Namhyung Kim
                   ` (13 subsequent siblings)
  18 siblings, 1 reply; 43+ messages in thread
From: Namhyung Kim @ 2013-06-26  7:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, Namhyung Kim, LKML,
	Steven Rostedt, Frederic Weisbecker, Jiri Olsa, David Ahern,
	Stephane Eranian

From: Namhyung Kim <namhyung.kim@lge.com>

The ftrace command is a simple wrapper of kernel's ftrace
functionality.  It only supports single thread tracing currently and
just reads trace_pipe in text and then write it to stdout.

Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/Makefile         |   1 +
 tools/perf/builtin-ftrace.c | 227 ++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/builtin.h        |   1 +
 tools/perf/command-list.txt |   1 +
 tools/perf/perf.c           |   1 +
 5 files changed, 231 insertions(+)
 create mode 100644 tools/perf/builtin-ftrace.c

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 5b7c6db87fde..cf4d19434519 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -420,6 +420,7 @@ BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o
 BUILTIN_OBJS += $(OUTPUT)builtin-lock.o
 BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o
 BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
+BUILTIN_OBJS += $(OUTPUT)builtin-ftrace.o
 BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o
 BUILTIN_OBJS += $(OUTPUT)builtin-mem.o
 
diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
new file mode 100644
index 000000000000..a3ad246bbf54
--- /dev/null
+++ b/tools/perf/builtin-ftrace.c
@@ -0,0 +1,227 @@
+/*
+ * builtin-ftrace.c
+ *
+ * Copyright (c) 2013  LG Electronics,  Namhyung Kim <namhyung@kernel.org>
+ *
+ * Released under the GPL v2.
+ */
+
+#include "builtin.h"
+#include "perf.h"
+
+#include <unistd.h>
+#include <signal.h>
+
+#include "util/debug.h"
+#include "util/parse-options.h"
+#include "util/evlist.h"
+#include "util/target.h"
+#include "util/thread_map.h"
+
+
+#define DEFAULT_TRACER  "function_graph"
+
+struct perf_ftrace {
+	struct perf_evlist *evlist;
+	struct perf_target target;
+	const char *tracer;
+};
+
+static bool done;
+
+static void sig_handler(int sig __maybe_unused)
+{
+	done = true;
+}
+
+static int write_tracing_file(const char *name, const char *val)
+{
+	char *file;
+	int fd, ret = -1;
+	ssize_t size = strlen(val);
+
+	file = get_tracing_file(name);
+	if (!file) {
+		pr_debug("cannot get tracing file: %s\n", name);
+		return -1;
+	}
+
+	fd = open(file, O_WRONLY);
+	if (fd < 0) {
+		pr_debug("cannot open tracing file: %s\n", name);
+		goto out;
+	}
+
+	if (write(fd, val, size) == size)
+		ret = 0;
+	else
+		pr_debug("write '%s' to tracing/%s failed\n", val, name);
+
+out:
+	put_tracing_file(file);
+	return ret;
+}
+
+static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused)
+{
+	if (write_tracing_file("tracing_on", "0") < 0)
+		return -1;
+
+	if (write_tracing_file("current_tracer", "nop") < 0)
+		return -1;
+
+	if (write_tracing_file("set_ftrace_pid", " ") < 0)
+		return -1;
+
+	return 0;
+}
+
+static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
+{
+	char *trace_file;
+	int trace_fd;
+	char *trace_pid;
+	char buf[4096];
+	struct pollfd pollfd = {
+		.events = POLLIN,
+	};
+
+	if (geteuid() != 0) {
+		pr_err("ftrace only works for root!\n");
+		return -1;
+	}
+
+	if (argc < 1)
+		return -1;
+
+	signal(SIGINT, sig_handler);
+	signal(SIGUSR1, sig_handler);
+	signal(SIGCHLD, sig_handler);
+
+	reset_tracing_files(ftrace);
+
+	/* reset ftrace buffer */
+	if (write_tracing_file("trace", "0") < 0)
+		goto out;
+
+	if (perf_evlist__prepare_workload(ftrace->evlist, &ftrace->target,
+					  argv, false, true) < 0)
+		goto out;
+
+	if (write_tracing_file("current_tracer", ftrace->tracer) < 0) {
+		pr_err("failed to set current_tracer to %s\n", ftrace->tracer);
+		goto out;
+	}
+
+	if (asprintf(&trace_pid, "%d", ftrace->evlist->threads->map[0]) < 0) {
+		pr_err("failed to allocate pid string\n");
+		goto out;
+	}
+
+	if (write_tracing_file("set_ftrace_pid", trace_pid) < 0) {
+		pr_err("failed to set pid: %s\n", trace_pid);
+		goto out_free_pid;
+	}
+
+	trace_file = get_tracing_file("trace_pipe");
+	if (!trace_file) {
+		pr_err("failed to open trace_pipe\n");
+		goto out_free_pid;
+	}
+
+	trace_fd = open(trace_file, O_RDONLY);
+
+	put_tracing_file(trace_file);
+
+	if (trace_fd < 0) {
+		pr_err("failed to open trace_pipe\n");
+		goto out_free_pid;
+	}
+
+	fcntl(trace_fd, F_SETFL, O_NONBLOCK);
+	pollfd.fd = trace_fd;
+
+	if (write_tracing_file("tracing_on", "1") < 0) {
+		pr_err("can't enable tracing\n");
+		goto out_close_fd;
+	}
+
+	perf_evlist__start_workload(ftrace->evlist);
+
+	while (!done) {
+		if (poll(&pollfd, 1, -1) < 0)
+			break;
+
+		if (pollfd.revents & POLLIN) {
+			int n = read(trace_fd, buf, sizeof(buf));
+			if (n < 0)
+				break;
+			if (fwrite(buf, n, 1, stdout) != 1)
+				break;
+		}
+	}
+
+	write_tracing_file("tracing_on", "0");
+
+	/* read remaining buffer contents */
+	while (true) {
+		int n = read(trace_fd, buf, sizeof(buf));
+		if (n <= 0)
+			break;
+		if (fwrite(buf, n, 1, stdout) != 1)
+			break;
+	}
+
+out_close_fd:
+	close(trace_fd);
+out_free_pid:
+	free(trace_pid);
+out:
+	reset_tracing_files(ftrace);
+
+	return done ? 0 : -1;
+}
+
+int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
+{
+	int ret;
+	struct perf_ftrace ftrace = {
+		.target = { .uid = UINT_MAX, },
+	};
+	const char * const ftrace_usage[] = {
+		"perf ftrace [<options>] [<command>]",
+		"perf ftrace [<options>] -- <command> [<options>]",
+		NULL
+	};
+	const struct option ftrace_options[] = {
+	OPT_STRING('t', "tracer", &ftrace.tracer, "tracer",
+		   "tracer to use"),
+	OPT_INCR('v', "verbose", &verbose,
+		 "be more verbose"),
+	OPT_END()
+	};
+
+	argc = parse_options(argc, argv, ftrace_options, ftrace_usage,
+			    PARSE_OPT_STOP_AT_NON_OPTION);
+	if (!argc)
+		usage_with_options(ftrace_usage, ftrace_options);
+
+	ftrace.evlist = perf_evlist__new();
+	if (ftrace.evlist == NULL)
+		return -ENOMEM;
+
+	ret = perf_evlist__create_maps(ftrace.evlist, &ftrace.target);
+	if (ret < 0)
+		goto out_delete_evlist;
+
+	if (ftrace.tracer == NULL)
+		ftrace.tracer = DEFAULT_TRACER;
+
+	ret = __cmd_ftrace(&ftrace, argc, argv);
+
+	perf_evlist__delete_maps(ftrace.evlist);
+out_delete_evlist:
+	perf_evlist__delete(ftrace.evlist);
+
+	return ret;
+}
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index b210d62907e4..55da75c4e990 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -37,6 +37,7 @@ extern int cmd_test(int argc, const char **argv, const char *prefix);
 extern int cmd_trace(int argc, const char **argv, const char *prefix);
 extern int cmd_inject(int argc, const char **argv, const char *prefix);
 extern int cmd_mem(int argc, const char **argv, const char *prefix);
+extern int cmd_ftrace(int argc, const char **argv, const char *prefix);
 
 extern int find_scripts(char **scripts_array, char **scripts_path_array);
 #endif
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 0906fc401c52..c24d76e61bc1 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -9,6 +9,7 @@ perf-buildid-cache		mainporcelain common
 perf-buildid-list		mainporcelain common
 perf-diff			mainporcelain common
 perf-evlist			mainporcelain common
+perf-ftrace			mainporcelain common
 perf-inject			mainporcelain common
 perf-kmem			mainporcelain common
 perf-kvm			mainporcelain common
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 85e1aed95204..8966f4b718b8 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -61,6 +61,7 @@ static struct cmd_struct commands[] = {
 #endif
 	{ "inject",	cmd_inject,	0 },
 	{ "mem",	cmd_mem,	0 },
+	{ "ftrace",	cmd_ftrace,	0 },
 };
 
 struct pager_config {
-- 
1.7.11.7


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

* [PATCH 06/19] perf ftrace: Add support for --pid option
  2013-06-26  7:14 [PATCHSET 00/19] perf tools: Introduce new 'ftrace' command (v3) Namhyung Kim
                   ` (4 preceding siblings ...)
  2013-06-26  7:14 ` [PATCH 05/19] perf tools: Introduce new 'ftrace' tool Namhyung Kim
@ 2013-06-26  7:14 ` Namhyung Kim
  2013-06-26 17:12   ` David Ahern
  2013-07-10 14:18   ` Jiri Olsa
  2013-06-26  7:14 ` [PATCH 07/19] perf ftrace: Add support for -a and -C option Namhyung Kim
                   ` (12 subsequent siblings)
  18 siblings, 2 replies; 43+ messages in thread
From: Namhyung Kim @ 2013-06-26  7:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, Namhyung Kim, LKML,
	Steven Rostedt, Frederic Weisbecker, Jiri Olsa, David Ahern,
	Stephane Eranian

From: Namhyung Kim <namhyung.kim@lge.com>

The -p (--pid) option enables to trace existing process by its pid.

Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/builtin-ftrace.c | 89 ++++++++++++++++++++++++++++++++-------------
 1 file changed, 63 insertions(+), 26 deletions(-)

diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
index a3ad246bbf54..2025161bbaed 100644
--- a/tools/perf/builtin-ftrace.c
+++ b/tools/perf/builtin-ftrace.c
@@ -11,6 +11,7 @@
 
 #include <unistd.h>
 #include <signal.h>
+#include <fcntl.h>
 
 #include "util/debug.h"
 #include "util/parse-options.h"
@@ -34,11 +35,12 @@ static void sig_handler(int sig __maybe_unused)
 	done = true;
 }
 
-static int write_tracing_file(const char *name, const char *val)
+static int __write_tracing_file(const char *name, const char *val, bool append)
 {
 	char *file;
 	int fd, ret = -1;
 	ssize_t size = strlen(val);
+	int flags = O_WRONLY;
 
 	file = get_tracing_file(name);
 	if (!file) {
@@ -46,7 +48,12 @@ static int write_tracing_file(const char *name, const char *val)
 		return -1;
 	}
 
-	fd = open(file, O_WRONLY);
+	if (append)
+		flags |= O_APPEND;
+	else
+		flags |= O_TRUNC;
+
+	fd = open(file, flags);
 	if (fd < 0) {
 		pr_debug("cannot open tracing file: %s\n", name);
 		goto out;
@@ -62,6 +69,16 @@ out:
 	return ret;
 }
 
+static int write_tracing_file(const char *name, const char *val)
+{
+	return __write_tracing_file(name, val, false);
+}
+
+static int append_tracing_file(const char *name, const char *val)
+{
+	return __write_tracing_file(name, val, true);
+}
+
 static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused)
 {
 	if (write_tracing_file("tracing_on", "0") < 0)
@@ -76,11 +93,27 @@ static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused)
 	return 0;
 }
 
+static int set_tracing_pid(struct perf_ftrace *ftrace)
+{
+	int i;
+	char buf[16];
+
+	if (perf_target__has_cpu(&ftrace->target))
+		return 0;
+
+	for (i = 0; i < thread_map__nr(ftrace->evlist->threads); i++) {
+		scnprintf(buf, sizeof(buf), "%d",
+			  ftrace->evlist->threads->map[i]);
+		if (append_tracing_file("set_ftrace_pid", buf) < 0)
+			return -1;
+	}
+	return 0;
+}
+
 static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
 {
 	char *trace_file;
 	int trace_fd;
-	char *trace_pid;
 	char buf[4096];
 	struct pollfd pollfd = {
 		.events = POLLIN,
@@ -91,42 +124,37 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
 		return -1;
 	}
 
-	if (argc < 1)
-		return -1;
-
 	signal(SIGINT, sig_handler);
 	signal(SIGUSR1, sig_handler);
 	signal(SIGCHLD, sig_handler);
 
-	reset_tracing_files(ftrace);
+	if (reset_tracing_files(ftrace) < 0)
+		goto out;
 
 	/* reset ftrace buffer */
 	if (write_tracing_file("trace", "0") < 0)
 		goto out;
 
-	if (perf_evlist__prepare_workload(ftrace->evlist, &ftrace->target,
-					  argv, false, true) < 0)
-		goto out;
-
-	if (write_tracing_file("current_tracer", ftrace->tracer) < 0) {
-		pr_err("failed to set current_tracer to %s\n", ftrace->tracer);
+	if (argc && perf_evlist__prepare_workload(ftrace->evlist,
+						  &ftrace->target,
+						  argv, false, true) < 0) {
 		goto out;
 	}
 
-	if (asprintf(&trace_pid, "%d", ftrace->evlist->threads->map[0]) < 0) {
-		pr_err("failed to allocate pid string\n");
-		goto out;
+	if (set_tracing_pid(ftrace) < 0) {
+		pr_err("failed to set ftrace pid\n");
+		goto out_reset;
 	}
 
-	if (write_tracing_file("set_ftrace_pid", trace_pid) < 0) {
-		pr_err("failed to set pid: %s\n", trace_pid);
-		goto out_free_pid;
+	if (write_tracing_file("current_tracer", ftrace->tracer) < 0) {
+		pr_err("failed to set current_tracer to %s\n", ftrace->tracer);
+		goto out_reset;
 	}
 
 	trace_file = get_tracing_file("trace_pipe");
 	if (!trace_file) {
 		pr_err("failed to open trace_pipe\n");
-		goto out_free_pid;
+		goto out_reset;
 	}
 
 	trace_fd = open(trace_file, O_RDONLY);
@@ -135,7 +163,7 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
 
 	if (trace_fd < 0) {
 		pr_err("failed to open trace_pipe\n");
-		goto out_free_pid;
+		goto out_reset;
 	}
 
 	fcntl(trace_fd, F_SETFL, O_NONBLOCK);
@@ -174,11 +202,9 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
 
 out_close_fd:
 	close(trace_fd);
-out_free_pid:
-	free(trace_pid);
-out:
+out_reset:
 	reset_tracing_files(ftrace);
-
+out:
 	return done ? 0 : -1;
 }
 
@@ -196,6 +222,8 @@ int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
 	const struct option ftrace_options[] = {
 	OPT_STRING('t', "tracer", &ftrace.tracer, "tracer",
 		   "tracer to use"),
+	OPT_STRING('p', "pid", &ftrace.target.tid, "pid",
+		   "trace on existing process id"),
 	OPT_INCR('v', "verbose", &verbose,
 		 "be more verbose"),
 	OPT_END()
@@ -203,9 +231,18 @@ int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
 
 	argc = parse_options(argc, argv, ftrace_options, ftrace_usage,
 			    PARSE_OPT_STOP_AT_NON_OPTION);
-	if (!argc)
+	if (!argc && perf_target__none(&ftrace.target))
 		usage_with_options(ftrace_usage, ftrace_options);
 
+	ret = perf_target__validate(&ftrace.target);
+	if (ret) {
+		char errbuf[512];
+
+		perf_target__strerror(&ftrace.target, ret, errbuf, 512);
+		pr_err("%s\n", errbuf);
+		return -EINVAL;
+	}
+
 	ftrace.evlist = perf_evlist__new();
 	if (ftrace.evlist == NULL)
 		return -ENOMEM;
-- 
1.7.11.7


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

* [PATCH 07/19] perf ftrace: Add support for -a and -C option
  2013-06-26  7:14 [PATCHSET 00/19] perf tools: Introduce new 'ftrace' command (v3) Namhyung Kim
                   ` (5 preceding siblings ...)
  2013-06-26  7:14 ` [PATCH 06/19] perf ftrace: Add support for --pid option Namhyung Kim
@ 2013-06-26  7:14 ` Namhyung Kim
  2013-06-26  7:14 ` [PATCH 08/19] perf ftrace: Split "live" sub-command Namhyung Kim
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 43+ messages in thread
From: Namhyung Kim @ 2013-06-26  7:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, Namhyung Kim, LKML,
	Steven Rostedt, Frederic Weisbecker, Jiri Olsa, David Ahern,
	Stephane Eranian

From: Namhyung Kim <namhyung.kim@lge.com>

The -a/--all-cpus and -C/--cpu option is for controlling tracing cpus.
To do that, add and use cpu_map__sprintf() function.

Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/builtin-ftrace.c | 69 +++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/cpumap.c    | 45 +++++++++++++++++++++++++++++
 tools/perf/util/cpumap.h    |  1 +
 3 files changed, 115 insertions(+)

diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
index 2025161bbaed..efe907e4bd56 100644
--- a/tools/perf/builtin-ftrace.c
+++ b/tools/perf/builtin-ftrace.c
@@ -18,6 +18,7 @@
 #include "util/evlist.h"
 #include "util/target.h"
 #include "util/thread_map.h"
+#include "util/cpumap.h"
 
 
 #define DEFAULT_TRACER  "function_graph"
@@ -79,6 +80,8 @@ static int append_tracing_file(const char *name, const char *val)
 	return __write_tracing_file(name, val, true);
 }
 
+static int reset_tracing_cpu(void);
+
 static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused)
 {
 	if (write_tracing_file("tracing_on", "0") < 0)
@@ -90,6 +93,9 @@ static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused)
 	if (write_tracing_file("set_ftrace_pid", " ") < 0)
 		return -1;
 
+	if (reset_tracing_cpu() < 0)
+		return -1;
+
 	return 0;
 }
 
@@ -110,6 +116,60 @@ static int set_tracing_pid(struct perf_ftrace *ftrace)
 	return 0;
 }
 
+static int set_tracing_cpu(struct perf_ftrace *ftrace)
+{
+	char *cpumask;
+	size_t mask_size;
+	int ret;
+	int last_cpu;
+	struct cpu_map *cpumap = ftrace->evlist->cpus;
+
+	if (!perf_target__has_cpu(&ftrace->target))
+		return 0;
+
+	last_cpu = cpumap->map[cpumap->nr - 1];
+	mask_size = (last_cpu + 3) / 4 + 1;
+	mask_size += last_cpu / 32; /* ',' is needed for every 32th cpus */
+
+	cpumask = malloc(mask_size);
+	if (cpumask == NULL) {
+		pr_debug("failed to allocate cpu mask\n");
+		return -1;
+	}
+
+	cpu_map__sprintf(cpumap, cpumask);
+
+	ret = write_tracing_file("tracing_cpumask", cpumask);
+
+	free(cpumask);
+	return ret;
+}
+
+static int reset_tracing_cpu(void)
+{
+	char *cpumask;
+	size_t mask_size;
+	int last_cpu;
+	struct cpu_map *cpumap = cpu_map__new(NULL);
+
+	last_cpu = cpumap->map[cpumap->nr - 1];
+	mask_size = (last_cpu + 3) / 4 + 1;
+	mask_size += last_cpu / 32; /* ',' is needed for every 32th cpus */
+
+	cpumask = malloc(mask_size);
+	if (cpumask == NULL) {
+		pr_debug("failed to allocate cpu mask\n");
+		return -1;
+	}
+
+	cpu_map__sprintf(cpumap, cpumask);
+
+	write_tracing_file("tracing_cpumask", cpumask);
+
+	free(cpumask);
+	return 0;
+}
+
 static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
 {
 	char *trace_file;
@@ -146,6 +206,11 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
 		goto out_reset;
 	}
 
+	if (set_tracing_cpu(ftrace) < 0) {
+		pr_err("failed to set tracing cpumask\n");
+		goto out_reset;
+	}
+
 	if (write_tracing_file("current_tracer", ftrace->tracer) < 0) {
 		pr_err("failed to set current_tracer to %s\n", ftrace->tracer);
 		goto out_reset;
@@ -226,6 +291,10 @@ int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
 		   "trace on existing process id"),
 	OPT_INCR('v', "verbose", &verbose,
 		 "be more verbose"),
+	OPT_BOOLEAN('a', "all-cpus", &ftrace.target.system_wide,
+		    "system-wide collection from all CPUs"),
+	OPT_STRING('C', "cpu", &ftrace.target.cpu_list, "cpu",
+		    "list of cpus to monitor"),
 	OPT_END()
 	};
 
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index beb8cf9f9976..7933839915ea 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -187,6 +187,51 @@ size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp)
 	return printed + fprintf(fp, "\n");
 }
 
+static char hex_char(char val)
+{
+	if (0 <= val && val <= 9)
+		return val + '0';
+	if (10 <= val && val < 16)
+		return val - 10 + 'a';
+	return '?';
+}
+
+size_t cpu_map__sprintf(struct cpu_map *map, char *buf)
+{
+	int i, cpu;
+	char *ptr = buf;
+	unsigned char *bitmap;
+	int last_cpu = map->map[map->nr - 1];
+
+	bitmap = zalloc((last_cpu + 7) / 8);
+	if (bitmap == NULL) {
+		buf[0] = '\0';
+		return 0;
+	}
+
+	for (i = 0; i < map->nr; i++) {
+		cpu = map->map[i];
+		bitmap[cpu / 8] |= 1 << (cpu % 8);
+	}
+
+	for (cpu = last_cpu / 4 * 4; cpu >= 0; cpu -= 4) {
+		unsigned char bits = bitmap[cpu / 8];
+
+		if (cpu % 8)
+			bits >>= 4;
+		else
+			bits &= 0xf;
+
+		*ptr++ = hex_char(bits);
+		if ((cpu % 32) == 0 && cpu > 0)
+			*ptr++ = ',';
+	}
+	*ptr++ = '\0';
+
+	free(bitmap);
+	return ptr - buf;
+}
+
 struct cpu_map *cpu_map__dummy_new(void)
 {
 	struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int));
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index b123bb9d6f55..a9a7f19f89d7 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -14,6 +14,7 @@ struct cpu_map *cpu_map__dummy_new(void);
 void cpu_map__delete(struct cpu_map *map);
 struct cpu_map *cpu_map__read(FILE *file);
 size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
+size_t cpu_map__sprintf(struct cpu_map *map, char *buf);
 int cpu_map__get_socket(struct cpu_map *map, int idx);
 int cpu_map__get_core(struct cpu_map *map, int idx);
 int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp);
-- 
1.7.11.7


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

* [PATCH 08/19] perf ftrace: Split "live" sub-command
  2013-06-26  7:14 [PATCHSET 00/19] perf tools: Introduce new 'ftrace' command (v3) Namhyung Kim
                   ` (6 preceding siblings ...)
  2013-06-26  7:14 ` [PATCH 07/19] perf ftrace: Add support for -a and -C option Namhyung Kim
@ 2013-06-26  7:14 ` Namhyung Kim
  2013-06-26  7:14 ` [PATCH 09/19] perf ftrace: Add 'record' sub-command Namhyung Kim
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 43+ messages in thread
From: Namhyung Kim @ 2013-06-26  7:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, Namhyung Kim, LKML,
	Steven Rostedt, Frederic Weisbecker, Jiri Olsa, David Ahern,
	Stephane Eranian

From: Namhyung Kim <namhyung.kim@lge.com>

Separate out the default behavior to "live" subcommand.  It's a
preparation to support more subcommands like "record" and "report".

Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/builtin-ftrace.c | 109 +++++++++++++++++++++++++++-----------------
 1 file changed, 68 insertions(+), 41 deletions(-)

diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
index efe907e4bd56..4ec96413d3a5 100644
--- a/tools/perf/builtin-ftrace.c
+++ b/tools/perf/builtin-ftrace.c
@@ -170,7 +170,7 @@ static int reset_tracing_cpu(void)
 	return 0;
 }
 
-static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
+static int do_ftrace_live(struct perf_ftrace *ftrace)
 {
 	char *trace_file;
 	int trace_fd;
@@ -179,11 +179,6 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
 		.events = POLLIN,
 	};
 
-	if (geteuid() != 0) {
-		pr_err("ftrace only works for root!\n");
-		return -1;
-	}
-
 	signal(SIGINT, sig_handler);
 	signal(SIGUSR1, sig_handler);
 	signal(SIGCHLD, sig_handler);
@@ -195,12 +190,6 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
 	if (write_tracing_file("trace", "0") < 0)
 		goto out;
 
-	if (argc && perf_evlist__prepare_workload(ftrace->evlist,
-						  &ftrace->target,
-						  argv, false, true) < 0) {
-		goto out;
-	}
-
 	if (set_tracing_pid(ftrace) < 0) {
 		pr_err("failed to set ftrace pid\n");
 		goto out_reset;
@@ -273,61 +262,99 @@ out:
 	return done ? 0 : -1;
 }
 
-int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
+static int
+__cmd_ftrace_live(struct perf_ftrace *ftrace, int argc, const char **argv)
 {
-	int ret;
-	struct perf_ftrace ftrace = {
-		.target = { .uid = UINT_MAX, },
-	};
-	const char * const ftrace_usage[] = {
-		"perf ftrace [<options>] [<command>]",
-		"perf ftrace [<options>] -- <command> [<options>]",
+	int ret = -1;
+	const char * const live_usage[] = {
+		"perf ftrace live [<options>] [<command>]",
+		"perf ftrace live [<options>] -- <command> [<options>]",
 		NULL
 	};
-	const struct option ftrace_options[] = {
-	OPT_STRING('t', "tracer", &ftrace.tracer, "tracer",
+	const struct option live_options[] = {
+	OPT_STRING('t', "tracer", &ftrace->tracer, "tracer",
 		   "tracer to use"),
-	OPT_STRING('p', "pid", &ftrace.target.tid, "pid",
+	OPT_STRING('p', "pid", &ftrace->target.tid, "pid",
 		   "trace on existing process id"),
 	OPT_INCR('v', "verbose", &verbose,
 		 "be more verbose"),
-	OPT_BOOLEAN('a', "all-cpus", &ftrace.target.system_wide,
+	OPT_BOOLEAN('a', "all-cpus", &ftrace->target.system_wide,
 		    "system-wide collection from all CPUs"),
-	OPT_STRING('C', "cpu", &ftrace.target.cpu_list, "cpu",
+	OPT_STRING('C', "cpu", &ftrace->target.cpu_list, "cpu",
 		    "list of cpus to monitor"),
 	OPT_END()
 	};
 
-	argc = parse_options(argc, argv, ftrace_options, ftrace_usage,
-			    PARSE_OPT_STOP_AT_NON_OPTION);
-	if (!argc && perf_target__none(&ftrace.target))
-		usage_with_options(ftrace_usage, ftrace_options);
+	argc = parse_options(argc, argv, live_options, live_usage,
+			     PARSE_OPT_STOP_AT_NON_OPTION);
+	if (!argc && perf_target__none(&ftrace->target))
+		usage_with_options(live_usage, live_options);
 
-	ret = perf_target__validate(&ftrace.target);
+	ret = perf_target__validate(&ftrace->target);
 	if (ret) {
 		char errbuf[512];
 
-		perf_target__strerror(&ftrace.target, ret, errbuf, 512);
+		perf_target__strerror(&ftrace->target, ret, errbuf, 512);
 		pr_err("%s\n", errbuf);
 		return -EINVAL;
 	}
 
-	ftrace.evlist = perf_evlist__new();
-	if (ftrace.evlist == NULL)
+	ftrace->evlist = perf_evlist__new();
+	if (ftrace->evlist == NULL)
 		return -ENOMEM;
 
-	ret = perf_evlist__create_maps(ftrace.evlist, &ftrace.target);
+	ret = perf_evlist__create_maps(ftrace->evlist, &ftrace->target);
 	if (ret < 0)
-		goto out_delete_evlist;
+		goto out;
 
-	if (ftrace.tracer == NULL)
-		ftrace.tracer = DEFAULT_TRACER;
+	if (ftrace->tracer == NULL)
+		ftrace->tracer = DEFAULT_TRACER;
 
-	ret = __cmd_ftrace(&ftrace, argc, argv);
+	if (argc && perf_evlist__prepare_workload(ftrace->evlist,
+						  &ftrace->target,
+						  argv, false, true) < 0)
+		goto out_maps;
+
+	ret = do_ftrace_live(ftrace);
 
-	perf_evlist__delete_maps(ftrace.evlist);
-out_delete_evlist:
-	perf_evlist__delete(ftrace.evlist);
+out_maps:
+	perf_evlist__delete_maps(ftrace->evlist);
+out:
+	perf_evlist__delete(ftrace->evlist);
+
+	return ret;
+}
+
+int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
+{
+	int ret;
+	struct perf_ftrace ftrace = {
+		.target = { .uid = UINT_MAX, },
+	};
+	const char * const ftrace_usage[] = {
+		"perf ftrace {live} [<options>] [<command>]",
+		"perf ftrace {live} [<options>] -- <command> [<options>]",
+		NULL
+	};
+	const struct option ftrace_options[] = {
+	OPT_END()
+	};
+
+	argc = parse_options(argc, argv, ftrace_options, ftrace_usage,
+			     PARSE_OPT_STOP_AT_NON_OPTION);
+	if (!argc)
+		usage_with_options(ftrace_usage, ftrace_options);
+
+	if (geteuid() != 0) {
+		pr_err("ftrace only works for root!\n");
+		return -1;
+	}
+
+	if (strcmp(argv[0], "live") == 0) {
+		ret = __cmd_ftrace_live(&ftrace, argc, argv);
+	} else {
+		usage_with_options(ftrace_usage, ftrace_options);
+	}
 
 	return ret;
 }
-- 
1.7.11.7


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

* [PATCH 09/19] perf ftrace: Add 'record' sub-command
  2013-06-26  7:14 [PATCHSET 00/19] perf tools: Introduce new 'ftrace' command (v3) Namhyung Kim
                   ` (7 preceding siblings ...)
  2013-06-26  7:14 ` [PATCH 08/19] perf ftrace: Split "live" sub-command Namhyung Kim
@ 2013-06-26  7:14 ` Namhyung Kim
  2013-07-10 14:28   ` Jiri Olsa
  2013-06-26  7:14 ` [PATCH 10/19] perf ftrace: Add 'show' sub-command Namhyung Kim
                   ` (9 subsequent siblings)
  18 siblings, 1 reply; 43+ messages in thread
From: Namhyung Kim @ 2013-06-26  7:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, Namhyung Kim, LKML,
	Steven Rostedt, Frederic Weisbecker, Jiri Olsa, David Ahern,
	Stephane Eranian

From: Namhyung Kim <namhyung.kim@lge.com>

The ftrace record command is for saving raw ftrace buffer contents
which can be get from per_cpu/cpuX/trace_pipe_raw.

Since ftrace events are generated very frequently so single thread for
recording mostly resulted in buffer overruns.  Thus it uses per-cpu
recorder thread to prevent such cases and they save the contents to
their own files.

These per-cpu data files are saved in a directory so that they can be
easily found when needed.  I chose the default directory name as
"perf.data.dir" and the first two (i.e. "perf.data") can be changed
with -o option.  The structure of the directory looks like:

  $ tree perf.data.dir
  perf.data.dir/
  |-- perf.header
  |-- trace-cpu0.buf
  |-- trace-cpu1.buf
  |-- trace-cpu2.buf
  `-- trace-cpu3.buf

In addition to trace-cpuX.buf files, it has perf.header file also.
The perf.header file is compatible with existing perf.data format and
contains usual event information, feature mask and sample data.  The
sample data is synthesized to indicate given cpu has a record file.

Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/builtin-ftrace.c | 629 ++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 611 insertions(+), 18 deletions(-)

diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
index 4ec96413d3a5..b348f7952ad9 100644
--- a/tools/perf/builtin-ftrace.c
+++ b/tools/perf/builtin-ftrace.c
@@ -12,6 +12,7 @@
 #include <unistd.h>
 #include <signal.h>
 #include <fcntl.h>
+#include <dirent.h>
 
 #include "util/debug.h"
 #include "util/parse-options.h"
@@ -19,14 +20,17 @@
 #include "util/target.h"
 #include "util/thread_map.h"
 #include "util/cpumap.h"
+#include "util/trace-event.h"
 
 
 #define DEFAULT_TRACER  "function_graph"
+#define DEFAULT_DIRNAME  "perf.data"
 
 struct perf_ftrace {
 	struct perf_evlist *evlist;
 	struct perf_target target;
 	const char *tracer;
+	const char *dirname;
 };
 
 static bool done;
@@ -170,41 +174,57 @@ static int reset_tracing_cpu(void)
 	return 0;
 }
 
-static int do_ftrace_live(struct perf_ftrace *ftrace)
+static int setup_tracing_files(struct perf_ftrace *ftrace)
 {
-	char *trace_file;
-	int trace_fd;
-	char buf[4096];
-	struct pollfd pollfd = {
-		.events = POLLIN,
-	};
-
-	signal(SIGINT, sig_handler);
-	signal(SIGUSR1, sig_handler);
-	signal(SIGCHLD, sig_handler);
+	int ret = -1;
 
-	if (reset_tracing_files(ftrace) < 0)
+	if (reset_tracing_files(ftrace) < 0) {
+		pr_err("failed to reset tracing files\n");
 		goto out;
+	}
 
 	/* reset ftrace buffer */
-	if (write_tracing_file("trace", "0") < 0)
+	if (write_tracing_file("trace", "0") < 0) {
+		pr_err("failed to reset ftrace buffer\n");
 		goto out;
+	}
 
 	if (set_tracing_pid(ftrace) < 0) {
 		pr_err("failed to set ftrace pid\n");
-		goto out_reset;
+		goto out;
 	}
 
 	if (set_tracing_cpu(ftrace) < 0) {
 		pr_err("failed to set tracing cpumask\n");
-		goto out_reset;
+		goto out;
 	}
 
 	if (write_tracing_file("current_tracer", ftrace->tracer) < 0) {
 		pr_err("failed to set current_tracer to %s\n", ftrace->tracer);
-		goto out_reset;
+		goto out;
 	}
 
+	ret = 0;
+out:
+	return ret;
+}
+
+static int do_ftrace_live(struct perf_ftrace *ftrace)
+{
+	char *trace_file;
+	int trace_fd;
+	char buf[4096];
+	struct pollfd pollfd = {
+		.events = POLLIN,
+	};
+
+	signal(SIGINT, sig_handler);
+	signal(SIGUSR1, sig_handler);
+	signal(SIGCHLD, sig_handler);
+
+	if (setup_tracing_files(ftrace) < 0)
+		goto out_reset;
+
 	trace_file = get_tracing_file("trace_pipe");
 	if (!trace_file) {
 		pr_err("failed to open trace_pipe\n");
@@ -258,7 +278,510 @@ out_close_fd:
 	close(trace_fd);
 out_reset:
 	reset_tracing_files(ftrace);
+	return done ? 0 : -1;
+}
+
+static int alloc_ftrace_evsel(struct perf_ftrace *ftrace)
+{
+	if (!strcmp(ftrace->tracer, "function")) {
+		if (perf_evlist__add_newtp(ftrace->evlist, "ftrace",
+					   "function", NULL) < 0) {
+			pr_err("failed to allocate ftrace event\n");
+			return -1;
+		}
+	} else if (!strcmp(ftrace->tracer, "function_graph")) {
+		if (perf_evlist__add_newtp(ftrace->evlist, "ftrace",
+					   "funcgraph_entry", NULL) ||
+		    perf_evlist__add_newtp(ftrace->evlist, "ftrace",
+					   "funcgraph_exit", NULL)) {
+			pr_err("failed to allocate ftrace event\n");
+			return -1;
+		}
+	} else {
+		pr_err("Not supported tracer: %s\n", ftrace->tracer);
+		return -1;
+	}
+	return 0;
+}
+
+static int remove_directory(const char *pathname)
+{
+	DIR *dir;
+	int ret = 0;
+	struct dirent *dent;
+	char namebuf[PATH_MAX];
+
+	dir = opendir(pathname);
+	if (dir == NULL)
+		return 0;
+
+	while ((dent = readdir(dir)) != NULL && !ret) {
+		struct stat statbuf;
+
+		if (dent->d_name[0] == '.')
+			continue;
+
+		scnprintf(namebuf, sizeof(namebuf), "%s/%s",
+			  pathname, dent->d_name);
+
+		ret = stat(namebuf, &statbuf);
+		if (ret < 0) {
+			pr_debug("stat failed\n");
+			break;
+		}
+
+		if (S_ISREG(statbuf.st_mode))
+			ret = unlink(namebuf);
+		else if (S_ISDIR(statbuf.st_mode))
+			ret = remove_directory(namebuf);
+		else {
+			pr_debug("unknown file.\n");
+			ret = -1;
+		}
+	}
+	closedir(dir);
+
+	if (ret < 0)
+		return ret;
+
+	return rmdir(pathname);
+}
+
+static int create_perf_directory(struct perf_ftrace *ftrace)
+{
+	int err;
+	char buf[PATH_MAX];
+	struct stat statbuf;
+
+	scnprintf(buf, sizeof(buf), "%s.dir", ftrace->dirname);
+
+	if (stat(buf, &statbuf) == 0) {
+		/* same name already exists - rename to *.old.dir */
+		char *old_name = malloc(strlen(buf) + 5);
+		if (old_name == NULL)
+			return -1;
+
+		scnprintf(old_name, strlen(buf) + 5,
+			  "%s.old.dir", ftrace->dirname);
+
+		if (remove_directory(old_name) < 0) {
+			perror("rmdir");
+			return -1;
+		}
+
+		if (rename(buf, old_name) < 0) {
+			perror("rename");
+			free(old_name);
+			return -1;
+		}
+
+		free(old_name);
+	}
+
+	err = mkdir(buf, 0755);
+	if (err < 0) {
+		perror("mkdir");
+		return -1;
+	}
+
+	strcat(buf, "/perf.header");
+
+	err = open(buf, O_RDWR | O_CREAT | O_TRUNC, 0644);
+	return err;
+}
+
+static void sig_dummy_handler(int sig __maybe_unused)
+{
+	while (!done)
+		continue;
+}
+
+enum {
+	RECORD_STATE__ERROR = -1,
+	RECORD_STATE__INIT,
+	RECORD_STATE__READY,
+	RECORD_STATE__DONE,
+};
+
+struct ftrace_record_arg {
+	struct perf_ftrace *ftrace;
+	int cpu;
+	int state;
+	pthread_t id;
+	struct list_head node;
+};
+
+static int recorder_count;
+pthread_cond_t recorder_ready_cond = PTHREAD_COND_INITIALIZER;
+pthread_cond_t recorder_start_cond = PTHREAD_COND_INITIALIZER;
+pthread_mutex_t recorder_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void *record_ftrace_raw_buffer(void *arg)
+{
+	struct ftrace_record_arg *fra = arg;
+	char buf[4096];
+	char *trace_file;
+	int trace_fd;
+	int output_fd;
+	int ret, n;
+	off_t byte_written = 0;
+	sigset_t sigmask;
+	struct pollfd pollfd = {
+		.events = POLLIN,
+	};
+
+	fra->state = RECORD_STATE__ERROR;
+
+	snprintf(buf, sizeof(buf), "per_cpu/cpu%d/trace_pipe_raw", fra->cpu);
+
+	trace_file = get_tracing_file(buf);
+	if (!trace_file) {
+		pr_err("failed to get trace_pipe_raw\n");
+		goto out;
+	}
+
+	trace_fd = open(trace_file, O_RDONLY);
+
+	put_tracing_file(trace_file);
+
+	if (trace_fd < 0) {
+		pr_err("failed to open trace_pipe_raw\n");
+		goto out;
+	}
+
+	snprintf(buf, sizeof(buf), "%s.dir/trace-cpu%d.buf",
+		 fra->ftrace->dirname, fra->cpu);
+
+	output_fd = open(buf, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+	if (output_fd < 0) {
+		pr_err("failed to open output file\n");
+		goto out_close;
+	}
+
+	fra->state = RECORD_STATE__READY;
+
+	/*
+	 * block all signals but SIGUSR2.
+	 * It'll be used to unblock a recorder to finish.
+	 */
+	sigfillset(&sigmask);
+	sigdelset(&sigmask, SIGUSR2);
+	pthread_sigmask(SIG_SETMASK, &sigmask,NULL);
+
+	signal(SIGUSR2, sig_dummy_handler);
+
+	fcntl(trace_fd, F_SETFL, O_NONBLOCK);
+	pollfd.fd = trace_fd;
+
+	/* Now I'm ready */
+	pthread_mutex_lock(&recorder_mutex);
+	recorder_count++;
+	pthread_cond_signal(&recorder_ready_cond);
+	pthread_cond_wait(&recorder_start_cond, &recorder_mutex);
+	pthread_mutex_unlock(&recorder_mutex);
+
+	pr_debug2("now recording for cpu%d\n", fra->cpu);
+
+	while (!done) {
+		ret = poll(&pollfd, 1, -1);
+		if (ret < 0 && errno != EINTR)
+			goto out_close;
+
+		if (pollfd.revents & POLLIN) {
+			n = read(trace_fd, buf, sizeof(buf));
+			if (n < 0)
+				goto out_close;
+			if (write(output_fd, buf, n) != n)
+				goto out_close;
+			byte_written += n;
+		}
+	}
+
+	/* read remaining buffer contents */
+	while (true) {
+		n = read(trace_fd, buf, sizeof(buf));
+		if (n < 0)
+			goto out_close;
+		if (n == 0)
+			break;
+		if (write(output_fd, buf, n) != n)
+			goto out_close;
+		byte_written += n;
+	}
+	fra->state = RECORD_STATE__DONE;
+
+out_close:
+	close(trace_fd);
 out:
+	if (fra->state == RECORD_STATE__ERROR) {
+		/*
+		 * We need to update recorder_count in this case also
+		 * in order to prevent deadlocking in the main thread.
+		 */
+		pthread_mutex_lock(&recorder_mutex);
+		recorder_count++;
+		pthread_cond_signal(&recorder_ready_cond);
+		pthread_mutex_unlock(&recorder_mutex);
+	}
+	return fra;
+}
+
+static void *synthesize_raw_data(struct perf_evsel *evsel)
+{
+	void *data = NULL;
+	u32 data_size;
+
+	if (!strcmp(evsel->tp_format->name, "function")) {
+		struct {
+			unsigned short common_type;
+			unsigned char common_flags;
+			unsigned char common_preempt_count;
+			int common_pid;
+			int common_padding;
+
+			unsigned long ip;
+			unsigned long parent_ip;
+		} function_format = {
+			.common_type = evsel->attr.config,
+		};
+
+		data_size = sizeof(function_format);
+
+		data = malloc(data_size + sizeof(u32));
+		if (data == NULL)
+			return NULL;
+
+		memcpy(data, &data_size, sizeof(data_size));
+		memcpy(data + sizeof(data_size), &function_format,
+		       sizeof(function_format));
+	} else if (!strcmp(evsel->tp_format->name, "funcgraph_entry")) {
+		struct {
+			unsigned short common_type;
+			unsigned char common_flags;
+			unsigned char common_preempt_count;
+			int common_pid;
+			int common_padding;
+
+			unsigned long func;
+			int depth;
+		} funcgraph_entry_format = {
+			.common_type = evsel->attr.config,
+		};
+
+		data_size = sizeof(funcgraph_entry_format);
+
+		data = malloc(data_size + sizeof(u32));
+		if (data == NULL)
+			return NULL;
+
+		memcpy(data, &data_size, sizeof(data_size));
+		memcpy(data + sizeof(data_size), &funcgraph_entry_format,
+		       sizeof(funcgraph_entry_format));
+	}
+	return data;
+}
+
+static int do_ftrace_record(struct perf_ftrace *ftrace)
+{
+	int i, err, feat;
+	int perf_fd;
+	LIST_HEAD(recorders);
+	struct perf_session *session;
+	struct ftrace_record_arg *fra, *tmp;
+
+	signal(SIGINT, sig_handler);
+	signal(SIGUSR1, sig_handler);
+	signal(SIGCHLD, sig_handler);
+
+	if (setup_tracing_files(ftrace) < 0)
+		goto out_reset;
+
+	alloc_ftrace_evsel(ftrace);
+
+	perf_fd = create_perf_directory(ftrace);
+	if (perf_fd < 0) {
+		pr_err("failed to create perf directory\n");
+		goto out_reset;
+	}
+
+	/* just use a dummy session for header recording */
+	session = zalloc(sizeof(*session));
+	if (session == NULL) {
+		pr_err("failed to allocate perf session\n");
+		goto out_close;
+	}
+	session->evlist = ftrace->evlist;
+
+	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
+		perf_header__set_feat(&session->header, feat);
+
+	perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
+	perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
+	perf_header__clear_feat(&session->header, HEADER_PMU_MAPPINGS);
+	perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
+
+	err = perf_session__write_header(session, ftrace->evlist,
+					 perf_fd, false);
+	if (err < 0) {
+		pr_err("failed to write perf header\n");
+		goto out_session;
+	}
+
+	/*
+	 * We record ftrace's per_cpu buffer so that it'd better having
+	 * corresponding cpu maps anyway.
+	 */
+	if (!perf_target__has_cpu(&ftrace->target)) {
+		struct cpu_map *new_map;
+
+		new_map = cpu_map__new(NULL);
+		if (new_map == NULL) {
+			pr_err("failed to create new cpu map\n");
+			goto out_session;
+		}
+
+		/* replace existing cpu map */
+		cpu_map__delete(ftrace->evlist->cpus);
+		ftrace->evlist->cpus = new_map;
+	}
+
+	for (i = 0; i < cpu_map__nr(ftrace->evlist->cpus); i++) {
+		fra = malloc(sizeof(*fra));
+		if (fra == NULL) {
+			pr_err("not enough memory!\n");
+			goto out_fra;
+		}
+
+		fra->ftrace = ftrace;
+		fra->cpu = ftrace->evlist->cpus->map[i];
+		fra->state = RECORD_STATE__INIT;
+		list_add_tail(&fra->node, &recorders);
+
+		err = pthread_create(&fra->id, NULL,
+				     record_ftrace_raw_buffer, fra);
+		if (err < 0) {
+			pr_err("failed to create recorder thread\n");
+			goto out_fra;
+		}
+	}
+
+	/* wait for all recorders ready */
+	pthread_mutex_lock(&recorder_mutex);
+	while (recorder_count != cpu_map__nr(ftrace->evlist->cpus))
+		pthread_cond_wait(&recorder_ready_cond, &recorder_mutex);
+	pthread_mutex_unlock(&recorder_mutex);
+
+	list_for_each_entry(fra, &recorders, node) {
+		if (fra->state != RECORD_STATE__READY) {
+			pr_err("cpu%d: failed to start recorder", fra->cpu);
+			goto out_fra;
+		}
+	}
+
+	if (write_tracing_file("tracing_on", "1") < 0) {
+		pr_err("can't enable tracing\n");
+		goto out_fra;
+	}
+
+	perf_evlist__start_workload(ftrace->evlist);
+
+	pr_debug2("start recording per cpu buffers\n");
+	pthread_mutex_lock(&recorder_mutex);
+	pthread_cond_broadcast(&recorder_start_cond);
+	pthread_mutex_unlock(&recorder_mutex);
+
+	/* wait for signal/finish */
+	pause();
+
+	if (write_tracing_file("tracing_on", "0") < 0) {
+		pr_err("can't disable tracing\n");
+		goto out_fra;
+	}
+
+	/* signal recorders to terminate */
+	list_for_each_entry(fra, &recorders, node) {
+		pr_debug2("killing recorder thread for cpu%d\n", fra->cpu);
+		pthread_kill(fra->id, SIGUSR2);
+	}
+
+	list_for_each_entry(fra, &recorders, node)
+		pthread_join(fra->id, NULL);
+
+	/* synthesize sample data */
+	list_for_each_entry(fra, &recorders, node) {
+		struct perf_evsel *evsel = perf_evlist__first(ftrace->evlist);
+		union perf_event event = {
+			.sample = {
+				.header = {
+					.type = PERF_RECORD_SAMPLE,
+					.misc = PERF_RECORD_MISC_KERNEL,
+					.size = sizeof(event.sample.header) +
+						evsel->sample_size,
+				},
+			},
+		};
+		struct perf_sample sample = {
+			.cpu = fra->cpu,
+			.period = 1,
+		};
+		void *raw_data;
+		u32 raw_size;
+		int orig_size;
+
+		if (fra->state != RECORD_STATE__DONE) {
+			pr_warning("recorder failed for some reason on cpu%d\n",
+				   fra->cpu);
+			continue;
+		}
+
+		perf_event__synthesize_sample(&event, evsel->attr.sample_type,
+					      &sample, false);
+
+		raw_data = synthesize_raw_data(evsel);
+		if (raw_data == NULL) {
+			pr_err("synthesizing raw sample failed\n");
+			goto out_fra;
+		}
+
+		/*
+		 * start of raw data is the size of raw data excluding itself.
+		 */
+		raw_size = sizeof(u32) + (*(u32 *) raw_data);
+
+		orig_size = event.sample.header.size;
+		event.sample.header.size += raw_size;
+
+		err = write(perf_fd, &event.sample, orig_size);
+		if (err != orig_size) {
+			pr_err("write error occurred\n");
+			free(raw_data);
+			goto out_fra;
+		}
+
+		err = write(perf_fd, raw_data, raw_size);
+		free(raw_data);
+
+		if (err != (int)raw_size) {
+			pr_err("write error occurred\n");
+			goto out_fra;
+		}
+
+		session->header.data_size += event.sample.header.size;
+	}
+
+	perf_session__write_header(session, ftrace->evlist, perf_fd, true);
+
+out_fra:
+	list_for_each_entry_safe(fra, tmp, &recorders, node) {
+		list_del(&fra->node);
+		free(fra);
+	}
+out_session:
+	free(session);
+out_close:
+	close(perf_fd);
+out_reset:
+	reset_tracing_files(ftrace);
 	return done ? 0 : -1;
 }
 
@@ -325,6 +848,74 @@ out:
 	return ret;
 }
 
+static int
+__cmd_ftrace_record(struct perf_ftrace *ftrace, int argc, const char **argv)
+{
+	int ret = -1;
+	const char * const record_usage[] = {
+		"perf ftrace record [<options>] [<command>]",
+		"perf ftrace record [<options>] -- <command> [<options>]",
+		NULL
+	};
+	const struct option record_options[] = {
+	OPT_STRING('t', "tracer", &ftrace->tracer, "tracer",
+		   "tracer to use"),
+	OPT_STRING('p', "pid", &ftrace->target.tid, "pid",
+		   "trace on existing process id"),
+	OPT_INCR('v', "verbose", &verbose,
+		 "be more verbose"),
+	OPT_BOOLEAN('a', "all-cpus", &ftrace->target.system_wide,
+		    "system-wide collection from all CPUs"),
+	OPT_STRING('C', "cpu", &ftrace->target.cpu_list, "cpu",
+		    "list of cpus to monitor"),
+	OPT_STRING('o', "output", &ftrace->dirname, "dirname",
+		   "input directory name to use (default: perf.data)"),
+	OPT_END()
+	};
+
+	argc = parse_options(argc, argv, record_options, record_usage,
+			     PARSE_OPT_STOP_AT_NON_OPTION);
+	if (!argc && perf_target__none(&ftrace->target))
+		usage_with_options(record_usage, record_options);
+
+	ret = perf_target__validate(&ftrace->target);
+	if (ret) {
+		char errbuf[512];
+
+		perf_target__strerror(&ftrace->target, ret, errbuf, 512);
+		pr_err("%s\n", errbuf);
+		return -EINVAL;
+	}
+
+	ftrace->evlist = perf_evlist__new();
+	if (ftrace->evlist == NULL)
+		return -ENOMEM;
+
+	ret = perf_evlist__create_maps(ftrace->evlist, &ftrace->target);
+	if (ret < 0)
+		goto out;
+
+	if (ftrace->tracer == NULL)
+		ftrace->tracer = DEFAULT_TRACER;
+
+	if (ftrace->dirname == NULL)
+		ftrace->dirname = DEFAULT_DIRNAME;
+
+	if (argc && perf_evlist__prepare_workload(ftrace->evlist,
+						  &ftrace->target,
+						  argv, false, true) < 0)
+		goto out_maps;
+
+	ret = do_ftrace_record(ftrace);
+
+out_maps:
+	perf_evlist__delete_maps(ftrace->evlist);
+out:
+	perf_evlist__delete(ftrace->evlist);
+
+	return ret;
+}
+
 int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	int ret;
@@ -332,8 +923,8 @@ int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
 		.target = { .uid = UINT_MAX, },
 	};
 	const char * const ftrace_usage[] = {
-		"perf ftrace {live} [<options>] [<command>]",
-		"perf ftrace {live} [<options>] -- <command> [<options>]",
+		"perf ftrace {live|record} [<options>] [<command>]",
+		"perf ftrace {live|record} [<options>] -- <command> [<options>]",
 		NULL
 	};
 	const struct option ftrace_options[] = {
@@ -352,6 +943,8 @@ int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
 
 	if (strcmp(argv[0], "live") == 0) {
 		ret = __cmd_ftrace_live(&ftrace, argc, argv);
+	} else 	if (strncmp(argv[0], "rec", 3) == 0) {
+		ret = __cmd_ftrace_record(&ftrace, argc, argv);
 	} else {
 		usage_with_options(ftrace_usage, ftrace_options);
 	}
-- 
1.7.11.7


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

* [PATCH 10/19] perf ftrace: Add 'show' sub-command
  2013-06-26  7:14 [PATCHSET 00/19] perf tools: Introduce new 'ftrace' command (v3) Namhyung Kim
                   ` (8 preceding siblings ...)
  2013-06-26  7:14 ` [PATCH 09/19] perf ftrace: Add 'record' sub-command Namhyung Kim
@ 2013-06-26  7:14 ` Namhyung Kim
  2013-07-10 14:41   ` Jiri Olsa
  2013-06-26  7:14 ` [PATCH 11/19] perf ftrace: Add 'report' sub-command Namhyung Kim
                   ` (8 subsequent siblings)
  18 siblings, 1 reply; 43+ messages in thread
From: Namhyung Kim @ 2013-06-26  7:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, Namhyung Kim, LKML,
	Steven Rostedt, Frederic Weisbecker, Jiri Olsa, David Ahern,
	Stephane Eranian

From: Namhyung Kim <namhyung.kim@lge.com>

The ftrace show subcommand is for viewing recorded ftrace files.  It
enters perf.data.dir directory and open perf.header file to find out
necessary information.  And then read out per-cpu trace records using
kbuffer helper and print them to stdout in time order.

It only shows its basic form so function graph doesn't show duration/
overhead and no leaf entry handling is provided yet.  Maybe it can be
handled by a proper plugin in the libtraceevent.

Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/builtin-ftrace.c | 427 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 425 insertions(+), 2 deletions(-)

diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
index b348f7952ad9..1ed415a19d53 100644
--- a/tools/perf/builtin-ftrace.c
+++ b/tools/perf/builtin-ftrace.c
@@ -13,6 +13,7 @@
 #include <signal.h>
 #include <fcntl.h>
 #include <dirent.h>
+#include <sys/mman.h>
 
 #include "util/debug.h"
 #include "util/parse-options.h"
@@ -21,6 +22,8 @@
 #include "util/thread_map.h"
 #include "util/cpumap.h"
 #include "util/trace-event.h"
+#include "../lib/traceevent/kbuffer.h"
+#include "../lib/traceevent/event-parse.h"
 
 
 #define DEFAULT_TRACER  "function_graph"
@@ -31,6 +34,7 @@ struct perf_ftrace {
 	struct perf_target target;
 	const char *tracer;
 	const char *dirname;
+	struct pevent *pevent;
 };
 
 static bool done;
@@ -786,6 +790,371 @@ out_reset:
 }
 
 static int
+function_handler(struct trace_seq *s, struct pevent_record *record,
+		 struct event_format *event, void *context __maybe_unused)
+{
+	struct pevent *pevent = event->pevent;
+	unsigned long long function;
+	const char *func;
+
+	if (pevent_get_field_val(s, event, "ip", record, &function, 1))
+		return trace_seq_putc(s, '!');
+
+	func = pevent_find_function(pevent, function);
+	if (func)
+		trace_seq_printf(s, "%s <-- ", func);
+	else
+		trace_seq_printf(s, "0x%llx", function);
+
+	if (pevent_get_field_val(s, event, "parent_ip", record, &function, 1))
+		return trace_seq_putc(s, '!');
+
+	func = pevent_find_function(pevent, function);
+	if (func)
+		trace_seq_printf(s, "%s", func);
+	else
+		trace_seq_printf(s, "0x%llx", function);
+
+	trace_seq_putc(s, '\n');
+	return 0;
+}
+
+#define TRACE_GRAPH_INDENT  2
+
+static int
+fgraph_ent_handler(struct trace_seq *s, struct pevent_record *record,
+		   struct event_format *event, void *context __maybe_unused)
+{
+	unsigned long long depth;
+	unsigned long long val;
+	const char *func;
+	int i;
+
+	if (pevent_get_field_val(s, event, "depth", record, &depth, 1))
+		return trace_seq_putc(s, '!');
+
+	/* Function */
+	for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
+		trace_seq_putc(s, ' ');
+
+	if (pevent_get_field_val(s, event, "func", record, &val, 1))
+		return trace_seq_putc(s, '!');
+
+	func = pevent_find_function(event->pevent, val);
+
+	if (func)
+		trace_seq_printf(s, "%s() {", func);
+	else
+		trace_seq_printf(s, "%llx() {", val);
+
+	trace_seq_putc(s, '\n');
+	return 0;
+}
+
+static int
+fgraph_ret_handler(struct trace_seq *s, struct pevent_record *record,
+		   struct event_format *event, void *context __maybe_unused)
+{
+	unsigned long long depth;
+	int i;
+
+	if (pevent_get_field_val(s, event, "depth", record, &depth, 1))
+		return trace_seq_putc(s, '!');
+
+	/* Function */
+	for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
+		trace_seq_putc(s, ' ');
+
+	trace_seq_puts(s, "}\n");
+	return 0;
+}
+
+struct perf_ftrace_report {
+	struct perf_ftrace *ftrace;
+	struct perf_tool tool;
+};
+
+struct ftrace_report_arg {
+	struct list_head node;
+	struct pevent_record *record;
+	struct kbuffer *kbuf;
+	void *map;
+	int cpu;
+	int fd;
+	off_t offset;
+	off_t size;
+};
+
+static LIST_HEAD(ftrace_cpu_buffers);
+
+static int process_sample_event(struct perf_tool *tool,
+				union perf_event * event __maybe_unused,
+				struct perf_sample *sample,
+				struct perf_evsel *evsel __maybe_unused,
+				struct machine *machine __maybe_unused)
+{
+	struct perf_ftrace *ftrace;
+	struct perf_ftrace_report *report;
+	struct ftrace_report_arg *fra;
+	struct stat statbuf;
+	enum kbuffer_long_size long_size;
+	enum kbuffer_endian endian;
+	char buf[PATH_MAX];
+
+	report = container_of(tool, struct perf_ftrace_report, tool);
+	ftrace = report->ftrace;
+
+	fra = zalloc(sizeof(*fra));
+	if (fra == NULL)
+		return -1;
+
+	fra->cpu = sample->cpu;
+
+	scnprintf(buf, sizeof(buf), "%s.dir/trace-cpu%d.buf",
+		  ftrace->dirname, fra->cpu);
+
+	fra->fd = open(buf, O_RDONLY);
+	if (fra->fd < 0)
+		goto out;
+
+	if (fstat(fra->fd, &statbuf) < 0)
+		goto out_close;
+
+	fra->size = statbuf.st_size;
+	if (fra->size == 0) {
+		/* skip zero-size buffers */
+		free(fra);
+		return 0;
+	}
+
+	/*
+	 * FIXME: What if pevent->page_size is smaller than current page size?
+	 */
+	fra->map = mmap(NULL, pevent_get_page_size(ftrace->pevent),
+			PROT_READ, MAP_PRIVATE, fra->fd, fra->offset);
+	if (fra->map == MAP_FAILED)
+		goto out_close;
+
+	fra->offset = 0;
+
+	if (pevent_is_file_bigendian(ftrace->pevent))
+		endian = KBUFFER_ENDIAN_BIG;
+	else
+		endian = KBUFFER_ENDIAN_LITTLE;
+
+	if (pevent_get_long_size(ftrace->pevent) == 8)
+		long_size = KBUFFER_LSIZE_8;
+	else
+		long_size = KBUFFER_LSIZE_4;
+
+	fra->kbuf = kbuffer_alloc(long_size, endian);
+	if (fra->kbuf == NULL)
+		goto out_unmap;
+
+	if (ftrace->pevent->old_format)
+		kbuffer_set_old_format(fra->kbuf);
+
+	kbuffer_load_subbuffer(fra->kbuf, fra->map);
+
+	pr_debug2("setup kbuffer for cpu%d\n", fra->cpu);
+	list_add_tail(&fra->node, &ftrace_cpu_buffers);
+	return 0;
+
+out_unmap:
+	munmap(fra->map, pevent_get_page_size(ftrace->pevent));
+out_close:
+	close(fra->fd);
+out:
+	free(fra);
+	return -1;
+}
+
+static struct pevent_record *
+get_next_ftrace_event_record(struct perf_ftrace *ftrace,
+			     struct ftrace_report_arg *fra)
+{
+	struct pevent_record *record;
+	unsigned long long ts;
+	void *data;
+
+retry:
+	data = kbuffer_read_event(fra->kbuf, &ts);
+	if (data) {
+		record = zalloc(sizeof(*record));
+		if (record == NULL) {
+			pr_err("memory allocation failure\n");
+			return NULL;
+		}
+
+		record->ts = ts;
+		record->cpu = fra->cpu;
+		record->data = data;
+		record->size = kbuffer_event_size(fra->kbuf);
+		record->record_size = kbuffer_curr_size(fra->kbuf);
+		record->offset = kbuffer_curr_offset(fra->kbuf);
+		record->missed_events = kbuffer_missed_events(fra->kbuf);
+		record->ref_count = 1;
+
+		kbuffer_next_event(fra->kbuf, NULL);
+		return record;
+	}
+
+	munmap(fra->map, pevent_get_page_size(ftrace->pevent));
+	fra->map = NULL;
+
+	fra->offset += pevent_get_page_size(ftrace->pevent);
+	if (fra->offset >= fra->size) {
+		/* EOF */
+		return NULL;
+	}
+
+	fra->map = mmap(NULL, pevent_get_page_size(ftrace->pevent),
+			PROT_READ, MAP_PRIVATE, fra->fd, fra->offset);
+	if (fra->map == MAP_FAILED) {
+		pr_err("memory mapping failed\n");
+		return NULL;
+	}
+
+	kbuffer_load_subbuffer(fra->kbuf, fra->map);
+
+	goto retry;
+}
+
+static struct pevent_record *
+get_ftrace_event_record(struct perf_ftrace *ftrace,
+			struct ftrace_report_arg *fra)
+{
+	if (fra->record == NULL)
+		fra->record = get_next_ftrace_event_record(ftrace, fra);
+
+	return fra->record;
+}
+
+static struct pevent_record *get_ordered_record(struct perf_ftrace *ftrace)
+{
+	struct ftrace_report_arg *fra = NULL;
+	struct ftrace_report_arg *tmp;
+	struct pevent_record *record;
+	unsigned long long min_ts = LLONG_MAX;
+
+	list_for_each_entry(tmp, &ftrace_cpu_buffers, node) {
+		if (perf_target__has_cpu(&ftrace->target)) {
+			int i;
+			bool found = false;
+
+			for (i = 0; i < cpu_map__nr(ftrace->evlist->cpus); i++) {
+				if (tmp->cpu == ftrace->evlist->cpus->map[i]) {
+					found = true;
+					break;
+				}
+			}
+			if (!found)
+				continue;
+		}
+
+		record = get_ftrace_event_record(ftrace, tmp);
+		if (record && record->ts < min_ts) {
+			min_ts = record->ts;
+			fra = tmp;
+		}
+	}
+
+	if (fra) {
+		record = fra->record;
+		fra->record = NULL;
+		return record;
+	}
+	return NULL;
+}
+
+static void free_ftrace_report_args(struct perf_ftrace *ftrace)
+{
+	struct ftrace_report_arg *fra, *tmp;
+
+	list_for_each_entry_safe(fra, tmp, &ftrace_cpu_buffers, node) {
+		list_del(&fra->node);
+
+		/* don't care about the errors */
+		munmap(fra->map, pevent_get_page_size(ftrace->pevent));
+		kbuffer_free(fra->kbuf);
+		free(fra->record);
+		close(fra->fd);
+		free(fra);
+	}
+}
+
+static int do_ftrace_show(struct perf_ftrace *ftrace)
+{
+	int ret = 0;
+	char buf[PATH_MAX];
+	struct perf_session *session;
+	struct pevent_record *record;
+	struct trace_seq seq;
+	struct perf_ftrace_report show = {
+		.ftrace = ftrace,
+		.tool = {
+			.sample = process_sample_event,
+		},
+	};
+
+	scnprintf(buf, sizeof(buf), "%s.dir/perf.header", ftrace->dirname);
+
+	session = perf_session__new(buf, O_RDONLY, false, false, &show.tool);
+	if (session == NULL) {
+		pr_err("failed to create a session\n");
+		return -1;
+	}
+
+	ftrace->pevent = session->pevent;
+
+	pevent_register_event_handler(ftrace->pevent, -1,
+				      "ftrace", "function",
+				      function_handler, NULL);
+	pevent_register_event_handler(ftrace->pevent, -1,
+				      "ftrace", "funcgraph_entry",
+				      fgraph_ent_handler, NULL);
+	pevent_register_event_handler(ftrace->pevent, -1,
+				      "ftrace", "funcgraph_exit",
+				      fgraph_ret_handler, NULL);
+
+	if (perf_session__process_events(session, &show.tool) < 0) {
+		pr_err("failed to process events\n");
+		ret = -1;
+		goto out;
+	}
+
+	trace_seq_init(&seq);
+
+	record = get_ordered_record(ftrace);
+	while (record) {
+		int type;
+		struct event_format *event;
+
+		type = pevent_data_type(ftrace->pevent, record);
+		event = pevent_find_event(ftrace->pevent, type);
+		if (!event) {
+			pr_warning("no event found for type %d", type);
+			continue;
+		}
+
+		pevent_print_event(ftrace->pevent, &seq, record);
+		trace_seq_do_printf(&seq);
+
+		trace_seq_reset(&seq);
+
+		free(record);
+		record = get_ordered_record(ftrace);
+	}
+
+	trace_seq_destroy(&seq);
+
+out:
+	free_ftrace_report_args(ftrace);
+	perf_session__delete(session);
+	return ret;
+}
+
+static int
 __cmd_ftrace_live(struct perf_ftrace *ftrace, int argc, const char **argv)
 {
 	int ret = -1;
@@ -916,6 +1285,58 @@ out:
 	return ret;
 }
 
+static int
+__cmd_ftrace_show(struct perf_ftrace *ftrace, int argc, const char **argv)
+{
+	int ret = -1;
+	const char * const show_usage[] = {
+		"perf ftrace show [<options>]",
+		NULL
+	};
+	const struct option show_options[] = {
+	OPT_STRING('i', "input", &ftrace->dirname, "dirname",
+		   "input directory name to use (default: perf.data)"),
+	OPT_INCR('v', "verbose", &verbose,
+		 "be more verbose"),
+	OPT_STRING('C', "cpu", &ftrace->target.cpu_list, "cpu",
+		    "list of cpus to monitor"),
+	OPT_END()
+	};
+
+	argc = parse_options(argc, argv, show_options, show_usage,
+			     PARSE_OPT_STOP_AT_NON_OPTION);
+	if (argc)
+		usage_with_options(show_usage, show_options);
+
+	ret = perf_target__validate(&ftrace->target);
+	if (ret) {
+		char errbuf[512];
+
+		perf_target__strerror(&ftrace->target, ret, errbuf, 512);
+		pr_err("%s\n", errbuf);
+		return -EINVAL;
+	}
+
+	ftrace->evlist = perf_evlist__new();
+	if (ftrace->evlist == NULL)
+		return -ENOMEM;
+
+	ret = perf_evlist__create_maps(ftrace->evlist, &ftrace->target);
+	if (ret < 0)
+		goto out;
+
+	if (ftrace->dirname == NULL)
+		ftrace->dirname = DEFAULT_DIRNAME;
+
+	ret = do_ftrace_show(ftrace);
+
+	perf_evlist__delete_maps(ftrace->evlist);
+out:
+	perf_evlist__delete(ftrace->evlist);
+
+	return ret;
+}
+
 int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	int ret;
@@ -923,8 +1344,8 @@ int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
 		.target = { .uid = UINT_MAX, },
 	};
 	const char * const ftrace_usage[] = {
-		"perf ftrace {live|record} [<options>] [<command>]",
-		"perf ftrace {live|record} [<options>] -- <command> [<options>]",
+		"perf ftrace {live|record|show} [<options>] [<command>]",
+		"perf ftrace {live|record|show} [<options>] -- <command> [<options>]",
 		NULL
 	};
 	const struct option ftrace_options[] = {
@@ -945,6 +1366,8 @@ int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
 		ret = __cmd_ftrace_live(&ftrace, argc, argv);
 	} else 	if (strncmp(argv[0], "rec", 3) == 0) {
 		ret = __cmd_ftrace_record(&ftrace, argc, argv);
+	} else 	if (strcmp(argv[0], "show") == 0) {
+		ret = __cmd_ftrace_show(&ftrace, argc, argv);
 	} else {
 		usage_with_options(ftrace_usage, ftrace_options);
 	}
-- 
1.7.11.7


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

* [PATCH 11/19] perf ftrace: Add 'report' sub-command
  2013-06-26  7:14 [PATCHSET 00/19] perf tools: Introduce new 'ftrace' command (v3) Namhyung Kim
                   ` (9 preceding siblings ...)
  2013-06-26  7:14 ` [PATCH 10/19] perf ftrace: Add 'show' sub-command Namhyung Kim
@ 2013-06-26  7:14 ` Namhyung Kim
  2013-07-10 14:45   ` Jiri Olsa
  2013-06-26  7:14 ` [PATCH 12/19] perf evlist: Enhance perf_evlist__start_workload() Namhyung Kim
                   ` (7 subsequent siblings)
  18 siblings, 1 reply; 43+ messages in thread
From: Namhyung Kim @ 2013-06-26  7:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, Namhyung Kim, LKML,
	Steven Rostedt, Frederic Weisbecker, Jiri Olsa, David Ahern,
	Stephane Eranian

From: Namhyung Kim <namhyung.kim@lge.com>

The ftrace report command is for analyzing ftrace result as usual perf
report style.  Internal processing of the ftrace buffer is similar to
the 'show' sub-command but it synthesizes necessary information like
thread, dso, map and symbol from saved trace info.

It currently count number of samples as a period and it can be
extended to use calltime of funcgraph_exit in the future.

Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/builtin-ftrace.c | 281 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 279 insertions(+), 2 deletions(-)

diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
index 1ed415a19d53..1e28dc7e9743 100644
--- a/tools/perf/builtin-ftrace.c
+++ b/tools/perf/builtin-ftrace.c
@@ -21,6 +21,7 @@
 #include "util/target.h"
 #include "util/thread_map.h"
 #include "util/cpumap.h"
+#include "util/sort.h"
 #include "util/trace-event.h"
 #include "../lib/traceevent/kbuffer.h"
 #include "../lib/traceevent/event-parse.h"
@@ -35,6 +36,7 @@ struct perf_ftrace {
 	const char *tracer;
 	const char *dirname;
 	struct pevent *pevent;
+	bool show_full_info;
 };
 
 static bool done;
@@ -1154,6 +1156,212 @@ out:
 	return ret;
 }
 
+struct cmdline_list {
+	struct cmdline_list	*next;
+	char			*comm;
+	int			pid;
+};
+
+struct func_list {
+	struct func_list	*next;
+	unsigned long long	addr;
+	char			*func;
+	char			*mod;
+};
+
+static int do_ftrace_report(struct perf_ftrace *ftrace)
+{
+	int ret = -1;
+	char buf[PATH_MAX];
+	unsigned long nr_samples;
+	struct perf_session *session;
+	struct perf_evsel *evsel;
+	struct pevent_record *record;
+	struct perf_ftrace_report report = {
+		.ftrace = ftrace,
+		.tool = {
+			.sample = process_sample_event,
+		},
+	};
+	struct cmdline_list *cmdline;
+	struct func_list *func;
+	struct machine *machine;
+	struct dso *dso;
+
+	scnprintf(buf, sizeof(buf), "%s.dir/perf.header", ftrace->dirname);
+
+	session = perf_session__new(buf, O_RDONLY, false, false, &report.tool);
+	if (session == NULL) {
+		pr_err("failed to create a session\n");
+		return -1;
+	}
+
+	ftrace->pevent = session->pevent;
+
+	if (perf_session__process_events(session, &report.tool) < 0) {
+		pr_err("failed to process events\n");
+		goto out;
+	}
+
+	machine = machines__findnew(&session->machines, HOST_KERNEL_ID);
+
+	/* Synthesize thread info from saved cmdlines */
+	cmdline = ftrace->pevent->cmdlist;
+	while (cmdline) {
+		struct thread *thread;
+
+		thread = machine__findnew_thread(machine, cmdline->pid);
+		if (thread && !thread->comm_set)
+			thread__set_comm(thread, cmdline->comm);
+
+		cmdline = cmdline->next;
+	}
+
+	/* Synthesize kernel dso and symbol info from saved kallsyms */
+	func = ftrace->pevent->funclist;
+	while (func) {
+		struct symbol *sym;
+
+		scnprintf(buf, sizeof(buf), "[%s]",
+			  func->mod ? func->mod : "kernel.kallsyms");
+
+		dso = dso__kernel_findnew(machine, buf, NULL, DSO_TYPE_KERNEL);
+		if (dso == NULL) {
+			pr_debug("can't find or allocate dso %s\n", buf);
+			continue;
+		}
+
+		sym = symbol__new(func->addr, 0, STB_GLOBAL, func->func);
+		if (sym == NULL) {
+			pr_debug("failed to allocate new symbol\n");
+			continue;
+		}
+		symbols__insert(&dso->symbols[MAP__FUNCTION], sym);
+
+		func = func->next;
+	}
+
+	/* Generate kernel maps */
+	list_for_each_entry(dso, &machine->kernel_dsos, node) {
+		struct map *map = map__new2(0, dso, MAP__FUNCTION);
+		if (map == NULL) {
+			pr_debug("failed to allocate new map\n");
+			goto out;
+		}
+
+		symbols__fixup_end(&dso->symbols[MAP__FUNCTION]);
+		map__fixup_start(map);
+		map__fixup_end(map);
+
+		dso__set_loaded(dso, MAP__FUNCTION);
+
+		map_groups__insert(&machine->kmaps, map);
+		if (strcmp(dso->name, "[kernel.kallsyms]") == 0)
+			machine->vmlinux_maps[MAP__FUNCTION] = map;
+	}
+
+	/* FIXME: no need to get ordered */
+	record = get_ordered_record(ftrace);
+	while (record) {
+		int type;
+		struct addr_location al;
+		union perf_event event = {
+			.header = {
+				.misc = PERF_RECORD_MISC_KERNEL,
+			},
+		};
+		struct perf_sample sample = {
+			.cpu = record->cpu,
+			.raw_data = record->data,
+			.period = 1,
+		};
+		struct format_field *field;
+		unsigned long long val;
+
+		type = pevent_data_type(ftrace->pevent, record);
+		evsel = perf_evlist__find_tracepoint_by_id(session->evlist,
+							   type);
+		if (evsel == NULL) {
+			pr_warning("no event found for type %d\n", type);
+			continue;
+		}
+
+		event.ip.pid = pevent_data_pid(ftrace->pevent, record);
+
+		if (!strcmp(perf_evsel__name(evsel), "ftrace:function"))
+			field = pevent_find_field(evsel->tp_format, "ip");
+		else
+			field = pevent_find_field(evsel->tp_format, "func");
+
+		if (pevent_read_number_field(field, record->data, &val) < 0) {
+			pr_err("failed to parse function address\n");
+			goto out;
+		}
+		event.ip.ip = val;
+
+		if (perf_event__preprocess_sample(&event, machine, &al,
+						  &sample, NULL) < 0) {
+			pr_err("problem processing %d event, skipping it.\n",
+				event.header.type);
+			goto out;
+		}
+
+		/* TODO: update sample.period using calltime */
+		if (!__hists__add_entry(&evsel->hists, &al, NULL,
+					sample.period, 0)) {
+			pr_err("failed to add a hist entry\n");
+			goto out;
+		}
+
+		evsel->hists.stats.total_period += sample.period;
+		hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
+
+		free(record);
+		record = get_ordered_record(ftrace);
+	}
+	ret = 0;
+
+	perf_session__fprintf_info(session, stdout, ftrace->show_full_info);
+
+	nr_samples = 0;
+	list_for_each_entry(evsel, &session->evlist->entries, node) {
+		struct hists *hists = &evsel->hists;
+
+		hists__collapse_resort(hists);
+		hists__output_resort(&evsel->hists);
+		nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
+	}
+
+	if (nr_samples == 0) {
+		pr_warning("The %s file has no samples!\n", session->filename);
+		goto out;
+	}
+
+	list_for_each_entry(evsel, &session->evlist->entries, node) {
+		struct hists *hists = &evsel->hists;
+		const char *evname = perf_evsel__name(evsel);
+		u64 nr_events = hists->stats.total_period;
+		char unit;
+
+		nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
+		nr_samples = convert_unit(nr_samples, &unit);
+		fprintf(stdout, "# Samples: %lu%c", nr_samples, unit);
+		if (evname != NULL)
+			fprintf(stdout, " of event '%s'", evname);
+
+		fprintf(stdout, "\n# Event count (approx.): %" PRIu64, nr_events);
+		fprintf(stdout, "\n#\n");
+
+		hists__fprintf(hists, true, 0, 0, 0.0, stdout);
+		fprintf(stdout, "\n\n");
+	}
+
+out:
+	free_ftrace_report_args(ftrace);
+	perf_session__delete(session);
+	return ret;
+}
+
 static int
 __cmd_ftrace_live(struct perf_ftrace *ftrace, int argc, const char **argv)
 {
@@ -1337,6 +1545,73 @@ out:
 	return ret;
 }
 
+static int
+__cmd_ftrace_report(struct perf_ftrace *ftrace, int argc, const char **argv)
+{
+	int ret = -1;
+	const char * const report_usage[] = {
+		"perf ftrace report [<options>]",
+		NULL
+	};
+	const struct option report_options[] = {
+	OPT_STRING('i', "input", &ftrace->dirname, "dirname",
+		   "input directory name to use (default: perf.data)"),
+	OPT_INCR('v', "verbose", &verbose,
+		 "be more verbose"),
+	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
+		    "dump raw trace in ASCII"),
+	OPT_STRING('C', "cpu", &ftrace->target.cpu_list, "cpu",
+		    "list of cpus to monitor"),
+	OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
+		   "sort by key(s): pid, comm, dso, symbol, cpu"),
+	OPT_BOOLEAN('I', "show-info", &ftrace->show_full_info,
+		    "Display extended information like cpu/numa topology"),
+	OPT_END()
+	};
+
+	argc = parse_options(argc, argv, report_options, report_usage,
+			     PARSE_OPT_STOP_AT_NON_OPTION);
+	if (argc)
+		usage_with_options(report_usage, report_options);
+
+	ret = perf_target__validate(&ftrace->target);
+	if (ret) {
+		char errbuf[512];
+
+		perf_target__strerror(&ftrace->target, ret, errbuf, 512);
+		pr_err("%s\n", errbuf);
+		return -EINVAL;
+	}
+
+	ftrace->evlist = perf_evlist__new();
+	if (ftrace->evlist == NULL)
+		return -ENOMEM;
+
+	ret = perf_evlist__create_maps(ftrace->evlist, &ftrace->target);
+	if (ret < 0)
+		goto out;
+
+	if (ftrace->dirname == NULL)
+		ftrace->dirname = DEFAULT_DIRNAME;
+
+	perf_hpp__column_enable(PERF_HPP__OVERHEAD);
+	perf_hpp__init();
+
+	setup_sorting();
+
+	symbol_conf.exclude_other = false;
+	symbol_conf.try_vmlinux_path = false;
+	symbol__init();
+
+	ret = do_ftrace_report(ftrace);
+
+	perf_evlist__delete_maps(ftrace->evlist);
+out:
+	perf_evlist__delete(ftrace->evlist);
+
+	return ret;
+}
+
 int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	int ret;
@@ -1344,8 +1619,8 @@ int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
 		.target = { .uid = UINT_MAX, },
 	};
 	const char * const ftrace_usage[] = {
-		"perf ftrace {live|record|show} [<options>] [<command>]",
-		"perf ftrace {live|record|show} [<options>] -- <command> [<options>]",
+		"perf ftrace {live|record|show|report} [<options>] [<command>]",
+		"perf ftrace {live|record|show|report} [<options>] -- <command> [<options>]",
 		NULL
 	};
 	const struct option ftrace_options[] = {
@@ -1368,6 +1643,8 @@ int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
 		ret = __cmd_ftrace_record(&ftrace, argc, argv);
 	} else 	if (strcmp(argv[0], "show") == 0) {
 		ret = __cmd_ftrace_show(&ftrace, argc, argv);
+	} else 	if (strncmp(argv[0], "rep", 3) == 0) {
+		ret = __cmd_ftrace_report(&ftrace, argc, argv);
 	} else {
 		usage_with_options(ftrace_usage, ftrace_options);
 	}
-- 
1.7.11.7


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

* [PATCH 12/19] perf evlist: Enhance perf_evlist__start_workload()
  2013-06-26  7:14 [PATCHSET 00/19] perf tools: Introduce new 'ftrace' command (v3) Namhyung Kim
                   ` (10 preceding siblings ...)
  2013-06-26  7:14 ` [PATCH 11/19] perf ftrace: Add 'report' sub-command Namhyung Kim
@ 2013-06-26  7:14 ` Namhyung Kim
  2013-07-12  8:50   ` [tip:perf/urgent] " tip-bot for Namhyung Kim
  2013-06-26  7:14 ` [PATCH 13/19] perf ftrace: Use pager for displaying result Namhyung Kim
                   ` (6 subsequent siblings)
  18 siblings, 1 reply; 43+ messages in thread
From: Namhyung Kim @ 2013-06-26  7:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, Namhyung Kim, LKML,
	Steven Rostedt, Frederic Weisbecker, Jiri Olsa, David Ahern,
	Stephane Eranian

From: Namhyung Kim <namhyung.kim@lge.com>

When perf tries to start a workload, it relies on a pipe which the
workload was blocked for reading.  After closing the pipe on the
parent, the workload (child) can start the actual work via exec().

However, if another process was forked after creating a workload, this
mechanism cannot work since the other process (child) also inherits
the pipe, so that closing the pipe in parent cannot unblock the
workload.  Fix it by using explicit write call can then closing it.

For similar reason, the pipe fd on parent should be marked as CLOEXEC
so that it can be closed after another child exec'ed.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/util/evlist.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 89aea20984ca..4a901be599ed 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -821,6 +821,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
 		goto out_close_pipes;
 	}
 
+	fcntl(go_pipe[1], F_SETFD, FD_CLOEXEC);
 	evlist->workload.cork_fd = go_pipe[1];
 	close(child_ready_pipe[0]);
 	return 0;
@@ -837,10 +838,17 @@ out_close_ready_pipe:
 int perf_evlist__start_workload(struct perf_evlist *evlist)
 {
 	if (evlist->workload.cork_fd > 0) {
+		char bf;
+		int ret;
 		/*
 		 * Remove the cork, let it rip!
 		 */
-		return close(evlist->workload.cork_fd);
+		ret = write(evlist->workload.cork_fd, &bf, 1);
+		if (ret < 0)
+			perror("enable to write to pipe");
+
+		close(evlist->workload.cork_fd);
+		return ret;
 	}
 
 	return 0;
-- 
1.7.11.7


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

* [PATCH 13/19] perf ftrace: Use pager for displaying result
  2013-06-26  7:14 [PATCHSET 00/19] perf tools: Introduce new 'ftrace' command (v3) Namhyung Kim
                   ` (11 preceding siblings ...)
  2013-06-26  7:14 ` [PATCH 12/19] perf evlist: Enhance perf_evlist__start_workload() Namhyung Kim
@ 2013-06-26  7:14 ` Namhyung Kim
  2013-06-26  7:14 ` [PATCH 14/19] perf ftrace: Cleanup using ftrace_setup/teardown() Namhyung Kim
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 43+ messages in thread
From: Namhyung Kim @ 2013-06-26  7:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, Namhyung Kim, LKML,
	Steven Rostedt, Frederic Weisbecker, Jiri Olsa, David Ahern,
	Stephane Eranian

From: Namhyung Kim <namhyung.kim@lge.com>

It's convenient to use pager when seeing many lines of result.

Note that setup_pager() should be called after perf_evlist__
prepare_workload() since they can interfere each other regarding
shared stdio streams.

Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/builtin-ftrace.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
index 1e28dc7e9743..8bb2604517cc 100644
--- a/tools/perf/builtin-ftrace.c
+++ b/tools/perf/builtin-ftrace.c
@@ -227,6 +227,7 @@ static int do_ftrace_live(struct perf_ftrace *ftrace)
 	signal(SIGINT, sig_handler);
 	signal(SIGUSR1, sig_handler);
 	signal(SIGCHLD, sig_handler);
+	signal(SIGPIPE, sig_handler);
 
 	if (setup_tracing_files(ftrace) < 0)
 		goto out_reset;
@@ -1415,6 +1416,8 @@ __cmd_ftrace_live(struct perf_ftrace *ftrace, int argc, const char **argv)
 						  argv, false, true) < 0)
 		goto out_maps;
 
+	setup_pager();
+
 	ret = do_ftrace_live(ftrace);
 
 out_maps:
@@ -1536,6 +1539,8 @@ __cmd_ftrace_show(struct perf_ftrace *ftrace, int argc, const char **argv)
 	if (ftrace->dirname == NULL)
 		ftrace->dirname = DEFAULT_DIRNAME;
 
+	setup_pager();
+
 	ret = do_ftrace_show(ftrace);
 
 	perf_evlist__delete_maps(ftrace->evlist);
@@ -1597,6 +1602,7 @@ __cmd_ftrace_report(struct perf_ftrace *ftrace, int argc, const char **argv)
 	perf_hpp__column_enable(PERF_HPP__OVERHEAD);
 	perf_hpp__init();
 
+	setup_pager();
 	setup_sorting();
 
 	symbol_conf.exclude_other = false;
-- 
1.7.11.7


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

* [PATCH 14/19] perf ftrace: Cleanup using ftrace_setup/teardown()
  2013-06-26  7:14 [PATCHSET 00/19] perf tools: Introduce new 'ftrace' command (v3) Namhyung Kim
                   ` (12 preceding siblings ...)
  2013-06-26  7:14 ` [PATCH 13/19] perf ftrace: Use pager for displaying result Namhyung Kim
@ 2013-06-26  7:14 ` Namhyung Kim
  2013-06-26  7:14 ` [PATCH 15/19] perf tools: Add document for perf-ftrace command Namhyung Kim
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 43+ messages in thread
From: Namhyung Kim @ 2013-06-26  7:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, Namhyung Kim, LKML,
	Steven Rostedt, Frederic Weisbecker, Jiri Olsa, David Ahern,
	Stephane Eranian

From: Namhyung Kim <namhyung.kim@lge.com>

The ftrace sub-commands share some common code so that factor it out
to ftrace_setup() and ftrace_teardown() helpers.

Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/builtin-ftrace.c | 168 +++++++++++++++++---------------------------
 1 file changed, 64 insertions(+), 104 deletions(-)

diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
index 8bb2604517cc..698dd0b5cecf 100644
--- a/tools/perf/builtin-ftrace.c
+++ b/tools/perf/builtin-ftrace.c
@@ -1363,10 +1363,59 @@ out:
 	return ret;
 }
 
+static int ftrace_setup(struct perf_ftrace *ftrace, int argc, const char **argv)
+{
+	int ret;
+	char errbuf[512];
+
+	ret = perf_target__validate(&ftrace->target);
+	if (ret) {
+		perf_target__strerror(&ftrace->target, ret, errbuf, 512);
+		pr_err("%s\n", errbuf);
+		return -EINVAL;
+	}
+
+	ftrace->evlist = perf_evlist__new();
+	if (ftrace->evlist == NULL)
+		return -ENOMEM;
+
+	ret = perf_evlist__create_maps(ftrace->evlist, &ftrace->target);
+	if (ret < 0)
+		goto out;
+
+	if (ftrace->tracer == NULL)
+		ftrace->tracer = DEFAULT_TRACER;
+
+	if (ftrace->dirname == NULL)
+		ftrace->dirname = DEFAULT_DIRNAME;
+
+	if (argc) {
+		ret = perf_evlist__prepare_workload(ftrace->evlist,
+						    &ftrace->target,
+						    argv, false, true);
+		if (ret < 0)
+			goto out_maps;
+	}
+	return 0;
+
+out_maps:
+	perf_evlist__delete_maps(ftrace->evlist);
+out:
+	perf_evlist__delete(ftrace->evlist);
+
+	return ret;
+}
+
+static void ftrace_teardown(struct perf_ftrace *ftrace)
+{
+	perf_evlist__delete_maps(ftrace->evlist);
+	perf_evlist__delete(ftrace->evlist);
+}
+
 static int
 __cmd_ftrace_live(struct perf_ftrace *ftrace, int argc, const char **argv)
 {
-	int ret = -1;
+	int ret;
 	const char * const live_usage[] = {
 		"perf ftrace live [<options>] [<command>]",
 		"perf ftrace live [<options>] -- <command> [<options>]",
@@ -1391,47 +1440,22 @@ __cmd_ftrace_live(struct perf_ftrace *ftrace, int argc, const char **argv)
 	if (!argc && perf_target__none(&ftrace->target))
 		usage_with_options(live_usage, live_options);
 
-	ret = perf_target__validate(&ftrace->target);
-	if (ret) {
-		char errbuf[512];
-
-		perf_target__strerror(&ftrace->target, ret, errbuf, 512);
-		pr_err("%s\n", errbuf);
-		return -EINVAL;
-	}
-
-	ftrace->evlist = perf_evlist__new();
-	if (ftrace->evlist == NULL)
-		return -ENOMEM;
-
-	ret = perf_evlist__create_maps(ftrace->evlist, &ftrace->target);
+	ret = ftrace_setup(ftrace, argc, argv);
 	if (ret < 0)
-		goto out;
-
-	if (ftrace->tracer == NULL)
-		ftrace->tracer = DEFAULT_TRACER;
-
-	if (argc && perf_evlist__prepare_workload(ftrace->evlist,
-						  &ftrace->target,
-						  argv, false, true) < 0)
-		goto out_maps;
+		return ret;
 
 	setup_pager();
 
 	ret = do_ftrace_live(ftrace);
 
-out_maps:
-	perf_evlist__delete_maps(ftrace->evlist);
-out:
-	perf_evlist__delete(ftrace->evlist);
-
+	ftrace_teardown(ftrace);
 	return ret;
 }
 
 static int
 __cmd_ftrace_record(struct perf_ftrace *ftrace, int argc, const char **argv)
 {
-	int ret = -1;
+	int ret;
 	const char * const record_usage[] = {
 		"perf ftrace record [<options>] [<command>]",
 		"perf ftrace record [<options>] -- <command> [<options>]",
@@ -1458,39 +1482,13 @@ __cmd_ftrace_record(struct perf_ftrace *ftrace, int argc, const char **argv)
 	if (!argc && perf_target__none(&ftrace->target))
 		usage_with_options(record_usage, record_options);
 
-	ret = perf_target__validate(&ftrace->target);
-	if (ret) {
-		char errbuf[512];
-
-		perf_target__strerror(&ftrace->target, ret, errbuf, 512);
-		pr_err("%s\n", errbuf);
-		return -EINVAL;
-	}
-
-	ftrace->evlist = perf_evlist__new();
-	if (ftrace->evlist == NULL)
-		return -ENOMEM;
-
-	ret = perf_evlist__create_maps(ftrace->evlist, &ftrace->target);
+	ret = ftrace_setup(ftrace, argc, argv);
 	if (ret < 0)
-		goto out;
-
-	if (ftrace->tracer == NULL)
-		ftrace->tracer = DEFAULT_TRACER;
-
-	if (ftrace->dirname == NULL)
-		ftrace->dirname = DEFAULT_DIRNAME;
-
-	if (argc && perf_evlist__prepare_workload(ftrace->evlist,
-						  &ftrace->target,
-						  argv, false, true) < 0)
-		goto out_maps;
+		return ret;
 
 	ret = do_ftrace_record(ftrace);
 
-out_maps:
 	perf_evlist__delete_maps(ftrace->evlist);
-out:
 	perf_evlist__delete(ftrace->evlist);
 
 	return ret;
@@ -1499,7 +1497,7 @@ out:
 static int
 __cmd_ftrace_show(struct perf_ftrace *ftrace, int argc, const char **argv)
 {
-	int ret = -1;
+	int ret;
 	const char * const show_usage[] = {
 		"perf ftrace show [<options>]",
 		NULL
@@ -1519,41 +1517,22 @@ __cmd_ftrace_show(struct perf_ftrace *ftrace, int argc, const char **argv)
 	if (argc)
 		usage_with_options(show_usage, show_options);
 
-	ret = perf_target__validate(&ftrace->target);
-	if (ret) {
-		char errbuf[512];
-
-		perf_target__strerror(&ftrace->target, ret, errbuf, 512);
-		pr_err("%s\n", errbuf);
-		return -EINVAL;
-	}
-
-	ftrace->evlist = perf_evlist__new();
-	if (ftrace->evlist == NULL)
-		return -ENOMEM;
-
-	ret = perf_evlist__create_maps(ftrace->evlist, &ftrace->target);
+	ret = ftrace_setup(ftrace, argc, argv);
 	if (ret < 0)
-		goto out;
-
-	if (ftrace->dirname == NULL)
-		ftrace->dirname = DEFAULT_DIRNAME;
+		return ret;
 
 	setup_pager();
 
 	ret = do_ftrace_show(ftrace);
 
-	perf_evlist__delete_maps(ftrace->evlist);
-out:
-	perf_evlist__delete(ftrace->evlist);
-
+	ftrace_teardown(ftrace);
 	return ret;
 }
 
 static int
 __cmd_ftrace_report(struct perf_ftrace *ftrace, int argc, const char **argv)
 {
-	int ret = -1;
+	int ret;
 	const char * const report_usage[] = {
 		"perf ftrace report [<options>]",
 		NULL
@@ -1579,25 +1558,9 @@ __cmd_ftrace_report(struct perf_ftrace *ftrace, int argc, const char **argv)
 	if (argc)
 		usage_with_options(report_usage, report_options);
 
-	ret = perf_target__validate(&ftrace->target);
-	if (ret) {
-		char errbuf[512];
-
-		perf_target__strerror(&ftrace->target, ret, errbuf, 512);
-		pr_err("%s\n", errbuf);
-		return -EINVAL;
-	}
-
-	ftrace->evlist = perf_evlist__new();
-	if (ftrace->evlist == NULL)
-		return -ENOMEM;
-
-	ret = perf_evlist__create_maps(ftrace->evlist, &ftrace->target);
+	ret = ftrace_setup(ftrace, argc, argv);
 	if (ret < 0)
-		goto out;
-
-	if (ftrace->dirname == NULL)
-		ftrace->dirname = DEFAULT_DIRNAME;
+		return ret;
 
 	perf_hpp__column_enable(PERF_HPP__OVERHEAD);
 	perf_hpp__init();
@@ -1611,10 +1574,7 @@ __cmd_ftrace_report(struct perf_ftrace *ftrace, int argc, const char **argv)
 
 	ret = do_ftrace_report(ftrace);
 
-	perf_evlist__delete_maps(ftrace->evlist);
-out:
-	perf_evlist__delete(ftrace->evlist);
-
+	ftrace_teardown(ftrace);
 	return ret;
 }
 
-- 
1.7.11.7


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

* [PATCH 15/19] perf tools: Add document for perf-ftrace command
  2013-06-26  7:14 [PATCHSET 00/19] perf tools: Introduce new 'ftrace' command (v3) Namhyung Kim
                   ` (13 preceding siblings ...)
  2013-06-26  7:14 ` [PATCH 14/19] perf ftrace: Cleanup using ftrace_setup/teardown() Namhyung Kim
@ 2013-06-26  7:14 ` Namhyung Kim
  2013-07-10 14:22   ` Jiri Olsa
  2013-06-26  7:14 ` [PATCH 16/19] perf ftrace: Add a signal handler for SIGSEGV Namhyung Kim
                   ` (3 subsequent siblings)
  18 siblings, 1 reply; 43+ messages in thread
From: Namhyung Kim @ 2013-06-26  7:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, Namhyung Kim, LKML,
	Steven Rostedt, Frederic Weisbecker, Jiri Olsa, David Ahern,
	Stephane Eranian

From: Namhyung Kim <namhyung.kim@lge.com>

Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/Documentation/perf-ftrace.txt | 114 +++++++++++++++++++++++++++++++
 1 file changed, 114 insertions(+)
 create mode 100644 tools/perf/Documentation/perf-ftrace.txt

diff --git a/tools/perf/Documentation/perf-ftrace.txt b/tools/perf/Documentation/perf-ftrace.txt
new file mode 100644
index 000000000000..e102ccc6daa7
--- /dev/null
+++ b/tools/perf/Documentation/perf-ftrace.txt
@@ -0,0 +1,114 @@
+perf-ftrace(1)
+==============
+
+NAME
+----
+perf-ftrace - A front end for kernel's ftrace
+
+SYNOPSIS
+--------
+[verse]
+'perf ftrace' {live|record} [<options>] [<command>]
+'perf ftrace' {show|report} [<options>]
+
+DESCRIPTION
+-----------
+This command reads the ftrace buffer and displays the trace recorded.
+
+There are several variants of perf ftrace:
+
+  'perf ftrace live <command>' to see a live trace of kernel functions
+  via trace_pipe during executing the <command>.  If <command> is not
+  specified, one of the target options (-p, -a or -C) should be given.
+  It just prints out the result to stdout and doesn't save any files.
+
+  'perf ftrace record <command>' to record trace entries of kernel
+  functions during the execution of the <command>.  Like 'perf ftrace
+  live', at least one of <command> and/or target options should be
+  given in order to start recording.  The recorded results are saved
+  under a directory ('perf.data.dir' by default) and will be used by
+  other perf-ftrace tools like 'show' and 'report'.
+
+  'perf ftrace show' to see the trace of recorded functions.  It shows
+  functions sorted by time so the end result might be interspersed if
+  there's a concurrent execution.
+
+  'perf ftrace report' to display the result in an usual perf-report
+  style - entries are sorted by given sort keys and output is resorted
+  by its overhead.
+
+OPTIONS
+-------
+<command>...::
+	Any command you can specify in a shell.
+
+-t::
+--tracer=::
+        The ftrace tracer to be used (default: function_graph).
+	Currently only 'function' and 'function_graph' are supported.
+        Used by 'live' and 'record' subcommands only.
+
+-p::
+--pid=::
+	Record events on existing process ID (comma separated list).
+        Used by 'live' and 'record' subcommands only.
+
+-a::
+        Force system-wide collection.  Scripts run without a <command>
+        normally use -a by default, while scripts run with a <command>
+        normally don't - this option allows the latter to be run in
+        system-wide mode.  Used by 'live' and 'record' subcommands only.
+
+-C::
+--cpu:: Only process samples for the list of CPUs provided.
+        Multiple CPUs can be provided as a comma-separated list with
+        no space: 0,1. Ranges of CPUs are specified with -: 0-2.
+	Default is to report samples on all online CPUs.
+
+-s::
+--sort=::
+	Sort histogram entries by given key(s) - multiple keys can be
+        specified in CSV format.  Following sort keys are available:
+	pid, comm, dso, symbol, cpu.
+
+	Each key has following meaning:
+
+	- comm: command (name) of the task
+	- pid: command and tid of the task
+	- dso: name of library or module executed at the time of sample
+	- symbol: name of function executed at the time of sample
+	- cpu: cpu number the task ran at the time of sample
+
+	By default, comm, dso and symbol keys are used.
+	(i.e. --sort comm,dso,symbol)
+	Used by 'report' subcommands only.
+
+-i::
+--input=::
+        Input directory name excluding '.dir' at the end.
+        (default: perf.data)
+
+-o::
+--output=::
+        Output directory name excluding '.dir' at the end.
+	(default: perf.data)
+
+-v::
+--verbose::
+	Be more verbose (show counter open errors, etc).
+
+-D::
+--dump-raw-trace::
+        Dump raw trace in ASCII.  Used by 'report' subcommands only.
+
+-I::
+--show-info::
+	Display extended information about the record.  This adds
+	information which may be very large and thus may clutter the
+        display.  It currently includes: cpu and numa topology of the
+        host system.  It can only be used with the 'report' subcommand.
+
+SEE ALSO
+--------
+linkperf:perf-record[1], linkperf:perf-report[1],
+linkperf:perf-script[1]
-- 
1.7.11.7


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

* [PATCH 16/19] perf ftrace: Add a signal handler for SIGSEGV
  2013-06-26  7:14 [PATCHSET 00/19] perf tools: Introduce new 'ftrace' command (v3) Namhyung Kim
                   ` (14 preceding siblings ...)
  2013-06-26  7:14 ` [PATCH 15/19] perf tools: Add document for perf-ftrace command Namhyung Kim
@ 2013-06-26  7:14 ` Namhyung Kim
  2013-06-26  7:14 ` [PATCH 17/19] perf ftrace: Add --clock option Namhyung Kim
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 43+ messages in thread
From: Namhyung Kim @ 2013-06-26  7:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, Namhyung Kim, LKML,
	Steven Rostedt, Frederic Weisbecker, Jiri Olsa, David Ahern,
	Stephane Eranian

From: Namhyung Kim <namhyung.kim@lge.com>

It's for debugging purpose.

Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/builtin-ftrace.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
index 698dd0b5cecf..3b6bcc29715b 100644
--- a/tools/perf/builtin-ftrace.c
+++ b/tools/perf/builtin-ftrace.c
@@ -41,6 +41,13 @@ struct perf_ftrace {
 
 static bool done;
 
+static void sig_exit(int sig)
+{
+	psignal(sig, "perf");
+	signal(sig, SIG_DFL);
+	raise(sig);
+}
+
 static void sig_handler(int sig __maybe_unused)
 {
 	done = true;
@@ -228,6 +235,7 @@ static int do_ftrace_live(struct perf_ftrace *ftrace)
 	signal(SIGUSR1, sig_handler);
 	signal(SIGCHLD, sig_handler);
 	signal(SIGPIPE, sig_handler);
+	signal(SIGSEGV, sig_exit);
 
 	if (setup_tracing_files(ftrace) < 0)
 		goto out_reset;
@@ -599,6 +607,7 @@ static int do_ftrace_record(struct perf_ftrace *ftrace)
 	signal(SIGINT, sig_handler);
 	signal(SIGUSR1, sig_handler);
 	signal(SIGCHLD, sig_handler);
+	signal(SIGSEGV, sig_exit);
 
 	if (setup_tracing_files(ftrace) < 0)
 		goto out_reset;
@@ -1100,6 +1109,8 @@ static int do_ftrace_show(struct perf_ftrace *ftrace)
 		},
 	};
 
+	signal(SIGSEGV, sig_exit);
+
 	scnprintf(buf, sizeof(buf), "%s.dir/perf.header", ftrace->dirname);
 
 	session = perf_session__new(buf, O_RDONLY, false, false, &show.tool);
@@ -1189,6 +1200,8 @@ static int do_ftrace_report(struct perf_ftrace *ftrace)
 	struct machine *machine;
 	struct dso *dso;
 
+	signal(SIGSEGV, sig_exit);
+
 	scnprintf(buf, sizeof(buf), "%s.dir/perf.header", ftrace->dirname);
 
 	session = perf_session__new(buf, O_RDONLY, false, false, &report.tool);
-- 
1.7.11.7


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

* [PATCH 17/19] perf ftrace: Add --clock option
  2013-06-26  7:14 [PATCHSET 00/19] perf tools: Introduce new 'ftrace' command (v3) Namhyung Kim
                   ` (15 preceding siblings ...)
  2013-06-26  7:14 ` [PATCH 16/19] perf ftrace: Add a signal handler for SIGSEGV Namhyung Kim
@ 2013-06-26  7:14 ` Namhyung Kim
  2013-06-26  7:14 ` [PATCH 18/19] perf ftrace: Show leaf-functions as oneliner Namhyung Kim
  2013-06-26  7:14 ` [PATCH 19/19] perf ftrace: Tidy up the function graph output of 'show' subcommand Namhyung Kim
  18 siblings, 0 replies; 43+ messages in thread
From: Namhyung Kim @ 2013-06-26  7:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, Namhyung Kim, LKML,
	Steven Rostedt, Frederic Weisbecker, Jiri Olsa, David Ahern,
	Stephane Eranian

From: Namhyung Kim <namhyung.kim@lge.com>

The --clock (-c) option is for controlling trace_clock.  Default to
'perf' if exists, or 'local'.

Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/builtin-ftrace.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
index 3b6bcc29715b..48dc54851765 100644
--- a/tools/perf/builtin-ftrace.c
+++ b/tools/perf/builtin-ftrace.c
@@ -35,6 +35,7 @@ struct perf_ftrace {
 	struct perf_target target;
 	const char *tracer;
 	const char *dirname;
+	const char *clock;
 	struct pevent *pevent;
 	bool show_full_info;
 };
@@ -113,6 +114,9 @@ static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused)
 	if (reset_tracing_cpu() < 0)
 		return -1;
 
+	if (write_tracing_file("trace_clock", "local") < 0)
+		return -1;
+
 	return 0;
 }
 
@@ -187,6 +191,24 @@ static int reset_tracing_cpu(void)
 	return 0;
 }
 
+static int set_tracing_clock(struct perf_ftrace *ftrace)
+{
+	const char *clock = ftrace->clock;
+
+	if (clock == NULL)
+		clock = "perf";
+
+	if (!write_tracing_file("trace_clock", clock))
+		return 0;
+
+	/* exit if user specified an invalid clock */
+	if (ftrace->clock)
+		return -1;
+
+	pr_debug("'perf' clock is not supported.. falling back to 'local' clock\n");
+	return write_tracing_file("trace_clock", "local");
+}
+
 static int setup_tracing_files(struct perf_ftrace *ftrace)
 {
 	int ret = -1;
@@ -212,6 +234,11 @@ static int setup_tracing_files(struct perf_ftrace *ftrace)
 		goto out;
 	}
 
+	if (set_tracing_clock(ftrace) < 0) {
+		pr_err("failed to set trace clock\n");
+		goto out;
+	}
+
 	if (write_tracing_file("current_tracer", ftrace->tracer) < 0) {
 		pr_err("failed to set current_tracer to %s\n", ftrace->tracer);
 		goto out;
@@ -1445,6 +1472,8 @@ __cmd_ftrace_live(struct perf_ftrace *ftrace, int argc, const char **argv)
 		    "system-wide collection from all CPUs"),
 	OPT_STRING('C', "cpu", &ftrace->target.cpu_list, "cpu",
 		    "list of cpus to monitor"),
+	OPT_STRING('c', "clock", &ftrace->clock, "clock",
+		    "clock to be used for tracer"),
 	OPT_END()
 	};
 
@@ -1487,6 +1516,8 @@ __cmd_ftrace_record(struct perf_ftrace *ftrace, int argc, const char **argv)
 		    "list of cpus to monitor"),
 	OPT_STRING('o', "output", &ftrace->dirname, "dirname",
 		   "input directory name to use (default: perf.data)"),
+	OPT_STRING('c', "clock", &ftrace->clock, "clock",
+		    "clock to be used for tracer"),
 	OPT_END()
 	};
 
-- 
1.7.11.7


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

* [PATCH 18/19] perf ftrace: Show leaf-functions as oneliner
  2013-06-26  7:14 [PATCHSET 00/19] perf tools: Introduce new 'ftrace' command (v3) Namhyung Kim
                   ` (16 preceding siblings ...)
  2013-06-26  7:14 ` [PATCH 17/19] perf ftrace: Add --clock option Namhyung Kim
@ 2013-06-26  7:14 ` Namhyung Kim
  2013-06-26  7:14 ` [PATCH 19/19] perf ftrace: Tidy up the function graph output of 'show' subcommand Namhyung Kim
  18 siblings, 0 replies; 43+ messages in thread
From: Namhyung Kim @ 2013-06-26  7:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, Namhyung Kim, LKML,
	Steven Rostedt, Frederic Weisbecker, Jiri Olsa, David Ahern,
	Stephane Eranian

From: Namhyung Kim <namhyung.kim@lge.com>

Detect leaf functions and print them in a same line.

Note that it only converts leaf-functions that doesn't have any other
records between entry and exit even in other cpus.  I left other leaf
functions as is.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/builtin-ftrace.c | 87 +++++++++++++++++++++++++++++++++++++++------
 1 file changed, 76 insertions(+), 11 deletions(-)

diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
index 48dc54851765..f17269db3121 100644
--- a/tools/perf/builtin-ftrace.c
+++ b/tools/perf/builtin-ftrace.c
@@ -860,34 +860,77 @@ function_handler(struct trace_seq *s, struct pevent_record *record,
 
 #define TRACE_GRAPH_INDENT  2
 
+static struct pevent_record *peek_ordered_record(struct perf_ftrace *ftrace);
+static struct pevent_record *get_ordered_record(struct perf_ftrace *ftrace);
+
+static struct event_format *fgraph_exit_event;
+
 static int
 fgraph_ent_handler(struct trace_seq *s, struct pevent_record *record,
-		   struct event_format *event, void *context __maybe_unused)
+		   struct event_format *event, void *context)
 {
 	unsigned long long depth;
 	unsigned long long val;
 	const char *func;
+	struct perf_ftrace *ftrace = context;
+	struct pevent_record *next;
+	bool is_leaf = false;
+	bool needs_free = false;
+	void *data;
+	int ret = -1;
 	int i;
 
+	/*
+	 * record->data can be invalidated after calling peek_ordered_record()
+	 * because it can unmap the current kbuffer page.  Make a copy.
+	 */
+	data = malloc(record->size);
+	if (data == NULL)
+		goto nested;
+
+	memcpy(data, record->data, record->size);
+	record->data = data;
+	needs_free = true;
+
+	/* detect leaf function and make it one-liner */
+	next = peek_ordered_record(ftrace);
+	if (next && next->cpu == record->cpu &&
+	    pevent_data_type(event->pevent, next) == fgraph_exit_event->id) {
+		is_leaf = true;
+		/* consume record */
+		get_ordered_record(ftrace);
+		free(next);
+	}
+
+nested:
 	if (pevent_get_field_val(s, event, "depth", record, &depth, 1))
-		return trace_seq_putc(s, '!');
+		goto out;
 
 	/* Function */
 	for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
 		trace_seq_putc(s, ' ');
 
 	if (pevent_get_field_val(s, event, "func", record, &val, 1))
-		return trace_seq_putc(s, '!');
+		goto out;
 
 	func = pevent_find_function(event->pevent, val);
 
 	if (func)
-		trace_seq_printf(s, "%s() {", func);
+		trace_seq_printf(s, "%s()", func);
 	else
-		trace_seq_printf(s, "%llx() {", val);
+		trace_seq_printf(s, "%llx()", val);
 
-	trace_seq_putc(s, '\n');
-	return 0;
+	if (is_leaf)
+		trace_seq_puts(s, ";\n");
+	else
+		trace_seq_puts(s, " {\n");
+
+	ret = 0;
+out:
+	if (needs_free)
+		free(record->data);
+
+	return ret;
 }
 
 static int
@@ -1069,7 +1112,8 @@ get_ftrace_event_record(struct perf_ftrace *ftrace,
 	return fra->record;
 }
 
-static struct pevent_record *get_ordered_record(struct perf_ftrace *ftrace)
+static struct ftrace_report_arg *
+__get_ordered_record(struct perf_ftrace *ftrace)
 {
 	struct ftrace_report_arg *fra = NULL;
 	struct ftrace_report_arg *tmp;
@@ -1097,9 +1141,26 @@ static struct pevent_record *get_ordered_record(struct perf_ftrace *ftrace)
 			fra = tmp;
 		}
 	}
+	return fra;
+}
+
+static struct pevent_record *peek_ordered_record(struct perf_ftrace *ftrace)
+{
+	struct ftrace_report_arg *fra = __get_ordered_record(ftrace);
+
+	if (fra)
+		return fra->record;
+
+	return NULL;
+}
+
+static struct pevent_record *get_ordered_record(struct perf_ftrace *ftrace)
+{
+	struct ftrace_report_arg *fra = __get_ordered_record(ftrace);
 
 	if (fra) {
-		record = fra->record;
+		struct pevent_record *record = fra->record;
+
 		fra->record = NULL;
 		return record;
 	}
@@ -1153,10 +1214,10 @@ static int do_ftrace_show(struct perf_ftrace *ftrace)
 				      function_handler, NULL);
 	pevent_register_event_handler(ftrace->pevent, -1,
 				      "ftrace", "funcgraph_entry",
-				      fgraph_ent_handler, NULL);
+				      fgraph_ent_handler, ftrace);
 	pevent_register_event_handler(ftrace->pevent, -1,
 				      "ftrace", "funcgraph_exit",
-				      fgraph_ret_handler, NULL);
+				      fgraph_ret_handler, ftrace);
 
 	if (perf_session__process_events(session, &show.tool) < 0) {
 		pr_err("failed to process events\n");
@@ -1164,6 +1225,10 @@ static int do_ftrace_show(struct perf_ftrace *ftrace)
 		goto out;
 	}
 
+	fgraph_exit_event = pevent_find_event_by_name(ftrace->pevent, "ftrace",
+						     "funcgraph_exit");
+	BUG_ON(fgraph_exit_event == NULL);
+
 	trace_seq_init(&seq);
 
 	record = get_ordered_record(ftrace);
-- 
1.7.11.7


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

* [PATCH 19/19] perf ftrace: Tidy up the function graph output of 'show' subcommand
  2013-06-26  7:14 [PATCHSET 00/19] perf tools: Introduce new 'ftrace' command (v3) Namhyung Kim
                   ` (17 preceding siblings ...)
  2013-06-26  7:14 ` [PATCH 18/19] perf ftrace: Show leaf-functions as oneliner Namhyung Kim
@ 2013-06-26  7:14 ` Namhyung Kim
  18 siblings, 0 replies; 43+ messages in thread
From: Namhyung Kim @ 2013-06-26  7:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, Namhyung Kim, LKML,
	Steven Rostedt, Frederic Weisbecker, Jiri Olsa, David Ahern,
	Stephane Eranian

From: Namhyung Kim <namhyung.kim@lge.com>

Now it doesn't call pevent_print_event() but prints context info in
itself using print_graph_duration().  Make it compact by only print
cpu number and duration:

  # perf ftrace show
  ...
   10)   0.065 us |  __fsnotify_parent();
   10)            |  fsnotify() {
   10)   0.060 us |    __srcu_read_lock();
   10)   0.040 us |    __srcu_read_unlock();
   10)   0.652 us |  }
   10)   0.040 us |  fput();
   10)            |  __audit_syscall_exit() {
   10)            |    path_put() {
   10)   0.037 us |      dput();
   10)   0.032 us |      mntput();
   10)   0.563 us |    }
   10)   0.035 us |    unroll_tree_refs();
   10)   0.035 us |    kfree();
   10)   1.284 us |  }
   10)            |  __audit_syscall_entry() {
   10)   0.029 us |    current_kernel_time();
   10)   0.239 us |  }


Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/builtin-ftrace.c | 35 +++++++++++++++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
index f17269db3121..7905b7b777d0 100644
--- a/tools/perf/builtin-ftrace.c
+++ b/tools/perf/builtin-ftrace.c
@@ -865,6 +865,27 @@ static struct pevent_record *get_ordered_record(struct perf_ftrace *ftrace);
 
 static struct event_format *fgraph_exit_event;
 
+static void
+print_graph_duration(struct trace_seq *s, struct event_format *event,
+		     struct pevent_record *record)
+{
+	unsigned long long duration;
+	unsigned long long rettime, calltime;
+	unsigned long usec, nsec;
+
+	if (pevent_get_field_val(s, event, "rettime", record, &rettime, 1))
+		return;
+
+	if (pevent_get_field_val(s, event, "calltime", record, &calltime, 1))
+		return;
+
+	duration = rettime - calltime;
+	usec = duration / 1000;
+	nsec = duration % 1000;
+
+	trace_seq_printf(s, "%3d) %3lu.%03lu us |  ", record->cpu, usec, nsec);
+}
+
 static int
 fgraph_ent_handler(struct trace_seq *s, struct pevent_record *record,
 		   struct event_format *event, void *context)
@@ -897,9 +918,14 @@ fgraph_ent_handler(struct trace_seq *s, struct pevent_record *record,
 	if (next && next->cpu == record->cpu &&
 	    pevent_data_type(event->pevent, next) == fgraph_exit_event->id) {
 		is_leaf = true;
+
+		print_graph_duration(s, fgraph_exit_event, next);
+
 		/* consume record */
 		get_ordered_record(ftrace);
 		free(next);
+	} else {
+		trace_seq_printf(s, "%3d) %*s |  ", record->cpu, 10, "");
 	}
 
 nested:
@@ -940,6 +966,8 @@ fgraph_ret_handler(struct trace_seq *s, struct pevent_record *record,
 	unsigned long long depth;
 	int i;
 
+	print_graph_duration(s, event, record);
+
 	if (pevent_get_field_val(s, event, "depth", record, &depth, 1))
 		return trace_seq_putc(s, '!');
 
@@ -1243,9 +1271,12 @@ static int do_ftrace_show(struct perf_ftrace *ftrace)
 			continue;
 		}
 
-		pevent_print_event(ftrace->pevent, &seq, record);
-		trace_seq_do_printf(&seq);
+		if (!strcmp(ftrace->tracer, "function_graph"))
+			pevent_event_info(&seq, event, record);
+		else
+			pevent_print_event(ftrace->pevent, &seq, record);
 
+		trace_seq_do_printf(&seq);
 		trace_seq_reset(&seq);
 
 		free(record);
-- 
1.7.11.7


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

* Re: [PATCH 05/19] perf tools: Introduce new 'ftrace' tool
  2013-06-26  7:14 ` [PATCH 05/19] perf tools: Introduce new 'ftrace' tool Namhyung Kim
@ 2013-06-26 17:10   ` David Ahern
  2013-06-27  5:04     ` Namhyung Kim
  0 siblings, 1 reply; 43+ messages in thread
From: David Ahern @ 2013-06-26 17:10 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Paul Mackerras,
	Ingo Molnar, Namhyung Kim, LKML, Steven Rostedt,
	Frederic Weisbecker, Jiri Olsa, Stephane Eranian

On 6/26/13 1:14 AM, Namhyung Kim wrote:
> +	const char * const ftrace_usage[] = {
> +		"perf ftrace [<options>] [<command>]",
> +		"perf ftrace [<options>] -- <command> [<options>]",
> +		NULL
> +	};
> +	const struct option ftrace_options[] = {
> +	OPT_STRING('t', "tracer", &ftrace.tracer, "tracer",
> +		   "tracer to use"),

How does a user know what is a valid tracer string?

David

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

* Re: [PATCH 06/19] perf ftrace: Add support for --pid option
  2013-06-26  7:14 ` [PATCH 06/19] perf ftrace: Add support for --pid option Namhyung Kim
@ 2013-06-26 17:12   ` David Ahern
  2013-06-27  5:23     ` Namhyung Kim
  2013-07-10 14:18   ` Jiri Olsa
  1 sibling, 1 reply; 43+ messages in thread
From: David Ahern @ 2013-06-26 17:12 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Paul Mackerras,
	Ingo Molnar, Namhyung Kim, LKML, Steven Rostedt,
	Frederic Weisbecker, Jiri Olsa, Stephane Eranian

On 6/26/13 1:14 AM, Namhyung Kim wrote:
> @@ -196,6 +222,8 @@ int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
>   	const struct option ftrace_options[] = {
>   	OPT_STRING('t', "tracer", &ftrace.tracer, "tracer",
>   		   "tracer to use"),
> +	OPT_STRING('p', "pid", &ftrace.target.tid, "pid",
> +		   "trace on existing process id"),
>   	OPT_INCR('v', "verbose", &verbose,
>   		 "be more verbose"),
>   	OPT_END()

You are calling it pid but assigning it as a tid which is inconsistent 
with other perf commands. e.g., perf-record allows a list of pids (-p) 
or tids (-t). Why not support that in perf-ftrace? And that leads to the 
comment about consistency of options across perf commands: -t is used 
here for tracer type to use.

David


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

* Re: [PATCH 05/19] perf tools: Introduce new 'ftrace' tool
  2013-06-26 17:10   ` David Ahern
@ 2013-06-27  5:04     ` Namhyung Kim
  2013-06-27 13:51       ` David Ahern
  0 siblings, 1 reply; 43+ messages in thread
From: Namhyung Kim @ 2013-06-27  5:04 UTC (permalink / raw)
  To: David Ahern
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Paul Mackerras,
	Ingo Molnar, Namhyung Kim, LKML, Steven Rostedt,
	Frederic Weisbecker, Jiri Olsa, Stephane Eranian

Hi David,

On Wed, 26 Jun 2013 11:10:34 -0600, David Ahern wrote:
> On 6/26/13 1:14 AM, Namhyung Kim wrote:
>> +	const char * const ftrace_usage[] = {
>> +		"perf ftrace [<options>] [<command>]",
>> +		"perf ftrace [<options>] -- <command> [<options>]",
>> +		NULL
>> +	};
>> +	const struct option ftrace_options[] = {
>> +	OPT_STRING('t', "tracer", &ftrace.tracer, "tracer",
>> +		   "tracer to use"),
>
> How does a user know what is a valid tracer string?

The helpline should look like (at least):

  "tracer to use: function_graph or function"

I'll update it in the next spin.

Thanks,
Namhyung

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

* Re: [PATCH 06/19] perf ftrace: Add support for --pid option
  2013-06-26 17:12   ` David Ahern
@ 2013-06-27  5:23     ` Namhyung Kim
  2013-06-27 13:56       ` David Ahern
  0 siblings, 1 reply; 43+ messages in thread
From: Namhyung Kim @ 2013-06-27  5:23 UTC (permalink / raw)
  To: David Ahern
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Paul Mackerras,
	Ingo Molnar, Namhyung Kim, LKML, Steven Rostedt,
	Frederic Weisbecker, Jiri Olsa, Stephane Eranian

On Wed, 26 Jun 2013 11:12:19 -0600, David Ahern wrote:
> On 6/26/13 1:14 AM, Namhyung Kim wrote:
>> @@ -196,6 +222,8 @@ int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
>>   	const struct option ftrace_options[] = {
>>   	OPT_STRING('t', "tracer", &ftrace.tracer, "tracer",
>>   		   "tracer to use"),
>> +	OPT_STRING('p', "pid", &ftrace.target.tid, "pid",
>> +		   "trace on existing process id"),
>>   	OPT_INCR('v', "verbose", &verbose,
>>   		 "be more verbose"),
>>   	OPT_END()
>
> You are calling it pid but assigning it as a tid which is inconsistent
> with other perf commands. e.g., perf-record allows a list of pids (-p)
> or tids (-t). Why not support that in perf-ftrace? And that leads to
> the comment about consistency of options across perf commands: -t is
> used here for tracer type to use.

Sorry, I should've mentioned it.

The pid filtering in ftrace is done via set_ftrace_pid file under the
tracing debugfs directory.  IIRC It only supports process filtering not
thread filtering by iterating all threads in the kernel code.  So --tid
option cannot be implemented as other perf commands.

So I chose not to and assigned -t option to --tracer.

Thanks,
Namhyung

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

* Re: [PATCH 05/19] perf tools: Introduce new 'ftrace' tool
  2013-06-27  5:04     ` Namhyung Kim
@ 2013-06-27 13:51       ` David Ahern
  2013-06-27 14:22         ` Namhyung Kim
  0 siblings, 1 reply; 43+ messages in thread
From: David Ahern @ 2013-06-27 13:51 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Paul Mackerras,
	Ingo Molnar, Namhyung Kim, LKML, Steven Rostedt,
	Frederic Weisbecker, Jiri Olsa, Stephane Eranian

On 6/26/13 11:04 PM, Namhyung Kim wrote:
> Hi David,
>
> On Wed, 26 Jun 2013 11:10:34 -0600, David Ahern wrote:
>> On 6/26/13 1:14 AM, Namhyung Kim wrote:
>>> +	const char * const ftrace_usage[] = {
>>> +		"perf ftrace [<options>] [<command>]",
>>> +		"perf ftrace [<options>] -- <command> [<options>]",
>>> +		NULL
>>> +	};
>>> +	const struct option ftrace_options[] = {
>>> +	OPT_STRING('t', "tracer", &ftrace.tracer, "tracer",
>>> +		   "tracer to use"),
>>
>> How does a user know what is a valid tracer string?
>
> The helpline should look like (at least):
>
>    "tracer to use: function_graph or function"

exactly. I would suggest making that OPT_CALLBACK as well to validate 
the string content when options are parsed.

David



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

* Re: [PATCH 06/19] perf ftrace: Add support for --pid option
  2013-06-27  5:23     ` Namhyung Kim
@ 2013-06-27 13:56       ` David Ahern
  2013-06-27 14:12         ` Namhyung Kim
  0 siblings, 1 reply; 43+ messages in thread
From: David Ahern @ 2013-06-27 13:56 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Paul Mackerras,
	Ingo Molnar, Namhyung Kim, LKML, Steven Rostedt,
	Frederic Weisbecker, Jiri Olsa, Stephane Eranian

On 6/26/13 11:23 PM, Namhyung Kim wrote:
> On Wed, 26 Jun 2013 11:12:19 -0600, David Ahern wrote:
>> On 6/26/13 1:14 AM, Namhyung Kim wrote:
>>> @@ -196,6 +222,8 @@ int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
>>>    	const struct option ftrace_options[] = {
>>>    	OPT_STRING('t', "tracer", &ftrace.tracer, "tracer",
>>>    		   "tracer to use"),
>>> +	OPT_STRING('p', "pid", &ftrace.target.tid, "pid",
>>> +		   "trace on existing process id"),
>>>    	OPT_INCR('v', "verbose", &verbose,
>>>    		 "be more verbose"),
>>>    	OPT_END()
>>
>> You are calling it pid but assigning it as a tid which is inconsistent
>> with other perf commands. e.g., perf-record allows a list of pids (-p)
>> or tids (-t). Why not support that in perf-ftrace? And that leads to
>> the comment about consistency of options across perf commands: -t is
>> used here for tracer type to use.
>
> Sorry, I should've mentioned it.
>
> The pid filtering in ftrace is done via set_ftrace_pid file under the
> tracing debugfs directory.  IIRC It only supports process filtering not
> thread filtering by iterating all threads in the kernel code.  So --tid
> option cannot be implemented as other perf commands.
>
> So I chose not to and assigned -t option to --tracer.

Could that ever change? With the current code why call it pid in the 
option but assign it to target.tid? Seems a like a source for confusion 
later. Would be better to just assign to target.pid and let the 
machinery do the right thing.

David


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

* Re: [PATCH 06/19] perf ftrace: Add support for --pid option
  2013-06-27 13:56       ` David Ahern
@ 2013-06-27 14:12         ` Namhyung Kim
  0 siblings, 0 replies; 43+ messages in thread
From: Namhyung Kim @ 2013-06-27 14:12 UTC (permalink / raw)
  To: David Ahern
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Paul Mackerras,
	Ingo Molnar, Namhyung Kim, LKML, Steven Rostedt,
	Frederic Weisbecker, Jiri Olsa, Stephane Eranian

2013-06-27 (목), 07:56 -0600, David Ahern:
> On 6/26/13 11:23 PM, Namhyung Kim wrote:
> > The pid filtering in ftrace is done via set_ftrace_pid file under the
> > tracing debugfs directory.  IIRC It only supports process filtering not
> > thread filtering by iterating all threads in the kernel code.  So --tid
> > option cannot be implemented as other perf commands.
> >
> > So I chose not to and assigned -t option to --tracer.
> 
> Could that ever change? With the current code why call it pid in the 
> option but assign it to target.tid? Seems a like a source for confusion 

Hmm.. right.  I did it in order not to do same iteration of the thread
group in user space.  But now I think that it's just an unnecessary
optimization and can confuse readers.


> later. Would be better to just assign to target.pid and let the 
> machinery do the right thing.

Will do.

Thanks,
Namhyung



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

* Re: [PATCH 05/19] perf tools: Introduce new 'ftrace' tool
  2013-06-27 13:51       ` David Ahern
@ 2013-06-27 14:22         ` Namhyung Kim
  0 siblings, 0 replies; 43+ messages in thread
From: Namhyung Kim @ 2013-06-27 14:22 UTC (permalink / raw)
  To: David Ahern
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Paul Mackerras,
	Ingo Molnar, Namhyung Kim, LKML, Steven Rostedt,
	Frederic Weisbecker, Jiri Olsa, Stephane Eranian

2013-06-27 (목), 07:51 -0600, David Ahern:
> On 6/26/13 11:04 PM, Namhyung Kim wrote:
> > Hi David,
> >
> > On Wed, 26 Jun 2013 11:10:34 -0600, David Ahern wrote:
> >> On 6/26/13 1:14 AM, Namhyung Kim wrote:
> >>> +	const char * const ftrace_usage[] = {
> >>> +		"perf ftrace [<options>] [<command>]",
> >>> +		"perf ftrace [<options>] -- <command> [<options>]",
> >>> +		NULL
> >>> +	};
> >>> +	const struct option ftrace_options[] = {
> >>> +	OPT_STRING('t', "tracer", &ftrace.tracer, "tracer",
> >>> +		   "tracer to use"),
> >>
> >> How does a user know what is a valid tracer string?
> >
> > The helpline should look like (at least):
> >
> >    "tracer to use: function_graph or function"
> 
> exactly. I would suggest making that OPT_CALLBACK as well to validate 
> the string content when options are parsed.

Did you mean it by checking /sys/kernel/debug/tracing/available_tracers?

Yes, I can do that.  But current code does not support other tracers and
it'd anyway emit warning on an invalid tracer argument.

Thanks,
Namhyung


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

* Re: [PATCH 06/19] perf ftrace: Add support for --pid option
  2013-06-26  7:14 ` [PATCH 06/19] perf ftrace: Add support for --pid option Namhyung Kim
  2013-06-26 17:12   ` David Ahern
@ 2013-07-10 14:18   ` Jiri Olsa
  2013-07-11  7:56     ` Namhyung Kim
  1 sibling, 1 reply; 43+ messages in thread
From: Jiri Olsa @ 2013-07-10 14:18 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Paul Mackerras,
	Ingo Molnar, Namhyung Kim, LKML, Steven Rostedt,
	Frederic Weisbecker, David Ahern, Stephane Eranian

On Wed, Jun 26, 2013 at 04:14:09PM +0900, Namhyung Kim wrote:
> From: Namhyung Kim <namhyung.kim@lge.com>
> 
> The -p (--pid) option enables to trace existing process by its pid.

hi,
I can't get any output from -p for live subcommand:

[jolsa@krava perf]$ pgrep yes
6443
[jolsa@krava perf]$ sudo ./perf ftrace live -p `pgrep yes`

jirka

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

* Re: [PATCH 15/19] perf tools: Add document for perf-ftrace command
  2013-06-26  7:14 ` [PATCH 15/19] perf tools: Add document for perf-ftrace command Namhyung Kim
@ 2013-07-10 14:22   ` Jiri Olsa
  2013-07-11  8:18     ` Namhyung Kim
  0 siblings, 1 reply; 43+ messages in thread
From: Jiri Olsa @ 2013-07-10 14:22 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Paul Mackerras,
	Ingo Molnar, Namhyung Kim, LKML, Steven Rostedt,
	Frederic Weisbecker, David Ahern, Stephane Eranian

On Wed, Jun 26, 2013 at 04:14:18PM +0900, Namhyung Kim wrote:
> From: Namhyung Kim <namhyung.kim@lge.com>
> 
> Cc: Steven Rostedt <rostedt@goodmis.org>
> Cc: Frederic Weisbecker <fweisbec@gmail.com>
> Signed-off-by: Namhyung Kim <namhyung@kernel.org>
> ---

SNIP

> +OPTIONS
> +-------
> +<command>...::
> +	Any command you can specify in a shell.
> +
> +-t::
> +--tracer=::
> +        The ftrace tracer to be used (default: function_graph).
> +	Currently only 'function' and 'function_graph' are supported.
> +        Used by 'live' and 'record' subcommands only.

hum, 'live' subcommand  supports whatever is available in
'available_tracers' file, right?

and displays whatever gets into 'trace' .. which I think
is useful and should stay like that

jirka

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

* Re: [PATCH 09/19] perf ftrace: Add 'record' sub-command
  2013-06-26  7:14 ` [PATCH 09/19] perf ftrace: Add 'record' sub-command Namhyung Kim
@ 2013-07-10 14:28   ` Jiri Olsa
  2013-07-11  8:00     ` Namhyung Kim
  0 siblings, 1 reply; 43+ messages in thread
From: Jiri Olsa @ 2013-07-10 14:28 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Paul Mackerras,
	Ingo Molnar, Namhyung Kim, LKML, Steven Rostedt,
	Frederic Weisbecker, David Ahern, Stephane Eranian

On Wed, Jun 26, 2013 at 04:14:12PM +0900, Namhyung Kim wrote:
> From: Namhyung Kim <namhyung.kim@lge.com>

SNIP

> +
> +static int create_perf_directory(struct perf_ftrace *ftrace)
> +{
> +	int err;
> +	char buf[PATH_MAX];
> +	struct stat statbuf;
> +
> +	scnprintf(buf, sizeof(buf), "%s.dir", ftrace->dirname);
> +
> +	if (stat(buf, &statbuf) == 0) {
> +		/* same name already exists - rename to *.old.dir */
> +		char *old_name = malloc(strlen(buf) + 5);
> +		if (old_name == NULL)
> +			return -1;
> +
> +		scnprintf(old_name, strlen(buf) + 5,
> +			  "%s.old.dir", ftrace->dirname);
> +
> +		if (remove_directory(old_name) < 0) {
> +			perror("rmdir");
> +			return -1;
> +		}
> +
> +		if (rename(buf, old_name) < 0) {
> +			perror("rename");
> +			free(old_name);
> +			return -1;
> +		}
> +
> +		free(old_name);
> +	}
> +
> +	err = mkdir(buf, 0755);
> +	if (err < 0) {
> +		perror("mkdir");
> +		return -1;
> +	}
> +
> +	strcat(buf, "/perf.header");
> +
> +	err = open(buf, O_RDWR | O_CREAT | O_TRUNC, 0644);
> +	return err;
> +}

nitpick.. should this be rather be called create_perf_header,
which calls create_perf_directory inside?

jirka

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

* Re: [PATCH 10/19] perf ftrace: Add 'show' sub-command
  2013-06-26  7:14 ` [PATCH 10/19] perf ftrace: Add 'show' sub-command Namhyung Kim
@ 2013-07-10 14:41   ` Jiri Olsa
  2013-07-11  8:01     ` Namhyung Kim
  0 siblings, 1 reply; 43+ messages in thread
From: Jiri Olsa @ 2013-07-10 14:41 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Paul Mackerras,
	Ingo Molnar, Namhyung Kim, LKML, Steven Rostedt,
	Frederic Weisbecker, David Ahern, Stephane Eranian

On Wed, Jun 26, 2013 at 04:14:13PM +0900, Namhyung Kim wrote:
> From: Namhyung Kim <namhyung.kim@lge.com>
> 
> The ftrace show subcommand is for viewing recorded ftrace files.  It
> enters perf.data.dir directory and open perf.header file to find out
> necessary information.  And then read out per-cpu trace records using
> kbuffer helper and print them to stdout in time order.
> 
> It only shows its basic form so function graph doesn't show duration/
> overhead and no leaf entry handling is provided yet.  Maybe it can be
> handled by a proper plugin in the libtraceevent.
> 

[jolsa@krava perf]$ sudo ./perf ftrace show -i perf.data.dir/
failed to open perf.data.dir/.dir/perf.header: No such file or directory

I'd expect any directory name is possible

jirka

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

* Re: [PATCH 11/19] perf ftrace: Add 'report' sub-command
  2013-06-26  7:14 ` [PATCH 11/19] perf ftrace: Add 'report' sub-command Namhyung Kim
@ 2013-07-10 14:45   ` Jiri Olsa
  2013-07-11  8:10     ` Namhyung Kim
  0 siblings, 1 reply; 43+ messages in thread
From: Jiri Olsa @ 2013-07-10 14:45 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Paul Mackerras,
	Ingo Molnar, Namhyung Kim, LKML, Steven Rostedt,
	Frederic Weisbecker, David Ahern, Stephane Eranian

On Wed, Jun 26, 2013 at 04:14:14PM +0900, Namhyung Kim wrote:

SNIP

>  
> +static int
> +__cmd_ftrace_report(struct perf_ftrace *ftrace, int argc, const char **argv)
> +{
> +	int ret = -1;
> +	const char * const report_usage[] = {
> +		"perf ftrace report [<options>]",
> +		NULL
> +	};
> +	const struct option report_options[] = {
> +	OPT_STRING('i', "input", &ftrace->dirname, "dirname",
> +		   "input directory name to use (default: perf.data)"),
> +	OPT_INCR('v', "verbose", &verbose,
> +		 "be more verbose"),
> +	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
> +		    "dump raw trace in ASCII"),

not sure dump_trace is useful here, it's just the first cpu-x samples
and then following 2 lines repeated MANY times:

 ... thread: ls:30064
 ...... dso: [kernel.kallsyms]

I guess you need this to verify first SAMPLEs?

jirka

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

* Re: [PATCH 06/19] perf ftrace: Add support for --pid option
  2013-07-10 14:18   ` Jiri Olsa
@ 2013-07-11  7:56     ` Namhyung Kim
  2013-07-18  6:38       ` Namhyung Kim
  0 siblings, 1 reply; 43+ messages in thread
From: Namhyung Kim @ 2013-07-11  7:56 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Paul Mackerras,
	Ingo Molnar, Namhyung Kim, LKML, Steven Rostedt,
	Frederic Weisbecker, David Ahern, Stephane Eranian

On Wed, 10 Jul 2013 16:18:20 +0200, Jiri Olsa wrote:
> On Wed, Jun 26, 2013 at 04:14:09PM +0900, Namhyung Kim wrote:
>> From: Namhyung Kim <namhyung.kim@lge.com>
>> 
>> The -p (--pid) option enables to trace existing process by its pid.
>
> hi,
> I can't get any output from -p for live subcommand:
>
> [jolsa@krava perf]$ pgrep yes
> 6443
> [jolsa@krava perf]$ sudo ./perf ftrace live -p `pgrep yes`

Hmm... looks like it's stuck on polling the trace_pipe:

  $ sudo strace ./perf ftrace -p `pgrep yes'
  ...
  poll([{fd=3, events=POLLIN}], 1, 4294967295


Need to investigate it more.

Along with it, I found that I didn't close fd in
__write_tracing_file().  I'll fix it in the next spin too.

Thanks for the review and testing!
Namhyung

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

* Re: [PATCH 09/19] perf ftrace: Add 'record' sub-command
  2013-07-10 14:28   ` Jiri Olsa
@ 2013-07-11  8:00     ` Namhyung Kim
  0 siblings, 0 replies; 43+ messages in thread
From: Namhyung Kim @ 2013-07-11  8:00 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Paul Mackerras,
	Ingo Molnar, Namhyung Kim, LKML, Steven Rostedt,
	Frederic Weisbecker, David Ahern, Stephane Eranian

On Wed, 10 Jul 2013 16:28:21 +0200, Jiri Olsa wrote:
> On Wed, Jun 26, 2013 at 04:14:12PM +0900, Namhyung Kim wrote:
>> From: Namhyung Kim <namhyung.kim@lge.com>
>
> SNIP
>
>> +
>> +static int create_perf_directory(struct perf_ftrace *ftrace)
>> +{
>> +	int err;
>> +	char buf[PATH_MAX];
>> +	struct stat statbuf;
>> +
>> +	scnprintf(buf, sizeof(buf), "%s.dir", ftrace->dirname);
>> +
>> +	if (stat(buf, &statbuf) == 0) {
>> +		/* same name already exists - rename to *.old.dir */
>> +		char *old_name = malloc(strlen(buf) + 5);
>> +		if (old_name == NULL)
>> +			return -1;
>> +
>> +		scnprintf(old_name, strlen(buf) + 5,
>> +			  "%s.old.dir", ftrace->dirname);
>> +
>> +		if (remove_directory(old_name) < 0) {
>> +			perror("rmdir");
>> +			return -1;
>> +		}
>> +
>> +		if (rename(buf, old_name) < 0) {
>> +			perror("rename");
>> +			free(old_name);
>> +			return -1;
>> +		}
>> +
>> +		free(old_name);
>> +	}
>> +
>> +	err = mkdir(buf, 0755);
>> +	if (err < 0) {
>> +		perror("mkdir");
>> +		return -1;
>> +	}
>> +
>> +	strcat(buf, "/perf.header");
>> +
>> +	err = open(buf, O_RDWR | O_CREAT | O_TRUNC, 0644);
>> +	return err;
>> +}
>
> nitpick.. should this be rather be called create_perf_header,
> which calls create_perf_directory inside?

Looks reasonable.  I'll change the name.

Thanks,
Namhyung

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

* Re: [PATCH 10/19] perf ftrace: Add 'show' sub-command
  2013-07-10 14:41   ` Jiri Olsa
@ 2013-07-11  8:01     ` Namhyung Kim
  0 siblings, 0 replies; 43+ messages in thread
From: Namhyung Kim @ 2013-07-11  8:01 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Paul Mackerras,
	Ingo Molnar, Namhyung Kim, LKML, Steven Rostedt,
	Frederic Weisbecker, David Ahern, Stephane Eranian

On Wed, 10 Jul 2013 16:41:48 +0200, Jiri Olsa wrote:
> On Wed, Jun 26, 2013 at 04:14:13PM +0900, Namhyung Kim wrote:
>> From: Namhyung Kim <namhyung.kim@lge.com>
>> 
>> The ftrace show subcommand is for viewing recorded ftrace files.  It
>> enters perf.data.dir directory and open perf.header file to find out
>> necessary information.  And then read out per-cpu trace records using
>> kbuffer helper and print them to stdout in time order.
>> 
>> It only shows its basic form so function graph doesn't show duration/
>> overhead and no leaf entry handling is provided yet.  Maybe it can be
>> handled by a proper plugin in the libtraceevent.
>> 
>
> [jolsa@krava perf]$ sudo ./perf ftrace show -i perf.data.dir/
> failed to open perf.data.dir/.dir/perf.header: No such file or directory
>
> I'd expect any directory name is possible

Oops, right!  I should handle the case.

Thanks,
Namhyung

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

* Re: [PATCH 11/19] perf ftrace: Add 'report' sub-command
  2013-07-10 14:45   ` Jiri Olsa
@ 2013-07-11  8:10     ` Namhyung Kim
  0 siblings, 0 replies; 43+ messages in thread
From: Namhyung Kim @ 2013-07-11  8:10 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Paul Mackerras,
	Ingo Molnar, Namhyung Kim, LKML, Steven Rostedt,
	Frederic Weisbecker, David Ahern, Stephane Eranian

On Wed, 10 Jul 2013 16:45:39 +0200, Jiri Olsa wrote:
> On Wed, Jun 26, 2013 at 04:14:14PM +0900, Namhyung Kim wrote:
>
> SNIP
>
>>  
>> +static int
>> +__cmd_ftrace_report(struct perf_ftrace *ftrace, int argc, const char **argv)
>> +{
>> +	int ret = -1;
>> +	const char * const report_usage[] = {
>> +		"perf ftrace report [<options>]",
>> +		NULL
>> +	};
>> +	const struct option report_options[] = {
>> +	OPT_STRING('i', "input", &ftrace->dirname, "dirname",
>> +		   "input directory name to use (default: perf.data)"),
>> +	OPT_INCR('v', "verbose", &verbose,
>> +		 "be more verbose"),
>> +	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
>> +		    "dump raw trace in ASCII"),
>
> not sure dump_trace is useful here, it's just the first cpu-x samples
> and then following 2 lines repeated MANY times:
>
>  ... thread: ls:30064
>  ...... dso: [kernel.kallsyms]
>
> I guess you need this to verify first SAMPLEs?

I can't remember why exactly. ;-)

Probably I was thinking about adding more info like raw ftrace data.

Thanks,
Namhyung

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

* Re: [PATCH 15/19] perf tools: Add document for perf-ftrace command
  2013-07-10 14:22   ` Jiri Olsa
@ 2013-07-11  8:18     ` Namhyung Kim
  2013-07-11 11:43       ` Jiri Olsa
  0 siblings, 1 reply; 43+ messages in thread
From: Namhyung Kim @ 2013-07-11  8:18 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Paul Mackerras,
	Ingo Molnar, Namhyung Kim, LKML, Steven Rostedt,
	Frederic Weisbecker, David Ahern, Stephane Eranian

On Wed, 10 Jul 2013 16:22:19 +0200, Jiri Olsa wrote:
> On Wed, Jun 26, 2013 at 04:14:18PM +0900, Namhyung Kim wrote:
>> From: Namhyung Kim <namhyung.kim@lge.com>
>> 
>> Cc: Steven Rostedt <rostedt@goodmis.org>
>> Cc: Frederic Weisbecker <fweisbec@gmail.com>
>> Signed-off-by: Namhyung Kim <namhyung@kernel.org>
>> ---
>
> SNIP
>
>> +OPTIONS
>> +-------
>> +<command>...::
>> +	Any command you can specify in a shell.
>> +
>> +-t::
>> +--tracer=::
>> +        The ftrace tracer to be used (default: function_graph).
>> +	Currently only 'function' and 'function_graph' are supported.
>> +        Used by 'live' and 'record' subcommands only.
>
> hum, 'live' subcommand  supports whatever is available in
> 'available_tracers' file, right?
>
> and displays whatever gets into 'trace' .. which I think
> is useful and should stay like that

Agreed.  How about this?

	The ftrace tracer to be used (default: function_graph).
	Currently, only 'function' and 'function_graph' are
	supported by 'record' command. 'live' command accepts
	any available tracer in system and outputs trace result
	directly from the ftrace's trace_pipe.


Thanks,
Namhyung

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

* Re: [PATCH 15/19] perf tools: Add document for perf-ftrace command
  2013-07-11  8:18     ` Namhyung Kim
@ 2013-07-11 11:43       ` Jiri Olsa
  0 siblings, 0 replies; 43+ messages in thread
From: Jiri Olsa @ 2013-07-11 11:43 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Paul Mackerras,
	Ingo Molnar, Namhyung Kim, LKML, Steven Rostedt,
	Frederic Weisbecker, David Ahern, Stephane Eranian

On Thu, Jul 11, 2013 at 05:18:37PM +0900, Namhyung Kim wrote:
> On Wed, 10 Jul 2013 16:22:19 +0200, Jiri Olsa wrote:
> > On Wed, Jun 26, 2013 at 04:14:18PM +0900, Namhyung Kim wrote:
> >> From: Namhyung Kim <namhyung.kim@lge.com>
> >> 
> >> Cc: Steven Rostedt <rostedt@goodmis.org>
> >> Cc: Frederic Weisbecker <fweisbec@gmail.com>
> >> Signed-off-by: Namhyung Kim <namhyung@kernel.org>
> >> ---
> >
> > SNIP
> >
> >> +OPTIONS
> >> +-------
> >> +<command>...::
> >> +	Any command you can specify in a shell.
> >> +
> >> +-t::
> >> +--tracer=::
> >> +        The ftrace tracer to be used (default: function_graph).
> >> +	Currently only 'function' and 'function_graph' are supported.
> >> +        Used by 'live' and 'record' subcommands only.
> >
> > hum, 'live' subcommand  supports whatever is available in
> > 'available_tracers' file, right?
> >
> > and displays whatever gets into 'trace' .. which I think
> > is useful and should stay like that
> 
> Agreed.  How about this?
> 
> 	The ftrace tracer to be used (default: function_graph).
> 	Currently, only 'function' and 'function_graph' are
> 	supported by 'record' command. 'live' command accepts
> 	any available tracer in system and outputs trace result
> 	directly from the ftrace's trace_pipe.

sounds good

jirka

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

* [tip:perf/urgent] perf evlist: Enhance perf_evlist__start_workload()
  2013-06-26  7:14 ` [PATCH 12/19] perf evlist: Enhance perf_evlist__start_workload() Namhyung Kim
@ 2013-07-12  8:50   ` tip-bot for Namhyung Kim
  0 siblings, 0 replies; 43+ messages in thread
From: tip-bot for Namhyung Kim @ 2013-07-12  8:50 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, eranian, paulus, hpa, mingo, a.p.zijlstra,
	namhyung.kim, namhyung, jolsa, fweisbec, rostedt, dsahern, tglx

Commit-ID:  bcf3145fbeb1bd91ad2ca67b1946077530f7bfb1
Gitweb:     http://git.kernel.org/tip/bcf3145fbeb1bd91ad2ca67b1946077530f7bfb1
Author:     Namhyung Kim <namhyung.kim@lge.com>
AuthorDate: Wed, 26 Jun 2013 16:14:15 +0900
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Mon, 8 Jul 2013 17:38:30 -0300

perf evlist: Enhance perf_evlist__start_workload()

When perf tries to start a workload, it relies on a pipe which the
workload was blocked for reading.  After closing the pipe on the parent,
the workload (child) can start the actual work via exec().

However, if another process was forked after creating a workload, this
mechanism cannot work since the other process (child) also inherits the
pipe, so that closing the pipe in parent cannot unblock the workload.
Fix it by using explicit write call can then closing it.

For similar reason, the pipe fd on parent should be marked as CLOEXEC so
that it can be closed after another child exec'ed.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Link: http://lkml.kernel.org/r/1372230862-15861-13-git-send-email-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/evlist.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 99b43dd..8065ce8 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -821,6 +821,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
 		goto out_close_pipes;
 	}
 
+	fcntl(go_pipe[1], F_SETFD, FD_CLOEXEC);
 	evlist->workload.cork_fd = go_pipe[1];
 	close(child_ready_pipe[0]);
 	return 0;
@@ -837,10 +838,17 @@ out_close_ready_pipe:
 int perf_evlist__start_workload(struct perf_evlist *evlist)
 {
 	if (evlist->workload.cork_fd > 0) {
+		char bf;
+		int ret;
 		/*
 		 * Remove the cork, let it rip!
 		 */
-		return close(evlist->workload.cork_fd);
+		ret = write(evlist->workload.cork_fd, &bf, 1);
+		if (ret < 0)
+			perror("enable to write to pipe");
+
+		close(evlist->workload.cork_fd);
+		return ret;
 	}
 
 	return 0;

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

* Re: [PATCH 06/19] perf ftrace: Add support for --pid option
  2013-07-11  7:56     ` Namhyung Kim
@ 2013-07-18  6:38       ` Namhyung Kim
  0 siblings, 0 replies; 43+ messages in thread
From: Namhyung Kim @ 2013-07-18  6:38 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Paul Mackerras,
	Ingo Molnar, Namhyung Kim, LKML, Steven Rostedt,
	Frederic Weisbecker, David Ahern, Stephane Eranian

Hi Jiri,

On Thu, 11 Jul 2013 16:56:54 +0900, Namhyung Kim wrote:
> On Wed, 10 Jul 2013 16:18:20 +0200, Jiri Olsa wrote:
>> On Wed, Jun 26, 2013 at 04:14:09PM +0900, Namhyung Kim wrote:
>>> From: Namhyung Kim <namhyung.kim@lge.com>
>>> 
>>> The -p (--pid) option enables to trace existing process by its pid.
>>
>> hi,
>> I can't get any output from -p for live subcommand:
>>
>> [jolsa@krava perf]$ pgrep yes
>> 6443
>> [jolsa@krava perf]$ sudo ./perf ftrace live -p `pgrep yes`
>
> Hmm... looks like it's stuck on polling the trace_pipe:
>
>   $ sudo strace ./perf ftrace -p `pgrep yes'
>   ...
>   poll([{fd=3, events=POLLIN}], 1, 4294967295
>
>
> Need to investigate it more.

What's your kernel version?  My kernel was 3.6.9.  I guess there's a
problem with trace_pipe's poll implementation on pre-3.10 kernels which
was fixed by:

commit cc60cdc952be09bca5b0bff9fefc7aa6185c3049
Author: Steven Rostedt <srostedt@redhat.com>
Date:   Thu Feb 28 09:17:16 2013 -0500

    tracing: Fix polling on trace_pipe_raw
    
    The trace_pipe_raw never implemented polling and this was casing
    issues for several utilities. This is now implemented.
    
    Blocked reads still are on the TODO list.
    
    Reported-by: Mauro Carvalho Chehab <mchehab@redhat.com>
    Tested-by: Mauro Carvalho Chehab <mchehab@redhat.com>
    Signed-off-by: Steven Rostedt <rostedt@goodmis.org>


It seems recent kernel doesn't have this issue.  Could you confirm that?

Anyway, I decided not to use poll() here since all recorders only read
one file and it'll provide better compatibility.  I will use
non-blocking read() + nanosleep() as trace-cmd does.

Thanks,
Namhyung

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

* [tip:perf/core] perf util: Move debugfs/ tracing helper functions to util.c
  2013-06-26  7:14 ` [PATCH 01/19] perf util: Move debugfs/tracing helper functions to util.c Namhyung Kim
@ 2013-07-19  7:43   ` tip-bot for Namhyung Kim
  0 siblings, 0 replies; 43+ messages in thread
From: tip-bot for Namhyung Kim @ 2013-07-19  7:43 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, eranian, paulus, hpa, mingo, a.p.zijlstra,
	namhyung.kim, namhyung, jolsa, fweisbec, rostedt, dsahern, tglx

Commit-ID:  167aedc44e1743777e6aee71b0fe7ed94c6298cd
Gitweb:     http://git.kernel.org/tip/167aedc44e1743777e6aee71b0fe7ed94c6298cd
Author:     Namhyung Kim <namhyung.kim@lge.com>
AuthorDate: Wed, 26 Jun 2013 16:14:04 +0900
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Fri, 12 Jul 2013 13:46:00 -0300

perf util: Move debugfs/tracing helper functions to util.c

Since they're generic helpers move them to util.c so that they can be
used by others.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Link: http://lkml.kernel.org/r/1372230862-15861-2-git-send-email-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/trace-event-info.c | 59 --------------------------------------
 tools/perf/util/util.c             | 59 ++++++++++++++++++++++++++++++++++++++
 tools/perf/util/util.h             |  3 ++
 3 files changed, 62 insertions(+), 59 deletions(-)

diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index 3917eb9..615c062 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -46,65 +46,6 @@
 static int output_fd;
 
 
-static const char *find_debugfs(void)
-{
-	const char *path = perf_debugfs_mount(NULL);
-
-	if (!path)
-		pr_debug("Your kernel does not support the debugfs filesystem");
-
-	return path;
-}
-
-/*
- * Finds the path to the debugfs/tracing
- * Allocates the string and stores it.
- */
-static const char *find_tracing_dir(void)
-{
-	static char *tracing;
-	static int tracing_found;
-	const char *debugfs;
-
-	if (tracing_found)
-		return tracing;
-
-	debugfs = find_debugfs();
-	if (!debugfs)
-		return NULL;
-
-	tracing = malloc(strlen(debugfs) + 9);
-	if (!tracing)
-		return NULL;
-
-	sprintf(tracing, "%s/tracing", debugfs);
-
-	tracing_found = 1;
-	return tracing;
-}
-
-static char *get_tracing_file(const char *name)
-{
-	const char *tracing;
-	char *file;
-
-	tracing = find_tracing_dir();
-	if (!tracing)
-		return NULL;
-
-	file = malloc(strlen(tracing) + strlen(name) + 2);
-	if (!file)
-		return NULL;
-
-	sprintf(file, "%s/%s", tracing, name);
-	return file;
-}
-
-static void put_tracing_file(char *file)
-{
-	free(file);
-}
-
 int bigendian(void)
 {
 	unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0};
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 59d868a..9a06584 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -269,3 +269,62 @@ void perf_debugfs_set_path(const char *mntpt)
 	snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt);
 	set_tracing_events_path(mntpt);
 }
+
+static const char *find_debugfs(void)
+{
+	const char *path = perf_debugfs_mount(NULL);
+
+	if (!path)
+		fprintf(stderr, "Your kernel does not support the debugfs filesystem");
+
+	return path;
+}
+
+/*
+ * Finds the path to the debugfs/tracing
+ * Allocates the string and stores it.
+ */
+const char *find_tracing_dir(void)
+{
+	static char *tracing;
+	static int tracing_found;
+	const char *debugfs;
+
+	if (tracing_found)
+		return tracing;
+
+	debugfs = find_debugfs();
+	if (!debugfs)
+		return NULL;
+
+	tracing = malloc(strlen(debugfs) + 9);
+	if (!tracing)
+		return NULL;
+
+	sprintf(tracing, "%s/tracing", debugfs);
+
+	tracing_found = 1;
+	return tracing;
+}
+
+char *get_tracing_file(const char *name)
+{
+	const char *tracing;
+	char *file;
+
+	tracing = find_tracing_dir();
+	if (!tracing)
+		return NULL;
+
+	file = malloc(strlen(tracing) + strlen(name) + 2);
+	if (!file)
+		return NULL;
+
+	sprintf(file, "%s/%s", tracing, name);
+	return file;
+}
+
+void put_tracing_file(char *file)
+{
+	free(file);
+}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 2732fad..cc1574e 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -80,6 +80,9 @@ extern char buildid_dir[];
 extern char tracing_events_path[];
 extern void perf_debugfs_set_path(const char *mountpoint);
 const char *perf_debugfs_mount(const char *mountpoint);
+const char *find_tracing_dir(void);
+char *get_tracing_file(const char *name);
+void put_tracing_file(char *file);
 
 /* On most systems <limits.h> would have given us this, but
  * not on some systems (e.g. GNU/Hurd).

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

* [tip:perf/core] perf util: Use evsel-> name to get tracepoint_paths
  2013-06-26  7:14 ` [PATCH 02/19] perf util: Use evsel->name to get tracepoint_paths Namhyung Kim
@ 2013-07-19  7:44   ` tip-bot for Namhyung Kim
  0 siblings, 0 replies; 43+ messages in thread
From: tip-bot for Namhyung Kim @ 2013-07-19  7:44 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, eranian, paulus, hpa, mingo, a.p.zijlstra,
	namhyung.kim, namhyung, jolsa, fweisbec, rostedt, dsahern, tglx

Commit-ID:  e7c93f09b83be25281cf129674e0035664715033
Gitweb:     http://git.kernel.org/tip/e7c93f09b83be25281cf129674e0035664715033
Author:     Namhyung Kim <namhyung.kim@lge.com>
AuthorDate: Wed, 26 Jun 2013 16:14:05 +0900
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Fri, 12 Jul 2013 13:46:02 -0300

perf util: Use evsel->name to get tracepoint_paths

Most tracepoint events already have their system and event name in
->name field so that searching whole event tracing directory for each
evsel to match given id is suboptimal.

Factor out this routine into tracepoint_name_to_path().  In case of en
invalid name, it'll try to find path using id again.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Link: http://lkml.kernel.org/r/1372230862-15861-3-git-send-email-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/parse-events.c     | 23 +++++++++++++++++++++++
 tools/perf/util/parse-events.h     |  1 +
 tools/perf/util/trace-event-info.c | 15 +++++++++++++++
 3 files changed, 39 insertions(+)

diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 995fc25..ef72e98 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -217,6 +217,29 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
 	return NULL;
 }
 
+struct tracepoint_path *tracepoint_name_to_path(const char *name)
+{
+	struct tracepoint_path *path = zalloc(sizeof(*path));
+	char *str = strchr(name, ':');
+
+	if (path == NULL || str == NULL) {
+		free(path);
+		return NULL;
+	}
+
+	path->system = strndup(name, str - name);
+	path->name = strdup(str+1);
+
+	if (path->system == NULL || path->name == NULL) {
+		free(path->system);
+		free(path->name);
+		free(path);
+		path = NULL;
+	}
+
+	return path;
+}
+
 const char *event_type(int type)
 {
 	switch (type) {
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 8a48593..080f7cf 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -23,6 +23,7 @@ struct tracepoint_path {
 };
 
 extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
+extern struct tracepoint_path *tracepoint_name_to_path(const char *name);
 extern bool have_tracepoints(struct list_head *evlist);
 
 const char *event_type(int type);
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index 615c062..a42624a 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -414,12 +414,27 @@ get_tracepoints_path(struct list_head *pattrs)
 		if (pos->attr.type != PERF_TYPE_TRACEPOINT)
 			continue;
 		++nr_tracepoints;
+
+		if (pos->name) {
+			ppath->next = tracepoint_name_to_path(pos->name);
+			if (ppath->next)
+				goto next;
+
+			if (strchr(pos->name, ':') == NULL)
+				goto try_id;
+
+			goto error;
+		}
+
+try_id:
 		ppath->next = tracepoint_id_to_path(pos->attr.config);
 		if (!ppath->next) {
+error:
 			pr_debug("No memory to alloc tracepoints list\n");
 			put_tracepoints_path(&path);
 			return NULL;
 		}
+next:
 		ppath = ppath->next;
 	}
 

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

end of thread, other threads:[~2013-07-19  7:44 UTC | newest]

Thread overview: 43+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-06-26  7:14 [PATCHSET 00/19] perf tools: Introduce new 'ftrace' command (v3) Namhyung Kim
2013-06-26  7:14 ` [PATCH 01/19] perf util: Move debugfs/tracing helper functions to util.c Namhyung Kim
2013-07-19  7:43   ` [tip:perf/core] perf util: Move debugfs/ tracing " tip-bot for Namhyung Kim
2013-06-26  7:14 ` [PATCH 02/19] perf util: Use evsel->name to get tracepoint_paths Namhyung Kim
2013-07-19  7:44   ` [tip:perf/core] perf util: Use evsel-> name " tip-bot for Namhyung Kim
2013-06-26  7:14 ` [PATCH 03/19] perf util: Save pid-cmdline mapping into tracing header Namhyung Kim
2013-06-26  7:14 ` [PATCH 04/19] perf util: Add more debug message on failure path Namhyung Kim
2013-06-26  7:14 ` [PATCH 05/19] perf tools: Introduce new 'ftrace' tool Namhyung Kim
2013-06-26 17:10   ` David Ahern
2013-06-27  5:04     ` Namhyung Kim
2013-06-27 13:51       ` David Ahern
2013-06-27 14:22         ` Namhyung Kim
2013-06-26  7:14 ` [PATCH 06/19] perf ftrace: Add support for --pid option Namhyung Kim
2013-06-26 17:12   ` David Ahern
2013-06-27  5:23     ` Namhyung Kim
2013-06-27 13:56       ` David Ahern
2013-06-27 14:12         ` Namhyung Kim
2013-07-10 14:18   ` Jiri Olsa
2013-07-11  7:56     ` Namhyung Kim
2013-07-18  6:38       ` Namhyung Kim
2013-06-26  7:14 ` [PATCH 07/19] perf ftrace: Add support for -a and -C option Namhyung Kim
2013-06-26  7:14 ` [PATCH 08/19] perf ftrace: Split "live" sub-command Namhyung Kim
2013-06-26  7:14 ` [PATCH 09/19] perf ftrace: Add 'record' sub-command Namhyung Kim
2013-07-10 14:28   ` Jiri Olsa
2013-07-11  8:00     ` Namhyung Kim
2013-06-26  7:14 ` [PATCH 10/19] perf ftrace: Add 'show' sub-command Namhyung Kim
2013-07-10 14:41   ` Jiri Olsa
2013-07-11  8:01     ` Namhyung Kim
2013-06-26  7:14 ` [PATCH 11/19] perf ftrace: Add 'report' sub-command Namhyung Kim
2013-07-10 14:45   ` Jiri Olsa
2013-07-11  8:10     ` Namhyung Kim
2013-06-26  7:14 ` [PATCH 12/19] perf evlist: Enhance perf_evlist__start_workload() Namhyung Kim
2013-07-12  8:50   ` [tip:perf/urgent] " tip-bot for Namhyung Kim
2013-06-26  7:14 ` [PATCH 13/19] perf ftrace: Use pager for displaying result Namhyung Kim
2013-06-26  7:14 ` [PATCH 14/19] perf ftrace: Cleanup using ftrace_setup/teardown() Namhyung Kim
2013-06-26  7:14 ` [PATCH 15/19] perf tools: Add document for perf-ftrace command Namhyung Kim
2013-07-10 14:22   ` Jiri Olsa
2013-07-11  8:18     ` Namhyung Kim
2013-07-11 11:43       ` Jiri Olsa
2013-06-26  7:14 ` [PATCH 16/19] perf ftrace: Add a signal handler for SIGSEGV Namhyung Kim
2013-06-26  7:14 ` [PATCH 17/19] perf ftrace: Add --clock option Namhyung Kim
2013-06-26  7:14 ` [PATCH 18/19] perf ftrace: Show leaf-functions as oneliner Namhyung Kim
2013-06-26  7:14 ` [PATCH 19/19] perf ftrace: Tidy up the function graph output of 'show' subcommand Namhyung Kim

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.