All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH -perf/perf/core 0/6] Perf probe update (support inline call-site/--funcs/--filter)
@ 2011-01-13 12:45 Masami Hiramatsu
  2011-01-13 12:45 ` [PATCH -perf/perf/core 1/6] perf probe: Introduce lines walker interface Masami Hiramatsu
                   ` (5 more replies)
  0 siblings, 6 replies; 24+ messages in thread
From: Masami Hiramatsu @ 2011-01-13 12:45 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Ingo Molnar
  Cc: Steven Rostedt, Srikar Dronamraju, Franck Bui-Huu, linux-kernel,
	2nddept-manager

Hi,

This series enhances line-finder to find inline-function
call site, and adds two features; showing available
functions (Originally came from Srikar's uprobe series)
and function/variable filtering support.

Thank you,

---

Masami Hiramatsu (6):
      perf probe: Add filters support for available functions
      perf probe: Add variable filter support
      perf: Add strfilter for general purpose string filter
      perf probe: Add --funcs to show available functions in symtab
      perf probe: Enable to put probe inline function call site
      perf probe: Introduce lines walker interface


 tools/perf/Documentation/perf-probe.txt |   15 +
 tools/perf/Makefile                     |    2 
 tools/perf/builtin-probe.c              |   70 ++++++
 tools/perf/util/probe-event.c           |  137 +++++++++---
 tools/perf/util/probe-event.h           |    4 
 tools/perf/util/probe-finder.c          |  361 ++++++++++++++++++-------------
 tools/perf/util/strfilter.c             |  185 ++++++++++++++++
 tools/perf/util/strfilter.h             |   36 +++
 8 files changed, 626 insertions(+), 184 deletions(-)
 create mode 100644 tools/perf/util/strfilter.c
 create mode 100644 tools/perf/util/strfilter.h

-- 
Masami HIRAMATSU
2nd Dept. Linux Technology Center
Hitachi, Ltd., Systems Development Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com


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

* [PATCH -perf/perf/core 1/6] perf probe: Introduce lines walker interface
  2011-01-13 12:45 [PATCH -perf/perf/core 0/6] Perf probe update (support inline call-site/--funcs/--filter) Masami Hiramatsu
@ 2011-01-13 12:45 ` Masami Hiramatsu
  2011-01-26  7:22   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
  2011-01-13 12:46 ` [PATCH -perf/perf/core 2/6] perf probe: Enable to put probe inline function call site Masami Hiramatsu
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 24+ messages in thread
From: Masami Hiramatsu @ 2011-01-13 12:45 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Ingo Molnar
  Cc: Steven Rostedt, Srikar Dronamraju, Franck Bui-Huu, linux-kernel,
	2nddept-manager, Masami Hiramatsu, Peter Zijlstra,
	Paul Mackerras, Ingo Molnar, Arnaldo Carvalho de Melo,
	linux-kernel

Introduce die_walk_lines() for walking on the line list
of given die, and use it in line_range finder and probe
point finder.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Cc: linux-kernel@vger.kernel.org
---

 tools/perf/util/probe-finder.c |  321 +++++++++++++++++++++-------------------
 1 files changed, 167 insertions(+), 154 deletions(-)

diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index ab83b6a..5926d25 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -458,6 +458,124 @@ static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
 	return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
 }
 
+/* Walker on lines (Note: line number will not be sorted) */
+typedef int (* line_walk_handler_t) (const char *fname, int lineno,
+				     Dwarf_Addr addr, void *data);
+
+struct __line_walk_param {
+	line_walk_handler_t handler;
+	void *data;
+	int retval;
+};
+
+/* Walk on decl lines in given DIE */
+static int __die_walk_funclines(Dwarf_Die *sp_die,
+				line_walk_handler_t handler, void *data)
+{
+	const char *fname;
+	Dwarf_Addr addr;
+	int lineno, ret = 0;
+
+	/* Handle function declaration line */
+	fname = dwarf_decl_file(sp_die);
+	if (fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
+	    dwarf_entrypc(sp_die, &addr) == 0) {
+		ret = handler(fname, lineno, addr, data);
+	}
+
+	return ret;
+}
+
+static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)
+{
+	struct __line_walk_param *lw = data;
+
+	lw->retval = __die_walk_funclines(sp_die, lw->handler, lw->data);
+	if (lw->retval != 0)
+		return DWARF_CB_ABORT;
+
+	return DWARF_CB_OK;
+}
+
+/*
+ * Walk on lines inside given PDIE. If the PDIE is subprogram, walk only on
+ * the lines inside the subprogram, otherwise PDIE must be a CU DIE.
+ */
+static int die_walk_lines(Dwarf_Die *pdie, line_walk_handler_t handler,
+			  void *data)
+{
+	Dwarf_Lines *lines;
+	Dwarf_Line *line;
+	Dwarf_Addr addr;
+	const char *fname;
+	int lineno, ret = 0;
+	Dwarf_Die die_mem, *cu_die;
+	size_t nlines, i;
+
+	/* Get the CU die */
+	if (dwarf_tag(pdie) == DW_TAG_subprogram)
+		cu_die = dwarf_diecu(pdie, &die_mem, NULL, NULL);
+	else
+		cu_die = pdie;
+	if (!cu_die) {
+		pr_debug2("Failed to get CU from subprogram\n");
+		return -EINVAL;
+	}
+
+	/* Get lines list in the CU */
+	if (dwarf_getsrclines(cu_die, &lines, &nlines) != 0) {
+		pr_debug2("Failed to get source lines on this CU.\n");
+		return -ENOENT;
+	}
+	pr_debug2("Get %ld lines from this CU\n", nlines);
+
+	/* Walk on the lines on lines list */
+	for (i = 0; i < nlines; i++) {
+		line = dwarf_onesrcline(lines, i);
+		if (line == NULL ||
+		    dwarf_lineno(line, &lineno) != 0 ||
+		    dwarf_lineaddr(line, &addr) != 0) {
+			pr_debug2("Failed to get line info. "
+				  "Possible error in debuginfo.\n");
+			continue;
+		}
+		/* Filter lines based on address */
+		if (pdie != cu_die)
+			/*
+			 * Address filtering
+			 * The line is included in given function, and
+			 * no inline block includes it.
+			 */
+			if (!dwarf_haspc(pdie, addr) ||
+			    die_find_inlinefunc(pdie, addr, &die_mem))
+				continue;
+		/* Get source line */
+		fname = dwarf_linesrc(line, NULL, NULL);
+
+		ret = handler(fname, lineno, addr, data);
+		if (ret != 0)
+			return ret;
+	}
+
+	/*
+	 * Dwarf lines doesn't include function declarations and inlined
+	 * subroutines. We have to check functions list or given function.
+	 */
+	if (pdie != cu_die)
+		ret = __die_walk_funclines(pdie, handler, data);
+	else {
+		struct __line_walk_param param = {
+			.handler = handler,
+			.data = data,
+			.retval = 0,
+		};
+		dwarf_getfuncs(cu_die, __die_walk_culines_cb, &param, 0);
+		ret = param.retval;
+	}
+
+	return ret;
+}
+
 struct __find_variable_param {
 	const char *name;
 	Dwarf_Addr addr;
@@ -1050,43 +1168,26 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
 	return ret;
 }
 
-/* Find probe point from its line number */
-static int find_probe_point_by_line(struct probe_finder *pf)
+static int probe_point_line_walker(const char *fname, int lineno,
+				   Dwarf_Addr addr, void *data)
 {
-	Dwarf_Lines *lines;
-	Dwarf_Line *line;
-	size_t nlines, i;
-	Dwarf_Addr addr;
-	int lineno;
-	int ret = 0;
+	struct probe_finder *pf = data;
+	int ret;
 
-	if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
-		pr_warning("No source lines found.\n");
-		return -ENOENT;
-	}
+	if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0)
+		return 0;
 
-	for (i = 0; i < nlines && ret == 0; i++) {
-		line = dwarf_onesrcline(lines, i);
-		if (dwarf_lineno(line, &lineno) != 0 ||
-		    lineno != pf->lno)
-			continue;
+	pf->addr = addr;
+	ret = call_probe_finder(NULL, pf);
 
-		/* TODO: Get fileno from line, but how? */
-		if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
-			continue;
-
-		if (dwarf_lineaddr(line, &addr) != 0) {
-			pr_warning("Failed to get the address of the line.\n");
-			return -ENOENT;
-		}
-		pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n",
-			 (int)i, lineno, (uintmax_t)addr);
-		pf->addr = addr;
+	/* Continue if no error, because the line will be in inline function */
+	return ret < 0 ?: 0;
+}
 
-		ret = call_probe_finder(NULL, pf);
-		/* Continuing, because target line might be inlined. */
-	}
-	return ret;
+/* Find probe point from its line number */
+static int find_probe_point_by_line(struct probe_finder *pf)
+{
+	return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf);
 }
 
 /* Find lines which match lazy pattern */
@@ -1140,15 +1241,31 @@ out_close:
 	return nlines;
 }
 
+static int probe_point_lazy_walker(const char *fname, int lineno,
+				   Dwarf_Addr addr, void *data)
+{
+	struct probe_finder *pf = data;
+	int ret;
+
+	if (!line_list__has_line(&pf->lcache, lineno) ||
+	    strtailcmp(fname, pf->fname) != 0)
+		return 0;
+
+	pr_debug("Probe line found: line:%d addr:0x%llx\n",
+		 lineno, (unsigned long long)addr);
+	pf->addr = addr;
+	ret = call_probe_finder(NULL, pf);
+
+	/*
+	 * Continue if no error, because the lazy pattern will match
+	 * to other lines
+	 */
+	return ret < 0 ?: 0;
+}
+
 /* Find probe points from lazy pattern  */
 static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
 {
-	Dwarf_Lines *lines;
-	Dwarf_Line *line;
-	size_t nlines, i;
-	Dwarf_Addr addr;
-	Dwarf_Die die_mem;
-	int lineno;
 	int ret = 0;
 
 	if (list_empty(&pf->lcache)) {
@@ -1162,45 +1279,7 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
 			return ret;
 	}
 
-	if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
-		pr_warning("No source lines found.\n");
-		return -ENOENT;
-	}
-
-	for (i = 0; i < nlines && ret >= 0; i++) {
-		line = dwarf_onesrcline(lines, i);
-
-		if (dwarf_lineno(line, &lineno) != 0 ||
-		    !line_list__has_line(&pf->lcache, lineno))
-			continue;
-
-		/* TODO: Get fileno from line, but how? */
-		if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
-			continue;
-
-		if (dwarf_lineaddr(line, &addr) != 0) {
-			pr_debug("Failed to get the address of line %d.\n",
-				 lineno);
-			continue;
-		}
-		if (sp_die) {
-			/* Address filtering 1: does sp_die include addr? */
-			if (!dwarf_haspc(sp_die, addr))
-				continue;
-			/* Address filtering 2: No child include addr? */
-			if (die_find_inlinefunc(sp_die, addr, &die_mem))
-				continue;
-		}
-
-		pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n",
-			 (int)i, lineno, (unsigned long long)addr);
-		pf->addr = addr;
-
-		ret = call_probe_finder(sp_die, pf);
-		/* Continuing, because target line might be inlined. */
-	}
-	/* TODO: deallocate lines, but how? */
-	return ret;
+	return die_walk_lines(sp_die, probe_point_lazy_walker, pf);
 }
 
 /* Callback parameter with return value */
@@ -1644,91 +1723,28 @@ static int line_range_add_line(const char *src, unsigned int lineno,
 	return line_list__add_line(&lr->line_list, lineno);
 }
 
-/* Search function declaration lines */
-static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data)
+static int line_range_walk_cb(const char *fname, int lineno,
+			      Dwarf_Addr addr __used,
+			      void *data)
 {
-	struct dwarf_callback_param *param = data;
-	struct line_finder *lf = param->data;
-	const char *src;
-	int lineno;
-
-	src = dwarf_decl_file(sp_die);
-	if (src && strtailcmp(src, lf->fname) != 0)
-		return DWARF_CB_OK;
+	struct line_finder *lf = data;
 
-	if (dwarf_decl_line(sp_die, &lineno) != 0 ||
+	if ((strtailcmp(fname, lf->fname) != 0) ||
 	    (lf->lno_s > lineno || lf->lno_e < lineno))
-		return DWARF_CB_OK;
+		return 0;
 
-	param->retval = line_range_add_line(src, lineno, lf->lr);
-	if (param->retval < 0)
-		return DWARF_CB_ABORT;
-	return DWARF_CB_OK;
-}
+	if (line_range_add_line(fname, lineno, lf->lr) < 0)
+		return -EINVAL;
 
-static int find_line_range_func_decl_lines(struct line_finder *lf)
-{
-	struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0};
-	dwarf_getfuncs(&lf->cu_die, line_range_funcdecl_cb, &param, 0);
-	return param.retval;
+	return 0;
 }
 
 /* Find line range from its line number */
 static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
 {
-	Dwarf_Lines *lines;
-	Dwarf_Line *line;
-	size_t nlines, i;
-	Dwarf_Addr addr;
-	int lineno, ret = 0;
-	const char *src;
-	Dwarf_Die die_mem;
-
-	line_list__init(&lf->lr->line_list);
-	if (dwarf_getsrclines(&lf->cu_die, &lines, &nlines) != 0) {
-		pr_warning("No source lines found.\n");
-		return -ENOENT;
-	}
-
-	/* Search probable lines on lines list */
-	for (i = 0; i < nlines; i++) {
-		line = dwarf_onesrcline(lines, i);
-		if (dwarf_lineno(line, &lineno) != 0 ||
-		    (lf->lno_s > lineno || lf->lno_e < lineno))
-			continue;
-
-		if (sp_die) {
-			/* Address filtering 1: does sp_die include addr? */
-			if (dwarf_lineaddr(line, &addr) != 0 ||
-			    !dwarf_haspc(sp_die, addr))
-				continue;
-
-			/* Address filtering 2: No child include addr? */
-			if (die_find_inlinefunc(sp_die, addr, &die_mem))
-				continue;
-		}
-
-		/* TODO: Get fileno from line, but how? */
-		src = dwarf_linesrc(line, NULL, NULL);
-		if (strtailcmp(src, lf->fname) != 0)
-			continue;
-
-		ret = line_range_add_line(src, lineno, lf->lr);
-		if (ret < 0)
-			return ret;
-	}
+	int ret;
 
-	/*
-	 * Dwarf lines doesn't include function declarations. We have to
-	 * check functions list or given function.
-	 */
-	if (sp_die) {
-		src = dwarf_decl_file(sp_die);
-		if (src && dwarf_decl_line(sp_die, &lineno) == 0 &&
-		    (lf->lno_s <= lineno && lf->lno_e >= lineno))
-			ret = line_range_add_line(src, lineno, lf->lr);
-	} else
-		ret = find_line_range_func_decl_lines(lf);
+	ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf);
 
 	/* Update status */
 	if (ret >= 0)
@@ -1758,9 +1774,6 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
 	struct line_finder *lf = param->data;
 	struct line_range *lr = lf->lr;
 
-	pr_debug("find (%llx) %s\n",
-		 (unsigned long long)dwarf_dieoffset(sp_die),
-		 dwarf_diename(sp_die));
 	if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
 	    die_compare_name(sp_die, lr->function)) {
 		lf->fname = dwarf_decl_file(sp_die);


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

* [PATCH -perf/perf/core 2/6] perf probe: Enable to put probe inline function call site
  2011-01-13 12:45 [PATCH -perf/perf/core 0/6] Perf probe update (support inline call-site/--funcs/--filter) Masami Hiramatsu
  2011-01-13 12:45 ` [PATCH -perf/perf/core 1/6] perf probe: Introduce lines walker interface Masami Hiramatsu
@ 2011-01-13 12:46 ` Masami Hiramatsu
  2011-01-26  7:22   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
  2011-01-13 12:46 ` [PATCH -perf/perf/core 3/6] perf probe: Add --funcs to show available functions in symtab Masami Hiramatsu
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 24+ messages in thread
From: Masami Hiramatsu @ 2011-01-13 12:46 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Ingo Molnar
  Cc: Steven Rostedt, Srikar Dronamraju, Franck Bui-Huu, linux-kernel,
	2nddept-manager, Masami Hiramatsu, Peter Zijlstra,
	Paul Mackerras, Ingo Molnar, Arnaldo Carvalho de Melo,
	linux-kernel

Enable to put probe inline function call site. This will
increase line-based probe-ability.

<Without this patch>
$ ./perf probe -L schedule:48
<schedule:48>
                pre_schedule(rq, prev);

     50         if (unlikely(!rq->nr_running))
                        idle_balance(cpu, rq);

                put_prev_task(rq, prev);
                next = pick_next_task(rq);

     56         if (likely(prev != next)) {
                        sched_info_switch(prev, next);
                        trace_sched_switch_out(prev, next);
                        perf_event_task_sched_out(prev, next);


<With this patch>
$ ./perf probe -L schedule:48
<schedule:48>
     48         pre_schedule(rq, prev);

     50         if (unlikely(!rq->nr_running))
     51                 idle_balance(cpu, rq);

     53         put_prev_task(rq, prev);
     54         next = pick_next_task(rq);

     56         if (likely(prev != next)) {
     57                 sched_info_switch(prev, next);
     58                 trace_sched_switch_out(prev, next);
     59                 perf_event_task_sched_out(prev, next);

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Cc: linux-kernel@vger.kernel.org
---

 tools/perf/util/probe-finder.c |   56 ++++++++++++++++++++++++++++++++++------
 1 files changed, 48 insertions(+), 8 deletions(-)

diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 5926d25..10c18c4 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -280,6 +280,19 @@ static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
 	return name ? (strcmp(tname, name) == 0) : false;
 }
 
+/* Get callsite line number of inline-function instance */
+static int die_get_call_lineno(Dwarf_Die *in_die)
+{
+	Dwarf_Attribute attr;
+	Dwarf_Word ret;
+
+	if (!dwarf_attr(in_die, DW_AT_call_line, &attr))
+		return -ENOENT;
+
+	dwarf_formudata(&attr, &ret);
+	return (int)ret;
+}
+
 /* Get type die */
 static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
 {
@@ -463,27 +476,54 @@ typedef int (* line_walk_handler_t) (const char *fname, int lineno,
 				     Dwarf_Addr addr, void *data);
 
 struct __line_walk_param {
+	const char *fname;
 	line_walk_handler_t handler;
 	void *data;
 	int retval;
 };
 
-/* Walk on decl lines in given DIE */
+static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data)
+{
+	struct __line_walk_param *lw = data;
+	Dwarf_Addr addr;
+	int lineno;
+
+	if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) {
+		lineno = die_get_call_lineno(in_die);
+		if (lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) {
+			lw->retval = lw->handler(lw->fname, lineno, addr,
+						 lw->data);
+			if (lw->retval != 0)
+				return DIE_FIND_CB_FOUND;
+		}
+	}
+	return DIE_FIND_CB_SIBLING;
+}
+
+/* Walk on lines of blocks included in given DIE */
 static int __die_walk_funclines(Dwarf_Die *sp_die,
 				line_walk_handler_t handler, void *data)
 {
-	const char *fname;
+	struct __line_walk_param lw = {
+		.handler = handler,
+		.data = data,
+		.retval = 0,
+	};
+	Dwarf_Die die_mem;
 	Dwarf_Addr addr;
-	int lineno, ret = 0;
+	int lineno;
 
 	/* Handle function declaration line */
-	fname = dwarf_decl_file(sp_die);
-	if (fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
+	lw.fname = dwarf_decl_file(sp_die);
+	if (lw.fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
 	    dwarf_entrypc(sp_die, &addr) == 0) {
-		ret = handler(fname, lineno, addr, data);
+		lw.retval = handler(lw.fname, lineno, addr, data);
+		if (lw.retval != 0)
+			goto done;
 	}
-
-	return ret;
+	die_find_child(sp_die, __die_walk_funclines_cb, &lw, &die_mem);
+done:
+	return lw.retval;
 }
 
 static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)


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

* [PATCH -perf/perf/core 3/6] perf probe: Add --funcs to show available functions in symtab
  2011-01-13 12:45 [PATCH -perf/perf/core 0/6] Perf probe update (support inline call-site/--funcs/--filter) Masami Hiramatsu
  2011-01-13 12:45 ` [PATCH -perf/perf/core 1/6] perf probe: Introduce lines walker interface Masami Hiramatsu
  2011-01-13 12:46 ` [PATCH -perf/perf/core 2/6] perf probe: Enable to put probe inline function call site Masami Hiramatsu
@ 2011-01-13 12:46 ` Masami Hiramatsu
  2011-01-13 21:24   ` Franck Bui-Huu
  2011-01-26  7:23   ` [tip:perf/core] perf probe: Add --funcs to show available functions in symtab tip-bot for Masami Hiramatsu
  2011-01-13 12:46 ` [PATCH -perf/perf/core 4/6] perf: Add strfilter for general purpose string filter Masami Hiramatsu
                   ` (2 subsequent siblings)
  5 siblings, 2 replies; 24+ messages in thread
From: Masami Hiramatsu @ 2011-01-13 12:46 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Ingo Molnar
  Cc: Steven Rostedt, Srikar Dronamraju, Franck Bui-Huu, linux-kernel,
	2nddept-manager, Masami Hiramatsu, Srikar Dronamraju,
	Peter Zijlstra, Paul Mackerras, Ingo Molnar,
	Arnaldo Carvalho de Melo, linux-kernel

Add --funcs to show available functions in symtab.
Originally this feature came from Srikar's uprobes patches
( http://lkml.org/lkml/2010/8/27/244 )

e.g.
# ./perf probe --funcs
...
__ablkcipher_walk_complete
__absent_pages_in_range
__account_scheduler_latency
__add_pages
__alloc_pages_nodemask
__alloc_percpu
__alloc_reserved_percpu
__alloc_skb
__alloc_workqueue_key
__any_online_cpu
__ata_ehi_push_desc
...

This also supports symbols in module, e.g.

# ./perf probe -m kvm --funcs
...
cleanup_module
cpuid_maxphyaddr
emulate_clts
emulate_instruction
emulate_int_real
emulate_invlpg
emulator_get_dr
emulator_set_dr
emulator_task_switch
emulator_write_emulated
emulator_write_phys
fx_init
...

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Original-patch-from: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Cc: linux-kernel@vger.kernel.org
---

 tools/perf/builtin-probe.c    |   29 +++++++++++++++++-
 tools/perf/util/probe-event.c |   67 ++++++++++++++++++++++++++++++++++++++++-
 tools/perf/util/probe-event.h |    1 +
 3 files changed, 94 insertions(+), 3 deletions(-)

diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index add163c..6cf708a 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -52,6 +52,7 @@ static struct {
 	bool show_lines;
 	bool show_vars;
 	bool show_ext_vars;
+	bool show_funcs;
 	bool mod_events;
 	int nevents;
 	struct perf_probe_event events[MAX_PROBES];
@@ -221,6 +222,8 @@ static const struct option options[] = {
 	OPT__DRY_RUN(&probe_event_dry_run),
 	OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
 		 "Set how many probe points can be found for a probe."),
+	OPT_BOOLEAN('F', "funcs", &params.show_funcs,
+		    "Show potential probe-able functions."),
 	OPT_END()
 };
 
@@ -246,7 +249,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 		params.max_probe_points = MAX_PROBES;
 
 	if ((!params.nevents && !params.dellist && !params.list_events &&
-	     !params.show_lines))
+	     !params.show_lines && !params.show_funcs))
 		usage_with_options(probe_usage, options);
 
 	/*
@@ -267,12 +270,36 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 			pr_err(" Error: Don't use --list with --vars.\n");
 			usage_with_options(probe_usage, options);
 		}
+		if (params.show_funcs) {
+			pr_err("  Error: Don't use --list with --funcs.\n");
+			usage_with_options(probe_usage, options);
+		}
 		ret = show_perf_probe_events();
 		if (ret < 0)
 			pr_err("  Error: Failed to show event list. (%d)\n",
 			       ret);
 		return ret;
 	}
+	if (params.show_funcs) {
+		if (params.nevents != 0 || params.dellist) {
+			pr_err("  Error: Don't use --funcs with"
+			       " --add/--del.\n");
+			usage_with_options(probe_usage, options);
+		}
+		if (params.show_lines) {
+			pr_err("  Error: Don't use --funcs with --line.\n");
+			usage_with_options(probe_usage, options);
+		}
+		if (params.show_vars) {
+			pr_err("  Error: Don't use --funcs with --vars.\n");
+			usage_with_options(probe_usage, options);
+		}
+		ret = show_available_funcs(params.target_module);
+		if (ret < 0)
+			pr_err("  Error: Failed to show functions."
+			       " (%d)\n", ret);
+		return ret;
+	}
 
 #ifdef DWARF_SUPPORT
 	if (params.show_lines) {
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 128aaab..1a93756 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -111,7 +111,25 @@ static struct symbol *__find_kernel_function_by_name(const char *name,
 						     NULL);
 }
 
-const char *kernel_get_module_path(const char *module)
+static struct map *kernel_get_module_map(const char *module)
+{
+	struct rb_node *nd;
+	struct map_groups *grp = &machine.kmaps;
+
+	if (!module)
+		module = "kernel";
+
+	for (nd = rb_first(&grp->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) {
+		struct map *pos = rb_entry(nd, struct map, rb_node);
+		if (strncmp(pos->dso->short_name + 1, module,
+			    pos->dso->short_name_len - 2) == 0) {
+			return pos;
+		}
+	}
+	return NULL;
+}
+
+static struct dso *kernel_get_module_dso(const char *module)
 {
 	struct dso *dso;
 	struct map *map;
@@ -141,7 +159,13 @@ const char *kernel_get_module_path(const char *module)
 		}
 	}
 found:
-	return dso->long_name;
+	return dso;
+}
+
+const char *kernel_get_module_path(const char *module)
+{
+	struct dso *dso = kernel_get_module_dso(module);
+	return (dso) ? dso->long_name : NULL;
 }
 
 #ifdef DWARF_SUPPORT
@@ -1913,3 +1937,42 @@ int del_perf_probe_events(struct strlist *dellist)
 	return ret;
 }
 
+/*
+ * If a symbol corresponds to a function with global binding return 0.
+ * For all others return 1.
+ */
+static int filter_non_global_functions(struct map *map __unused,
+					struct symbol *sym)
+{
+	if (sym->binding != STB_GLOBAL)
+		return 1;
+
+	return 0;
+}
+
+int show_available_funcs(const char *module)
+{
+	struct map *map;
+	int ret;
+
+	setup_pager();
+
+	ret = init_vmlinux();
+	if (ret < 0)
+		return ret;
+
+	map = kernel_get_module_map(module);
+	if (!map) {
+		pr_err("Failed to find %s map.\n", (module) ? : "kernel");
+		return -EINVAL;
+	}
+	if (map__load(map, filter_non_global_functions)) {
+		pr_err("Failed to load map.\n");
+		return -EINVAL;
+	}
+	if (!dso__sorted_by_name(map->dso, map->type))
+		dso__sort_by_name(map->dso, map->type);
+
+	dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
+	return 0;
+}
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 5accbed..1fb4f18 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -127,6 +127,7 @@ extern int show_line_range(struct line_range *lr, const char *module);
 extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
 			       int max_probe_points, const char *module,
 			       bool externs);
+extern int show_available_funcs(const char *module);
 
 
 /* Maximum index number of event-name postfix */


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

* [PATCH -perf/perf/core 4/6] perf: Add strfilter for general purpose string filter
  2011-01-13 12:45 [PATCH -perf/perf/core 0/6] Perf probe update (support inline call-site/--funcs/--filter) Masami Hiramatsu
                   ` (2 preceding siblings ...)
  2011-01-13 12:46 ` [PATCH -perf/perf/core 3/6] perf probe: Add --funcs to show available functions in symtab Masami Hiramatsu
@ 2011-01-13 12:46 ` Masami Hiramatsu
  2011-01-13 13:01   ` Peter Zijlstra
  2011-01-17 12:40   ` Arnaldo Carvalho de Melo
  2011-01-13 12:46 ` [PATCH -perf/perf/core 5/6] perf probe: Add variable filter support Masami Hiramatsu
  2011-01-13 12:46 ` [PATCH -perf/perf/core 6/6] perf probe: Add filters support for available functions Masami Hiramatsu
  5 siblings, 2 replies; 24+ messages in thread
From: Masami Hiramatsu @ 2011-01-13 12:46 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Ingo Molnar
  Cc: Steven Rostedt, Srikar Dronamraju, Franck Bui-Huu, linux-kernel,
	2nddept-manager, Masami Hiramatsu, Peter Zijlstra,
	Paul Mackerras, Ingo Molnar, Arnaldo Carvalho de Melo,
	linux-kernel

Add strfilter for general purpose string filter.
Every filter rules are descrived by glob matching pattern
and '!' prefix which means Logical NOT.
A strfilter consists of those filter rules connected
with '&' and '|'. A set of rules can be folded by using
'(' and ')'. It also accepts spaces around rules and those
operators.

Format:
<rule> ::= <glob-exp> | "!" <rule> | <rule> <op> <rule> | "(" <rule> ")"
<op> ::= "&" | "|"

e.g.
 "(add* | del*) & *timer" filter rules pass strings which
 start with add or del and end with timer.

This will be used by perf probe --filter.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Cc: linux-kernel@vger.kernel.org
---

 tools/perf/Makefile         |    2 
 tools/perf/util/strfilter.c |  185 +++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/strfilter.h |   36 ++++++++
 3 files changed, 223 insertions(+), 0 deletions(-)
 create mode 100644 tools/perf/util/strfilter.c
 create mode 100644 tools/perf/util/strfilter.h

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 2b5387d..50dcfb1 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -411,6 +411,7 @@ LIB_H += util/help.h
 LIB_H += util/session.h
 LIB_H += util/strbuf.h
 LIB_H += util/strlist.h
+LIB_H += util/strfilter.h
 LIB_H += util/svghelper.h
 LIB_H += util/run-command.h
 LIB_H += util/sigchain.h
@@ -450,6 +451,7 @@ LIB_OBJS += $(OUTPUT)util/quote.o
 LIB_OBJS += $(OUTPUT)util/strbuf.o
 LIB_OBJS += $(OUTPUT)util/string.o
 LIB_OBJS += $(OUTPUT)util/strlist.o
+LIB_OBJS += $(OUTPUT)util/strfilter.o
 LIB_OBJS += $(OUTPUT)util/usage.o
 LIB_OBJS += $(OUTPUT)util/wrapper.o
 LIB_OBJS += $(OUTPUT)util/sigchain.o
diff --git a/tools/perf/util/strfilter.c b/tools/perf/util/strfilter.c
new file mode 100644
index 0000000..877146b
--- /dev/null
+++ b/tools/perf/util/strfilter.c
@@ -0,0 +1,185 @@
+#include <ctype.h>
+#include "util.h"
+#include "string.h"
+#include "strfilter.h"
+
+/* Operators */
+static const char *OP_and	= "&";	/* Logical AND */
+static const char *OP_or	= "|";	/* Logical OR */
+static const char *OP_not	= "!";	/* Logical NOT */
+
+#define is_operator(c)	((c) == '|' || (c) == '&' || (c) == '!')
+#define is_separator(c)	(is_operator(c) || (c) == '(' || (c) == ')')
+
+void strfilter__delete(struct strfilter *self)
+{
+	if (self) {
+		if (self->p && !is_operator(*self->p))
+			free((char *)self->p);
+		strfilter__delete(self->l);
+		strfilter__delete(self->r);
+		free(self);
+	}
+}
+
+static const char *get_token(const char *s, const char **e)
+{
+	const char *p;
+
+	while (isspace(*s))	/* Skip spaces */
+		s++;
+
+	if (*s == '\0') {
+		p = s;
+		goto end;
+	}
+
+	p = s + 1;
+	if (!is_separator(*s)) {
+		/* End search */
+retry:
+		while (*p && !is_separator(*p) && !isspace(*p))
+			p++;
+		/* Escape and special case: '!' is also used in glob pattern */
+		if (*(p - 1) == '\\' || (*p == '!' && *(p - 1) == '[')) {
+			p++;
+			goto retry;
+		}
+	}
+end:
+	*e = p;
+	return s;
+}
+
+static struct strfilter *strfilter__alloc(const char *op,
+					  struct strfilter *l,
+					  struct strfilter *r)
+{
+	struct strfilter *ret = zalloc(sizeof(struct strfilter));
+
+	if (ret) {
+		ret->p = op;
+		ret->l = l;
+		ret->r = r;
+	}
+
+	return ret;
+}
+
+static struct strfilter *__strfilter__new(const char *s, const char **ep)
+{
+	struct strfilter root, *cur, *last_op;
+	const char *e;
+
+	memset(&root, 0, sizeof(root));
+	last_op = cur = &root;
+
+	s = get_token(s, &e);
+	while (*s != '\0' && *s != ')') {
+		switch (*s) {
+		case '&':	/* Exchg last OP->r with AND */
+			if (!cur->r || !last_op->r)
+				goto error;
+			cur = strfilter__alloc(OP_and, last_op->r, NULL);
+			last_op->r = cur;
+			last_op = cur;
+			break;
+		case '|':	/* Exchg the root with OR */
+			if (!cur->r || !root.r)
+				goto error;
+			cur = strfilter__alloc(OP_or, root.r, NULL);
+			root.r = cur;
+			last_op = cur;
+			break;
+		case '!':	/* Add NOT as a leaf node */
+			if (cur->r)
+				goto error;
+			cur->r = strfilter__alloc(OP_not, NULL, NULL);
+			cur = cur->r;
+			break;
+		case '(':	/* Recursively parses inside the parenthesis */
+			if (cur->r)
+				goto error;
+			cur->r = __strfilter__new(s + 1, &s);
+			if (!s)
+				goto nomem;
+			if (!cur->r || *s != ')')
+				goto error;
+			e = s + 1;
+			break;
+		default:
+			if (cur->r)
+				goto error;
+			cur->r = strfilter__alloc(strndup(s, e - s),
+						  NULL, NULL);
+			if (!cur->r || !cur->r->p)
+				goto nomem;
+		}
+		if (!cur)
+			goto nomem;
+		s = get_token(e, &e);
+	}
+	if (!cur->r)
+		goto error;
+	*ep = s;
+	return root.r;
+nomem:
+	s = NULL;
+error:
+	*ep = s;
+	strfilter__delete(root.r);
+	return NULL;
+}
+
+/*
+ * Parse filter rule and return new strfilter.
+ * Return NULL if fail, and *ep == NULL if memory allocation failed.
+ */
+struct strfilter *strfilter__new(const char *rules, const char **err)
+{
+	struct strfilter *ret;
+	const char *ep;
+
+	ret = __strfilter__new(rules, &ep);
+	if (!ret || *ep != '\0') {
+		if (err)
+			*err = ep;
+		strfilter__delete(ret);
+		ret = NULL;
+	}
+
+	return ret;
+}
+
+struct strfilter *strfilter__new_and(struct strfilter *f1,
+				     struct strfilter *f2)
+{
+	return strfilter__alloc(OP_and, f1, f2);
+}
+
+struct strfilter *strfilter__new_or(struct strfilter *f1,
+				    struct strfilter *f2)
+{
+	return strfilter__alloc(OP_or, f1, f2);
+}
+
+/* Return true if STR matches the filter */
+bool strfilter__match(struct strfilter *self, const char *str)
+{
+	if (!self || !self->p)
+		return false;
+
+	switch (*self->p) {
+	case '|':	/* OR */
+		return strfilter__match(self->l, str) ||
+			strfilter__match(self->r, str);
+	case '&':	/* AND */
+		return strfilter__match(self->l, str) &&
+			strfilter__match(self->r, str);
+	case '!':	/* NOT */
+		return !strfilter__match(self->r, str);
+	default:
+		return strglobmatch(str, self->p);
+	}
+}
+
diff --git a/tools/perf/util/strfilter.h b/tools/perf/util/strfilter.h
new file mode 100644
index 0000000..52ca0bd
--- /dev/null
+++ b/tools/perf/util/strfilter.h
@@ -0,0 +1,36 @@
+#ifndef __PERF_STRFILTER_H
+#define __PERF_STRFILTER_H
+/* General purpose glob matching filter */
+
+#include <linux/list.h>
+#include <stdbool.h>
+
+/* String filter */
+struct strfilter {
+	struct strfilter *l;	/* Tree left branche (for &,|) */
+	struct strfilter *r;	/* Tree right branche (for !,&,|) */
+	const char *p;		/* Operator or rule */
+};
+
+/*
+ * Parse RULES and return new strfilter. If ERR is not NULL, *ERR will
+*  indicate where the parse error occured.
+ */
+struct strfilter *strfilter__new(const char *rules, const char **err);
+
+/* Make a new filter which F1 & F2 (and it holds F1 and F2) */
+struct strfilter *strfilter__new_and(struct strfilter *f1,
+				     struct strfilter *f2);
+
+/* Make a new filter which F1 | F2 (and it holds F1 and F2) */
+struct strfilter *strfilter__new_or(struct strfilter *f1,
+				    struct strfilter *f2);
+
+/* Match the STR and filter rule. Return true if the str match the rule */
+bool strfilter__match(struct strfilter *self, const char *str);
+
+/* Delete the filter */
+void strfilter__delete(struct strfilter *self);
+
+#endif
+


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

* [PATCH -perf/perf/core  5/6] perf probe: Add variable filter support
  2011-01-13 12:45 [PATCH -perf/perf/core 0/6] Perf probe update (support inline call-site/--funcs/--filter) Masami Hiramatsu
                   ` (3 preceding siblings ...)
  2011-01-13 12:46 ` [PATCH -perf/perf/core 4/6] perf: Add strfilter for general purpose string filter Masami Hiramatsu
@ 2011-01-13 12:46 ` Masami Hiramatsu
  2011-01-13 21:18   ` Franck Bui-Huu
  2011-01-13 12:46 ` [PATCH -perf/perf/core 6/6] perf probe: Add filters support for available functions Masami Hiramatsu
  5 siblings, 1 reply; 24+ messages in thread
From: Masami Hiramatsu @ 2011-01-13 12:46 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Ingo Molnar
  Cc: Steven Rostedt, Srikar Dronamraju, Franck Bui-Huu, linux-kernel,
	2nddept-manager, Masami Hiramatsu, Peter Zijlstra,
	Paul Mackerras, Ingo Molnar, Arnaldo Carvalho de Melo,
	Chase Douglas, linux-kernel

Add filters support for available variable list.
Default filter is "!__k???tab_*&!__crc_*" for
filtering out automatically generated symbols.

The format of filter rule is "[!]GLOBPATTERN", so
you can use wild cards. If the filter rule starts with
'!', matched variables are filter out.

e.g.)
 # perf probe -V schedule --externs --filter=cpu*
Available variables at schedule
        @<schedule+0>
                cpumask_var_t   cpu_callout_mask
                cpumask_var_t   cpu_core_map
                cpumask_var_t   cpu_isolated_map
                cpumask_var_t   cpu_sibling_map
                int     cpu_number
                long unsigned int*      cpu_bit_bitmap
		...

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Cc: Chase Douglas <chase.douglas@canonical.com>
Cc: linux-kernel@vger.kernel.org
---

 tools/perf/Documentation/perf-probe.txt |   14 ++++++
 tools/perf/builtin-probe.c              |   34 ++++++++++++++++
 tools/perf/util/probe-event.c           |   67 +++++++++++++++++++------------
 tools/perf/util/probe-event.h           |    3 +
 4 files changed, 91 insertions(+), 27 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 86b797a..7542e8a 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -73,6 +73,12 @@ OPTIONS
 	(Only for --vars) Show external defined variables in addition to local
 	variables.
 
+--filter=FILTER::
+	(Only for --vars) Set filter for variables. FILTER is a combination of
+	glob pattern, see FILTER PATTERN for detail.
+	Default FILTER is "!__k???tab_* & !__crc_*".
+	If several filters are specified, only the last filter is valid.
+
 -f::
 --force::
 	Forcibly add events with existing name.
@@ -135,6 +141,14 @@ e.g.
 
 This provides some sort of flexibility and robustness to probe point definitions against minor code changes. For example, actual 10th line of schedule() can be moved easily by modifying schedule(), but the same line matching 'rq=cpu_rq*' may still exist in the function.)
 
+FILTER PATTERN
+--------------
+ The filter pattern is glob matching pattern(s) to filter variables.
+ In addition, you can use "!" for specifying filter-out rule. You also can give several rules combined with "&" or "|", and fold those rules as one rule by using "(" ")".
+
+e.g.
+ With --filter "foo* | bar*", perf probe -V shows variables which start with "foo" or "bar".
+ With --filter "!foo* & *bar", perf probe -V shows variables which don't start with "foo" and end with "bar", like "fizzbar". But "foobar" is filtered out.
 
 EXAMPLES
 --------
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 6cf708a..abb423e 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -36,6 +36,7 @@
 #include "builtin.h"
 #include "util/util.h"
 #include "util/strlist.h"
+#include "util/strfilter.h"
 #include "util/symbol.h"
 #include "util/debug.h"
 #include "util/debugfs.h"
@@ -43,6 +44,7 @@
 #include "util/probe-finder.h"
 #include "util/probe-event.h"
 
+#define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*"
 #define MAX_PATH_LEN 256
 
 /* Session management structure */
@@ -60,6 +62,7 @@ static struct {
 	struct line_range line_range;
 	const char *target_module;
 	int max_probe_points;
+	struct strfilter *filter;
 } params;
 
 /* Parse an event definition. Note that any error must die. */
@@ -156,6 +159,27 @@ static int opt_show_vars(const struct option *opt __used,
 
 	return ret;
 }
+
+static int opt_set_filter(const struct option *opt __used,
+			  const char *str, int unset __used)
+{
+	const char *err;
+
+	if (str) {
+		pr_debug2("Set filter: %s\n", str);
+		if (params.filter)
+			strfilter__delete(params.filter);
+		params.filter = strfilter__new(str, &err);
+		if (!params.filter) {
+			pr_err("Filter parse error at %ld.\n", err - str + 1);
+			pr_err("Source: \"%s\"\n", str);
+			pr_err("         %*c\n", (int)(err - str + 1), '^');
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
 #endif
 
 static const char * const probe_usage[] = {
@@ -212,6 +236,10 @@ static const struct option options[] = {
 		     "Show accessible variables on PROBEDEF", opt_show_vars),
 	OPT_BOOLEAN('\0', "externs", &params.show_ext_vars,
 		    "Show external variables too (with --vars only)"),
+	OPT_CALLBACK('\0', "filter", NULL,
+		     "[!]FILTER", "Set a variable filter (with --vars only)\n"
+		     "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\")",
+		     opt_set_filter),
 	OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
 		   "file", "vmlinux pathname"),
 	OPT_STRING('s', "source", &symbol_conf.source_prefix,
@@ -324,10 +352,16 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 			       " --add/--del.\n");
 			usage_with_options(probe_usage, options);
 		}
+		if (!params.filter)
+			params.filter = strfilter__new(DEFAULT_VAR_FILTER,
+						       NULL);
+
 		ret = show_available_vars(params.events, params.nevents,
 					  params.max_probe_points,
 					  params.target_module,
+					  params.filter,
 					  params.show_ext_vars);
+		strfilter__delete(params.filter);
 		if (ret < 0)
 			pr_err("  Error: Failed to show vars. (%d)\n", ret);
 		return ret;
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 1a93756..b231a20 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -31,6 +31,7 @@
 #include <string.h>
 #include <stdarg.h>
 #include <limits.h>
+#include <elf.h>		/* For STB_GLOBAL */
 
 #undef _GNU_SOURCE
 #include "util.h"
@@ -450,12 +451,14 @@ end:
 }
 
 static int show_available_vars_at(int fd, struct perf_probe_event *pev,
-				  int max_vls, bool externs)
+				  int max_vls, struct strfilter *_filter,
+				  bool externs)
 {
 	char *buf;
-	int ret, i;
+	int ret, i, nvars;
 	struct str_node *node;
 	struct variable_list *vls = NULL, *vl;
+	const char *var;
 
 	buf = synthesize_perf_probe_point(&pev->point);
 	if (!buf)
@@ -463,36 +466,45 @@ static int show_available_vars_at(int fd, struct perf_probe_event *pev,
 	pr_debug("Searching variables at %s\n", buf);
 
 	ret = find_available_vars_at(fd, pev, &vls, max_vls, externs);
-	if (ret > 0) {
-		/* Some variables were found */
-		fprintf(stdout, "Available variables at %s\n", buf);
-		for (i = 0; i < ret; i++) {
-			vl = &vls[i];
-			/*
-			 * A probe point might be converted to
-			 * several trace points.
-			 */
-			fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol,
-				vl->point.offset);
-			free(vl->point.symbol);
-			if (vl->vars) {
-				strlist__for_each(node, vl->vars)
+	if (ret <= 0) {
+		pr_err("Failed to find variables at %s (%d)\n", buf, ret);
+		goto end;
+	}
+	/* Some variables are found */
+	fprintf(stdout, "Available variables at %s\n", buf);
+	for (i = 0; i < ret; i++) {
+		vl = &vls[i];
+		/*
+		 * A probe point might be converted to
+		 * several trace points.
+		 */
+		fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol,
+			vl->point.offset);
+		free(vl->point.symbol);
+		nvars = 0;
+		if (vl->vars) {
+			strlist__for_each(node, vl->vars) {
+				var = strchr(node->s, '\t') + 1;
+				if (strfilter__match(_filter, var)) {
 					fprintf(stdout, "\t\t%s\n", node->s);
-				strlist__delete(vl->vars);
-			} else
-				fprintf(stdout, "(No variables)\n");
+					nvars++;
+				}
+			}
+			strlist__delete(vl->vars);
 		}
-		free(vls);
-	} else
-		pr_err("Failed to find variables at %s (%d)\n", buf, ret);
-
+		if (nvars == 0)
+			fprintf(stdout, "\t\t(No matched variables)\n");
+	}
+	free(vls);
+end:
 	free(buf);
 	return ret;
 }
 
 /* Show available variables on given probe point */
 int show_available_vars(struct perf_probe_event *pevs, int npevs,
-			int max_vls, const char *module, bool externs)
+			int max_vls, const char *module,
+			struct strfilter *_filter, bool externs)
 {
 	int i, fd, ret = 0;
 
@@ -509,7 +521,8 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
 	setup_pager();
 
 	for (i = 0; i < npevs && ret >= 0; i++)
-		ret = show_available_vars_at(fd, &pevs[i], max_vls, externs);
+		ret = show_available_vars_at(fd, &pevs[i], max_vls, _filter,
+					     externs);
 
 	close(fd);
 	return ret;
@@ -555,7 +568,9 @@ int show_line_range(struct line_range *lr __unused, const char *module __unused)
 
 int show_available_vars(struct perf_probe_event *pevs __unused,
 			int npevs __unused, int max_vls __unused,
-			const char *module __unused, bool externs __unused)
+			const char *module __unused,
+			struct strfilter *filter __unused,
+			bool externs __unused)
 {
 	pr_warning("Debuginfo-analysis is not supported.\n");
 	return -ENOSYS;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 1fb4f18..4e80b2b 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -3,6 +3,7 @@
 
 #include <stdbool.h>
 #include "strlist.h"
+#include "strfilter.h"
 
 extern bool probe_event_dry_run;
 
@@ -126,7 +127,7 @@ extern int show_perf_probe_events(void);
 extern int show_line_range(struct line_range *lr, const char *module);
 extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
 			       int max_probe_points, const char *module,
-			       bool externs);
+			       struct strfilter *filter, bool externs);
 extern int show_available_funcs(const char *module);
 
 


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

* [PATCH -perf/perf/core 6/6] perf probe: Add filters support for available functions
  2011-01-13 12:45 [PATCH -perf/perf/core 0/6] Perf probe update (support inline call-site/--funcs/--filter) Masami Hiramatsu
                   ` (4 preceding siblings ...)
  2011-01-13 12:46 ` [PATCH -perf/perf/core 5/6] perf probe: Add variable filter support Masami Hiramatsu
@ 2011-01-13 12:46 ` Masami Hiramatsu
  5 siblings, 0 replies; 24+ messages in thread
From: Masami Hiramatsu @ 2011-01-13 12:46 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Ingo Molnar
  Cc: Steven Rostedt, Srikar Dronamraju, Franck Bui-Huu, linux-kernel,
	2nddept-manager, Masami Hiramatsu, Peter Zijlstra,
	Paul Mackerras, Ingo Molnar, Arnaldo Carvalho de Melo,
	Chase Douglas, linux-kernel

Add filters support for available function list.
Default filter is "!_*" for filtering out local-purpose
symbols.

e.g.)
 # perf probe --filter="add*" -F
add_disk
add_disk_randomness
add_input_randomness
add_interrupt_randomness
add_memory
add_page_to_unevictable_list
add_page_wait_queue
...

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Cc: Chase Douglas <chase.douglas@canonical.com>
Cc: linux-kernel@vger.kernel.org
---

 tools/perf/Documentation/perf-probe.txt |    9 +++++----
 tools/perf/builtin-probe.c              |   19 +++++++++++++------
 tools/perf/util/probe-event.c           |   23 +++++++++++++----------
 tools/perf/util/probe-event.h           |    2 +-
 4 files changed, 32 insertions(+), 21 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 7542e8a..32d4af3 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -74,9 +74,10 @@ OPTIONS
 	variables.
 
 --filter=FILTER::
-	(Only for --vars) Set filter for variables. FILTER is a combination of
-	glob pattern, see FILTER PATTERN for detail.
-	Default FILTER is "!__k???tab_* & !__crc_*".
+	(Only for --vars and --funcs) Set filter for variables. FILTER is a
+	combination of glob pattern, see FILTER PATTERN for detail.
+	Default FILTER is "!__k???tab_* & !__crc_*" for --vars, and "!_*"
+	for --funcs.
 	If several filters are specified, only the last filter is valid.
 
 -f::
@@ -143,7 +144,7 @@ This provides some sort of flexibility and robustness to probe point definitions
 
 FILTER PATTERN
 --------------
- The filter pattern is glob matching pattern(s) to filter variables.
+ The filter pattern is glob matching pattern(s) to filter variables or functions.
  In addition, you can use "!" for specifying filter-out rule. You also can give several rules combined with "&" or "|", and fold those rules as one rule by using "(" ")".
 
 e.g.
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index abb423e..fcde003 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -45,6 +45,7 @@
 #include "util/probe-event.h"
 
 #define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*"
+#define DEFAULT_FUNC_FILTER "!_*"
 #define MAX_PATH_LEN 256
 
 /* Session management structure */
@@ -159,6 +160,7 @@ static int opt_show_vars(const struct option *opt __used,
 
 	return ret;
 }
+#endif
 
 static int opt_set_filter(const struct option *opt __used,
 			  const char *str, int unset __used)
@@ -180,7 +182,6 @@ static int opt_set_filter(const struct option *opt __used,
 
 	return 0;
 }
-#endif
 
 static const char * const probe_usage[] = {
 	"perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
@@ -236,10 +237,6 @@ static const struct option options[] = {
 		     "Show accessible variables on PROBEDEF", opt_show_vars),
 	OPT_BOOLEAN('\0', "externs", &params.show_ext_vars,
 		    "Show external variables too (with --vars only)"),
-	OPT_CALLBACK('\0', "filter", NULL,
-		     "[!]FILTER", "Set a variable filter (with --vars only)\n"
-		     "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\")",
-		     opt_set_filter),
 	OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
 		   "file", "vmlinux pathname"),
 	OPT_STRING('s', "source", &symbol_conf.source_prefix,
@@ -252,6 +249,11 @@ static const struct option options[] = {
 		 "Set how many probe points can be found for a probe."),
 	OPT_BOOLEAN('F', "funcs", &params.show_funcs,
 		    "Show potential probe-able functions."),
+	OPT_CALLBACK('\0', "filter", NULL,
+		     "[!]FILTER", "Set a filter (with --vars/funcs only)\n"
+		     "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n"
+		     "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)",
+		     opt_set_filter),
 	OPT_END()
 };
 
@@ -322,7 +324,12 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 			pr_err("  Error: Don't use --funcs with --vars.\n");
 			usage_with_options(probe_usage, options);
 		}
-		ret = show_available_funcs(params.target_module);
+		if (!params.filter)
+			params.filter = strfilter__new(DEFAULT_FUNC_FILTER,
+						       NULL);
+		ret = show_available_funcs(params.target_module,
+					   params.filter);
+		strfilter__delete(params.filter);
 		if (ret < 0)
 			pr_err("  Error: Failed to show functions."
 			       " (%d)\n", ret);
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index b231a20..ebf73ae 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1951,21 +1951,23 @@ int del_perf_probe_events(struct strlist *dellist)
 
 	return ret;
 }
+/* TODO: don't use a global variable for filter ... */
+static struct strfilter *available_func_filter;
 
 /*
- * If a symbol corresponds to a function with global binding return 0.
- * For all others return 1.
+ * If a symbol corresponds to a function with global binding and
+ * matches filter return 0. For all others return 1.
  */
-static int filter_non_global_functions(struct map *map __unused,
-					struct symbol *sym)
+static int filter_available_functions(struct map *map __unused,
+				      struct symbol *sym)
 {
-	if (sym->binding != STB_GLOBAL)
-		return 1;
-
-	return 0;
+	if (sym->binding == STB_GLOBAL &&
+	    strfilter__match(available_func_filter, sym->name))
+		return 0;
+	return 1;
 }
 
-int show_available_funcs(const char *module)
+int show_available_funcs(const char *module, struct strfilter *_filter)
 {
 	struct map *map;
 	int ret;
@@ -1981,7 +1983,8 @@ int show_available_funcs(const char *module)
 		pr_err("Failed to find %s map.\n", (module) ? : "kernel");
 		return -EINVAL;
 	}
-	if (map__load(map, filter_non_global_functions)) {
+	available_func_filter = _filter;
+	if (map__load(map, filter_available_functions)) {
 		pr_err("Failed to load map.\n");
 		return -EINVAL;
 	}
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 4e80b2b..3434fc9 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -128,7 +128,7 @@ extern int show_line_range(struct line_range *lr, const char *module);
 extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
 			       int max_probe_points, const char *module,
 			       struct strfilter *filter, bool externs);
-extern int show_available_funcs(const char *module);
+extern int show_available_funcs(const char *module, struct strfilter *filter);
 
 
 /* Maximum index number of event-name postfix */


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

* Re: [PATCH -perf/perf/core 4/6] perf: Add strfilter for general purpose string filter
  2011-01-13 12:46 ` [PATCH -perf/perf/core 4/6] perf: Add strfilter for general purpose string filter Masami Hiramatsu
@ 2011-01-13 13:01   ` Peter Zijlstra
  2011-01-13 13:18     ` Masami Hiramatsu
  2011-01-17 12:40   ` Arnaldo Carvalho de Melo
  1 sibling, 1 reply; 24+ messages in thread
From: Peter Zijlstra @ 2011-01-13 13:01 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Arnaldo Carvalho de Melo, Ingo Molnar, Steven Rostedt,
	Srikar Dronamraju, Franck Bui-Huu, linux-kernel, 2nddept-manager,
	Paul Mackerras, Arnaldo Carvalho de Melo

On Thu, 2011-01-13 at 21:46 +0900, Masami Hiramatsu wrote:
> Format:
> <rule> ::= <glob-exp> | "!" <rule> | <rule> <op> <rule> | "(" <rule> ")"
> <op> ::= "&" | "|"
> 
> e.g.
>  "(add* | del*) & *timer" filter rules pass strings which
>  start with add or del and end with timer. 

Why not simply use regexps?

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

* Re: [PATCH -perf/perf/core 4/6] perf: Add strfilter for general purpose string filter
  2011-01-13 13:01   ` Peter Zijlstra
@ 2011-01-13 13:18     ` Masami Hiramatsu
  0 siblings, 0 replies; 24+ messages in thread
From: Masami Hiramatsu @ 2011-01-13 13:18 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Arnaldo Carvalho de Melo, Ingo Molnar, Steven Rostedt,
	Srikar Dronamraju, Franck Bui-Huu, linux-kernel, 2nddept-manager,
	Paul Mackerras, Arnaldo Carvalho de Melo

(2011/01/13 22:01), Peter Zijlstra wrote:
> On Thu, 2011-01-13 at 21:46 +0900, Masami Hiramatsu wrote:
>> Format:
>> <rule> ::= <glob-exp> | "!" <rule> | <rule> <op> <rule> | "(" <rule> ")"
>> <op> ::= "&" | "|"
>>
>> e.g.
>>  "(add* | del*) & *timer" filter rules pass strings which
>>  start with add or del and end with timer. 
> 
> Why not simply use regexps?

IMHO, regexp is usually too complex and too powerful just for
filtering and the combination of wild cards are simple and enough. :)
Moreover, if you'd like to filter with regexp, you just can use
"| grep" or "| egrep". ;)

(Of course, it is possible to expand this filter to support regexp by simply
 adding "~REGEXP" rule as ftrace does)

Thank you,

-- 
Masami HIRAMATSU
2nd Dept. Linux Technology Center
Hitachi, Ltd., Systems Development Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com

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

* Re: [PATCH -perf/perf/core  5/6] perf probe: Add variable filter support
  2011-01-13 12:46 ` [PATCH -perf/perf/core 5/6] perf probe: Add variable filter support Masami Hiramatsu
@ 2011-01-13 21:18   ` Franck Bui-Huu
  2011-01-14  2:42     ` Masami Hiramatsu
  0 siblings, 1 reply; 24+ messages in thread
From: Franck Bui-Huu @ 2011-01-13 21:18 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Arnaldo Carvalho de Melo, Ingo Molnar, Steven Rostedt,
	Srikar Dronamraju, linux-kernel, 2nddept-manager, Peter Zijlstra,
	Paul Mackerras, Arnaldo Carvalho de Melo, Chase Douglas

Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> writes:

> Add filters support for available variable list.
> Default filter is "!__k???tab_*&!__crc_*" for
> filtering out automatically generated symbols.
>
> The format of filter rule is "[!]GLOBPATTERN", so
> you can use wild cards. If the filter rule starts with
> '!', matched variables are filter out.
>
> e.g.)
>  # perf probe -V schedule --externs --filter=cpu*

I'm wondering if the different syntax below could be simpler:

   $ perf probe add <probe>
   $ perf probe del <probe>
   $ perf probe show       

   $ perf probe list <line>
           ...       --vars[=<pattern>] [--externs] <probe>
           ...       --funcs[=<pattern>]

instead of respectively:

   $ perf probe --add=<probe>
   $ perf probe --del=<probe>
   $ perf probe [--list|-l]       

   $ perf probe [--line|-L] <line>
   $ perf probe -V <probe> [--externs] [--filter=<pattern>]
   $ perf probe --funcs

-- 
		Franck

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

* Re: [PATCH -perf/perf/core 3/6] perf probe: Add --funcs to show available functions in symtab
  2011-01-13 12:46 ` [PATCH -perf/perf/core 3/6] perf probe: Add --funcs to show available functions in symtab Masami Hiramatsu
@ 2011-01-13 21:24   ` Franck Bui-Huu
  2011-01-14  9:49     ` Masami Hiramatsu
  2011-01-26  7:23   ` [tip:perf/core] perf probe: Add --funcs to show available functions in symtab tip-bot for Masami Hiramatsu
  1 sibling, 1 reply; 24+ messages in thread
From: Franck Bui-Huu @ 2011-01-13 21:24 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Arnaldo Carvalho de Melo, Ingo Molnar, Steven Rostedt,
	Srikar Dronamraju, linux-kernel, 2nddept-manager, Peter Zijlstra,
	Paul Mackerras, Arnaldo Carvalho de Melo

Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> writes:

[...]

>  tools/perf/builtin-probe.c    |   29 +++++++++++++++++-
>  tools/perf/util/probe-event.c |   67 ++++++++++++++++++++++++++++++++++++++++-
>  tools/perf/util/probe-event.h |    1 +
>  3 files changed, 94 insertions(+), 3 deletions(-)

"tools/perf/Documentation/perf-probe.txt" is missing ;)

-- 
		Franck

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

* Re: [PATCH -perf/perf/core  5/6] perf probe: Add variable filter support
  2011-01-13 21:18   ` Franck Bui-Huu
@ 2011-01-14  2:42     ` Masami Hiramatsu
  2011-01-17 12:07       ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 24+ messages in thread
From: Masami Hiramatsu @ 2011-01-14  2:42 UTC (permalink / raw)
  To: Franck Bui-Huu
  Cc: Arnaldo Carvalho de Melo, Ingo Molnar, Steven Rostedt,
	Srikar Dronamraju, linux-kernel, 2nddept-manager, Peter Zijlstra,
	Paul Mackerras, Arnaldo Carvalho de Melo, Chase Douglas

(2011/01/14 6:18), Franck Bui-Huu wrote:
> Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> writes:
> 
>> Add filters support for available variable list.
>> Default filter is "!__k???tab_*&!__crc_*" for
>> filtering out automatically generated symbols.
>>
>> The format of filter rule is "[!]GLOBPATTERN", so
>> you can use wild cards. If the filter rule starts with
>> '!', matched variables are filter out.
>>
>> e.g.)
>>  # perf probe -V schedule --externs --filter=cpu*
> 
> I'm wondering if the different syntax below could be simpler:
> 
>    $ perf probe add <probe>
>    $ perf probe del <probe>
>    $ perf probe show       
> 
>    $ perf probe list <line>
>            ...       --vars[=<pattern>] [--externs] <probe>
>            ...       --funcs[=<pattern>]

Hm, well, if no one complains about changing the syntax
of perf probe, it may make things simple (maybe we'll also
have to drop "perf probe <PROBE>" syntax). Nowadays
we already have perf-kvm, perf-sched, etc. which use sub-sub
commands.

IMHO, for avoiding confusion old options and "perf-list", below
sub-sub commands are more suitable.

   $ perf probe add <probe>
   $ perf probe del <probe>
   $ perf probe list
   $ perf probe lines <line>
   $ perf probe vars [--filter=<pattern>|-F <pattern>] [--extern] <probe>
   $ perf probe funcs [--filter=<pattern>|-F <pattern>]

Thank you,

-- 
Masami HIRAMATSU
2nd Dept. Linux Technology Center
Hitachi, Ltd., Systems Development Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com

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

* Re: [PATCH -perf/perf/core 3/6] perf probe: Add --funcs to show available functions in symtab
  2011-01-13 21:24   ` Franck Bui-Huu
@ 2011-01-14  9:49     ` Masami Hiramatsu
  2011-01-14  9:53       ` [PATCH -perf/perf/core ] perf probe: Update perf-probe.txt for --funcs Masami Hiramatsu
  0 siblings, 1 reply; 24+ messages in thread
From: Masami Hiramatsu @ 2011-01-14  9:49 UTC (permalink / raw)
  To: Franck Bui-Huu
  Cc: Arnaldo Carvalho de Melo, Ingo Molnar, Steven Rostedt,
	Srikar Dronamraju, linux-kernel, 2nddept-manager, Peter Zijlstra,
	Paul Mackerras, Arnaldo Carvalho de Melo

(2011/01/14 6:24), Franck Bui-Huu wrote:
> Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> writes:
> 
> [...]
> 
>>  tools/perf/builtin-probe.c    |   29 +++++++++++++++++-
>>  tools/perf/util/probe-event.c |   67 ++++++++++++++++++++++++++++++++++++++++-
>>  tools/perf/util/probe-event.h |    1 +
>>  3 files changed, 94 insertions(+), 3 deletions(-)
> 
> "tools/perf/Documentation/perf-probe.txt" is missing ;)
> 

Oops, good catch :)

Thanks!

-- 
Masami HIRAMATSU
2nd Dept. Linux Technology Center
Hitachi, Ltd., Systems Development Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com

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

* [PATCH -perf/perf/core ] perf probe: Update perf-probe.txt for --funcs
  2011-01-14  9:49     ` Masami Hiramatsu
@ 2011-01-14  9:53       ` Masami Hiramatsu
  2011-01-15 16:42         ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 24+ messages in thread
From: Masami Hiramatsu @ 2011-01-14  9:53 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Ingo Molnar
  Cc: Steven Rostedt, Srikar Dronamraju, Franck Bui-Huu, linux-kernel,
	2nddept-manager, Masami Hiramatsu, Srikar Dronamraju,
	Peter Zijlstra, Paul Mackerras, Ingo Molnar,
	Arnaldo Carvalho de Melo, linux-kernel

Add a documentation about functions listing option
to perf-probe.txt

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Original-patch-from: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Cc: linux-kernel@vger.kernel.org
---

 tools/perf/Documentation/perf-probe.txt |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 32d4af3..4df425a 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -73,6 +73,10 @@ OPTIONS
 	(Only for --vars) Show external defined variables in addition to local
 	variables.
 
+-F::
+--funcs::
+	Show available functions in given module or kernel.
+
 --filter=FILTER::
 	(Only for --vars and --funcs) Set filter for variables. FILTER is a
 	combination of glob pattern, see FILTER PATTERN for detail.


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

* Re: [PATCH -perf/perf/core ] perf probe: Update perf-probe.txt for --funcs
  2011-01-14  9:53       ` [PATCH -perf/perf/core ] perf probe: Update perf-probe.txt for --funcs Masami Hiramatsu
@ 2011-01-15 16:42         ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 24+ messages in thread
From: Arnaldo Carvalho de Melo @ 2011-01-15 16:42 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Ingo Molnar, Steven Rostedt, Srikar Dronamraju, Franck Bui-Huu,
	linux-kernel, 2nddept-manager, Peter Zijlstra, Paul Mackerras

Em Fri, Jan 14, 2011 at 06:53:24PM +0900, Masami Hiramatsu escreveu:
> Add a documentation about functions listing option
> to perf-probe.txt

I think this is not 'perf probe' specific, I think the symbol routines
need a separate tool: 'perf sym' :-)

Continuing reading the other patches.
	
 
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> Original-patch-from: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
> Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
> Cc: Paul Mackerras <paulus@samba.org>
> Cc: Ingo Molnar <mingo@elte.hu>
> Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
> Cc: linux-kernel@vger.kernel.org
> ---
> 
>  tools/perf/Documentation/perf-probe.txt |    4 ++++
>  1 files changed, 4 insertions(+), 0 deletions(-)
> 
> diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
> index 32d4af3..4df425a 100644
> --- a/tools/perf/Documentation/perf-probe.txt
> +++ b/tools/perf/Documentation/perf-probe.txt
> @@ -73,6 +73,10 @@ OPTIONS
>  	(Only for --vars) Show external defined variables in addition to local
>  	variables.
>  
> +-F::
> +--funcs::
> +	Show available functions in given module or kernel.
> +
>  --filter=FILTER::
>  	(Only for --vars and --funcs) Set filter for variables. FILTER is a
>  	combination of glob pattern, see FILTER PATTERN for detail.

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

* Re: [PATCH -perf/perf/core  5/6] perf probe: Add variable filter support
  2011-01-14  2:42     ` Masami Hiramatsu
@ 2011-01-17 12:07       ` Arnaldo Carvalho de Melo
  2011-01-19  1:12         ` Masami Hiramatsu
  0 siblings, 1 reply; 24+ messages in thread
From: Arnaldo Carvalho de Melo @ 2011-01-17 12:07 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Franck Bui-Huu, Ingo Molnar, Steven Rostedt, Srikar Dronamraju,
	linux-kernel, 2nddept-manager, Peter Zijlstra, Paul Mackerras,
	Chase Douglas

Em Fri, Jan 14, 2011 at 11:42:05AM +0900, Masami Hiramatsu escreveu:
> (2011/01/14 6:18), Franck Bui-Huu wrote:
> > I'm wondering if the different syntax below could be simpler:
> > 
> >    $ perf probe add <probe>
> >    $ perf probe del <probe>
> >    $ perf probe show       
> >    $ perf probe list <line>
> >            ...       --vars[=<pattern>] [--externs] <probe>
> >            ...       --funcs[=<pattern>]
 
> Hm, well, if no one complains about changing the syntax of perf probe,
> it may make things simple (maybe we'll also have to drop "perf probe
> <PROBE>" syntax). Nowadays we already have perf-kvm, perf-sched, etc.
> which use sub-sub commands.
 
> IMHO, for avoiding confusion old options and "perf-list", below
> sub-sub commands are more suitable.
 
>    $ perf probe add <probe>
>    $ perf probe del <probe>
>    $ perf probe list
>    $ perf probe lines <line>
>    $ perf probe vars [--filter=<pattern>|-F <pattern>] [--extern] <probe>
>    $ perf probe funcs [--filter=<pattern>|-F <pattern>]

Right, and when packaging, we can do just like Ingo and Thomas are doing
with 'perf trace', create a hardlink and if argv[0] is 'probe', that is
an alias to 'perf probe', so we would do it just like:

$ probe add <probe>
$ probe del <probe>
$ probe list
$ probe lines <line>
$ probe vars [--filter=<pattern>|-F <pattern>] [--extern] <probe>
$ probe funcs [--filter=<pattern>|-F <pattern>]

[root@felicio ~]# probe
bash: probe: command not found...

Also google told me that there was an /sbin/probe utility, but that was
a long time ago, in the kernel-pcmcia-cs package, nowadays we have
pcmciautils and it doesn't have this command, so I think it is up for
grabs :-)

So I think that the 'probe funcs' makes sense, will apply that patch in
perf/core.

- Arnaldo

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

* Re: [PATCH -perf/perf/core 4/6] perf: Add strfilter for general purpose string filter
  2011-01-13 12:46 ` [PATCH -perf/perf/core 4/6] perf: Add strfilter for general purpose string filter Masami Hiramatsu
  2011-01-13 13:01   ` Peter Zijlstra
@ 2011-01-17 12:40   ` Arnaldo Carvalho de Melo
  2011-01-17 12:55     ` Arnaldo Carvalho de Melo
  1 sibling, 1 reply; 24+ messages in thread
From: Arnaldo Carvalho de Melo @ 2011-01-17 12:40 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Ingo Molnar, Steven Rostedt, Srikar Dronamraju, Franck Bui-Huu,
	linux-kernel, 2nddept-manager, Peter Zijlstra, Paul Mackerras

Em Thu, Jan 13, 2011 at 09:46:17PM +0900, Masami Hiramatsu escreveu:
> Add strfilter for general purpose string filter.
> Every filter rules are descrived by glob matching pattern
> and '!' prefix which means Logical NOT.
> A strfilter consists of those filter rules connected
> with '&' and '|'. A set of rules can be folded by using
> '(' and ')'. It also accepts spaces around rules and those

You're not checking strfilter__alloc results, I'm fixing this for you
this time :-)

- Arnaldo

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

* Re: [PATCH -perf/perf/core 4/6] perf: Add strfilter for general purpose string filter
  2011-01-17 12:40   ` Arnaldo Carvalho de Melo
@ 2011-01-17 12:55     ` Arnaldo Carvalho de Melo
  2011-01-17 16:39       ` Masami Hiramatsu
  0 siblings, 1 reply; 24+ messages in thread
From: Arnaldo Carvalho de Melo @ 2011-01-17 12:55 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Ingo Molnar, Steven Rostedt, Srikar Dronamraju, Franck Bui-Huu,
	linux-kernel, 2nddept-manager, Peter Zijlstra, Paul Mackerras

Em Mon, Jan 17, 2011 at 10:40:29AM -0200, Arnaldo Carvalho de Melo escreveu:
> Em Thu, Jan 13, 2011 at 09:46:17PM +0900, Masami Hiramatsu escreveu:
> > Add strfilter for general purpose string filter.
> > Every filter rules are descrived by glob matching pattern
> > and '!' prefix which means Logical NOT.
> > A strfilter consists of those filter rules connected
> > with '&' and '|'. A set of rules can be folded by using
> > '(' and ')'. It also accepts spaces around rules and those
> 
> You're not checking strfilter__alloc results, I'm fixing this for you
> this time :-)

Not really, please check strdup() result and strfilter__delete() needs
to traverse all the nodes, not just the ones pointed at the root, right?

Please address these problems and resubmit this patch, I merged the
first three, folding the documentation one you sent for --funcs into the
third, where the feature was added.

Please rebase from my perf/core branch at:

http://git.kernel.org/?p=linux/kernel/git/acme/linux-2.6.git;a=shortlog;h=refs/heads/perf/core

- Arnaldo

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

* Re: [PATCH -perf/perf/core 4/6] perf: Add strfilter for general purpose string filter
  2011-01-17 12:55     ` Arnaldo Carvalho de Melo
@ 2011-01-17 16:39       ` Masami Hiramatsu
  2011-01-18 13:45         ` Masami Hiramatsu
  0 siblings, 1 reply; 24+ messages in thread
From: Masami Hiramatsu @ 2011-01-17 16:39 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Ingo Molnar, Steven Rostedt, Srikar Dronamraju, Franck Bui-Huu,
	linux-kernel, 2nddept-manager, Peter Zijlstra, Paul Mackerras

(2011/01/17 21:55), Arnaldo Carvalho de Melo wrote:
> Em Mon, Jan 17, 2011 at 10:40:29AM -0200, Arnaldo Carvalho de Melo escreveu:
>> Em Thu, Jan 13, 2011 at 09:46:17PM +0900, Masami Hiramatsu escreveu:
>>> Add strfilter for general purpose string filter.
>>> Every filter rules are descrived by glob matching pattern
>>> and '!' prefix which means Logical NOT.
>>> A strfilter consists of those filter rules connected
>>> with '&' and '|'. A set of rules can be folded by using
>>> '(' and ')'. It also accepts spaces around rules and those
>>
>> You're not checking strfilter__alloc results, I'm fixing this for you
>> this time :-)
> 
> Not really, please check strdup() result and strfilter__delete() needs
> to traverse all the nodes, not just the ones pointed at the root, right?

Would you mean that it should release all the node including
ascendants? Hmm, I think we might just need to update its parent
so that it doesn't get affected, because the strfilter__delete()
doesn't know which user variable points the parent of the given node.
E.g. If we remove "b*" from "(a* | b*)", just update it as "(a* | !*)"

> Please address these problems and resubmit this patch, I merged the
> first three, folding the documentation one you sent for --funcs into the
> third, where the feature was added.
> 
> Please rebase from my perf/core branch at:
> 
> http://git.kernel.org/?p=linux/kernel/git/acme/linux-2.6.git;a=shortlog;h=refs/heads/perf/core
>

Yeah, anyway, I'll update it for fixing the misses you pointed.

Thanks!


> - Arnaldo
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/


-- 
Masami HIRAMATSU
2nd Dept. Linux Technology Center
Hitachi, Ltd., Systems Development Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com

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

* Re: [PATCH -perf/perf/core 4/6] perf: Add strfilter for general purpose string filter
  2011-01-17 16:39       ` Masami Hiramatsu
@ 2011-01-18 13:45         ` Masami Hiramatsu
  0 siblings, 0 replies; 24+ messages in thread
From: Masami Hiramatsu @ 2011-01-18 13:45 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Ingo Molnar, Steven Rostedt, Srikar Dronamraju, Franck Bui-Huu,
	linux-kernel, 2nddept-manager, Peter Zijlstra, Paul Mackerras

(2011/01/18 1:39), Masami Hiramatsu wrote:
> (2011/01/17 21:55), Arnaldo Carvalho de Melo wrote:
>> Em Mon, Jan 17, 2011 at 10:40:29AM -0200, Arnaldo Carvalho de Melo escreveu:
>>> Em Thu, Jan 13, 2011 at 09:46:17PM +0900, Masami Hiramatsu escreveu:
>>>> Add strfilter for general purpose string filter.
>>>> Every filter rules are descrived by glob matching pattern
>>>> and '!' prefix which means Logical NOT.
>>>> A strfilter consists of those filter rules connected
>>>> with '&' and '|'. A set of rules can be folded by using
>>>> '(' and ')'. It also accepts spaces around rules and those
>>>
>>> You're not checking strfilter__alloc results, I'm fixing this for you
>>> this time :-)
>>
>> Not really, please check strdup() result and strfilter__delete() needs
>> to traverse all the nodes, not just the ones pointed at the root, right?
> 
> Would you mean that it should release all the node including
> ascendants? Hmm, I think we might just need to update its parent
> so that it doesn't get affected, because the strfilter__delete()
> doesn't know which user variable points the parent of the given node.
> E.g. If we remove "b*" from "(a* | b*)", just update it as "(a* | !*)"

Hmm, I changed my mind. I think this is more than enough.
It should be prohibited to pass the strfilter which is not
the tree root. So, I think current strfilter__delete() is enough, isn't it?

Thank you,

-- 
Masami HIRAMATSU
2nd Dept. Linux Technology Center
Hitachi, Ltd., Systems Development Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com

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

* Re: [PATCH -perf/perf/core  5/6] perf probe: Add variable filter support
  2011-01-17 12:07       ` Arnaldo Carvalho de Melo
@ 2011-01-19  1:12         ` Masami Hiramatsu
  0 siblings, 0 replies; 24+ messages in thread
From: Masami Hiramatsu @ 2011-01-19  1:12 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Franck Bui-Huu, Ingo Molnar, Steven Rostedt, Srikar Dronamraju,
	linux-kernel, 2nddept-manager, Peter Zijlstra, Paul Mackerras,
	Chase Douglas

(2011/01/17 21:07), Arnaldo Carvalho de Melo wrote:
> Em Fri, Jan 14, 2011 at 11:42:05AM +0900, Masami Hiramatsu escreveu:
>> (2011/01/14 6:18), Franck Bui-Huu wrote:
>>> I'm wondering if the different syntax below could be simpler:
>>>
>>>    $ perf probe add <probe>
>>>    $ perf probe del <probe>
>>>    $ perf probe show       
>>>    $ perf probe list <line>
>>>            ...       --vars[=<pattern>] [--externs] <probe>
>>>            ...       --funcs[=<pattern>]
>  
>> Hm, well, if no one complains about changing the syntax of perf probe,
>> it may make things simple (maybe we'll also have to drop "perf probe
>> <PROBE>" syntax). Nowadays we already have perf-kvm, perf-sched, etc.
>> which use sub-sub commands.
>  
>> IMHO, for avoiding confusion old options and "perf-list", below
>> sub-sub commands are more suitable.
>  
>>    $ perf probe add <probe>
>>    $ perf probe del <probe>
>>    $ perf probe list
>>    $ perf probe lines <line>
>>    $ perf probe vars [--filter=<pattern>|-F <pattern>] [--extern] <probe>
>>    $ perf probe funcs [--filter=<pattern>|-F <pattern>]
> 
> Right, and when packaging, we can do just like Ingo and Thomas are doing
> with 'perf trace', create a hardlink and if argv[0] is 'probe', that is
> an alias to 'perf probe', so we would do it just like:
> 
> $ probe add <probe>
> $ probe del <probe>
> $ probe list
> $ probe lines <line>
> $ probe vars [--filter=<pattern>|-F <pattern>] [--extern] <probe>
> $ probe funcs [--filter=<pattern>|-F <pattern>]

Looks good! :)

BTW, it seems that 'make clean' doesn't cleanup that
'trace' hardlink...

> 
> [root@felicio ~]# probe
> bash: probe: command not found...
> 
> Also google told me that there was an /sbin/probe utility, but that was
> a long time ago, in the kernel-pcmcia-cs package, nowadays we have
> pcmciautils and it doesn't have this command, so I think it is up for
> grabs :-)
> 
> So I think that the 'probe funcs' makes sense, will apply that patch in
> perf/core.

Thanks!


-- 
Masami HIRAMATSU
2nd Dept. Linux Technology Center
Hitachi, Ltd., Systems Development Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com

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

* [tip:perf/core] perf probe: Introduce lines walker interface
  2011-01-13 12:45 ` [PATCH -perf/perf/core 1/6] perf probe: Introduce lines walker interface Masami Hiramatsu
@ 2011-01-26  7:22   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 24+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2011-01-26  7:22 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, paulus, hpa, mingo, a.p.zijlstra, fbuihuu,
	masami.hiramatsu.pt, rostedt, srikar, tglx, mingo

Commit-ID:  4cc9cec636e7f78aba7f17606ac13cac07ea5787
Gitweb:     http://git.kernel.org/tip/4cc9cec636e7f78aba7f17606ac13cac07ea5787
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Thu, 13 Jan 2011 21:45:58 +0900
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Mon, 24 Jan 2011 10:49:52 -0200

perf probe: Introduce lines walker interface

Introduce die_walk_lines() for walking on the line list of given die, and use
it in line_range finder and probe point finder.

Cc: 2nddept-manager@sdl.hitachi.co.jp
Cc: Franck Bui-Huu <fbuihuu@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
LKML-Reference: <20110113124558.22426.48170.stgit@ltc236.sdl.hitachi.co.jp>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
[ committer note: s/%ld/%zd/ for a size_t nlines var that broke f14 x86 build]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/probe-finder.c |  321 +++++++++++++++++++++-------------------
 1 files changed, 167 insertions(+), 154 deletions(-)

diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index ab83b6a..508c017 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -458,6 +458,124 @@ static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
 	return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
 }
 
+/* Walker on lines (Note: line number will not be sorted) */
+typedef int (* line_walk_handler_t) (const char *fname, int lineno,
+				     Dwarf_Addr addr, void *data);
+
+struct __line_walk_param {
+	line_walk_handler_t handler;
+	void *data;
+	int retval;
+};
+
+/* Walk on decl lines in given DIE */
+static int __die_walk_funclines(Dwarf_Die *sp_die,
+				line_walk_handler_t handler, void *data)
+{
+	const char *fname;
+	Dwarf_Addr addr;
+	int lineno, ret = 0;
+
+	/* Handle function declaration line */
+	fname = dwarf_decl_file(sp_die);
+	if (fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
+	    dwarf_entrypc(sp_die, &addr) == 0) {
+		ret = handler(fname, lineno, addr, data);
+	}
+
+	return ret;
+}
+
+static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)
+{
+	struct __line_walk_param *lw = data;
+
+	lw->retval = __die_walk_funclines(sp_die, lw->handler, lw->data);
+	if (lw->retval != 0)
+		return DWARF_CB_ABORT;
+
+	return DWARF_CB_OK;
+}
+
+/*
+ * Walk on lines inside given PDIE. If the PDIE is subprogram, walk only on
+ * the lines inside the subprogram, otherwise PDIE must be a CU DIE.
+ */
+static int die_walk_lines(Dwarf_Die *pdie, line_walk_handler_t handler,
+			  void *data)
+{
+	Dwarf_Lines *lines;
+	Dwarf_Line *line;
+	Dwarf_Addr addr;
+	const char *fname;
+	int lineno, ret = 0;
+	Dwarf_Die die_mem, *cu_die;
+	size_t nlines, i;
+
+	/* Get the CU die */
+	if (dwarf_tag(pdie) == DW_TAG_subprogram)
+		cu_die = dwarf_diecu(pdie, &die_mem, NULL, NULL);
+	else
+		cu_die = pdie;
+	if (!cu_die) {
+		pr_debug2("Failed to get CU from subprogram\n");
+		return -EINVAL;
+	}
+
+	/* Get lines list in the CU */
+	if (dwarf_getsrclines(cu_die, &lines, &nlines) != 0) {
+		pr_debug2("Failed to get source lines on this CU.\n");
+		return -ENOENT;
+	}
+	pr_debug2("Get %zd lines from this CU\n", nlines);
+
+	/* Walk on the lines on lines list */
+	for (i = 0; i < nlines; i++) {
+		line = dwarf_onesrcline(lines, i);
+		if (line == NULL ||
+		    dwarf_lineno(line, &lineno) != 0 ||
+		    dwarf_lineaddr(line, &addr) != 0) {
+			pr_debug2("Failed to get line info. "
+				  "Possible error in debuginfo.\n");
+			continue;
+		}
+		/* Filter lines based on address */
+		if (pdie != cu_die)
+			/*
+			 * Address filtering
+			 * The line is included in given function, and
+			 * no inline block includes it.
+			 */
+			if (!dwarf_haspc(pdie, addr) ||
+			    die_find_inlinefunc(pdie, addr, &die_mem))
+				continue;
+		/* Get source line */
+		fname = dwarf_linesrc(line, NULL, NULL);
+
+		ret = handler(fname, lineno, addr, data);
+		if (ret != 0)
+			return ret;
+	}
+
+	/*
+	 * Dwarf lines doesn't include function declarations and inlined
+	 * subroutines. We have to check functions list or given function.
+	 */
+	if (pdie != cu_die)
+		ret = __die_walk_funclines(pdie, handler, data);
+	else {
+		struct __line_walk_param param = {
+			.handler = handler,
+			.data = data,
+			.retval = 0,
+		};
+		dwarf_getfuncs(cu_die, __die_walk_culines_cb, &param, 0);
+		ret = param.retval;
+	}
+
+	return ret;
+}
+
 struct __find_variable_param {
 	const char *name;
 	Dwarf_Addr addr;
@@ -1050,43 +1168,26 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
 	return ret;
 }
 
-/* Find probe point from its line number */
-static int find_probe_point_by_line(struct probe_finder *pf)
+static int probe_point_line_walker(const char *fname, int lineno,
+				   Dwarf_Addr addr, void *data)
 {
-	Dwarf_Lines *lines;
-	Dwarf_Line *line;
-	size_t nlines, i;
-	Dwarf_Addr addr;
-	int lineno;
-	int ret = 0;
+	struct probe_finder *pf = data;
+	int ret;
 
-	if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
-		pr_warning("No source lines found.\n");
-		return -ENOENT;
-	}
+	if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0)
+		return 0;
 
-	for (i = 0; i < nlines && ret == 0; i++) {
-		line = dwarf_onesrcline(lines, i);
-		if (dwarf_lineno(line, &lineno) != 0 ||
-		    lineno != pf->lno)
-			continue;
+	pf->addr = addr;
+	ret = call_probe_finder(NULL, pf);
 
-		/* TODO: Get fileno from line, but how? */
-		if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
-			continue;
-
-		if (dwarf_lineaddr(line, &addr) != 0) {
-			pr_warning("Failed to get the address of the line.\n");
-			return -ENOENT;
-		}
-		pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n",
-			 (int)i, lineno, (uintmax_t)addr);
-		pf->addr = addr;
+	/* Continue if no error, because the line will be in inline function */
+	return ret < 0 ?: 0;
+}
 
-		ret = call_probe_finder(NULL, pf);
-		/* Continuing, because target line might be inlined. */
-	}
-	return ret;
+/* Find probe point from its line number */
+static int find_probe_point_by_line(struct probe_finder *pf)
+{
+	return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf);
 }
 
 /* Find lines which match lazy pattern */
@@ -1140,15 +1241,31 @@ out_close:
 	return nlines;
 }
 
+static int probe_point_lazy_walker(const char *fname, int lineno,
+				   Dwarf_Addr addr, void *data)
+{
+	struct probe_finder *pf = data;
+	int ret;
+
+	if (!line_list__has_line(&pf->lcache, lineno) ||
+	    strtailcmp(fname, pf->fname) != 0)
+		return 0;
+
+	pr_debug("Probe line found: line:%d addr:0x%llx\n",
+		 lineno, (unsigned long long)addr);
+	pf->addr = addr;
+	ret = call_probe_finder(NULL, pf);
+
+	/*
+	 * Continue if no error, because the lazy pattern will match
+	 * to other lines
+	 */
+	return ret < 0 ?: 0;
+}
+
 /* Find probe points from lazy pattern  */
 static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
 {
-	Dwarf_Lines *lines;
-	Dwarf_Line *line;
-	size_t nlines, i;
-	Dwarf_Addr addr;
-	Dwarf_Die die_mem;
-	int lineno;
 	int ret = 0;
 
 	if (list_empty(&pf->lcache)) {
@@ -1162,45 +1279,7 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
 			return ret;
 	}
 
-	if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
-		pr_warning("No source lines found.\n");
-		return -ENOENT;
-	}
-
-	for (i = 0; i < nlines && ret >= 0; i++) {
-		line = dwarf_onesrcline(lines, i);
-
-		if (dwarf_lineno(line, &lineno) != 0 ||
-		    !line_list__has_line(&pf->lcache, lineno))
-			continue;
-
-		/* TODO: Get fileno from line, but how? */
-		if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
-			continue;
-
-		if (dwarf_lineaddr(line, &addr) != 0) {
-			pr_debug("Failed to get the address of line %d.\n",
-				 lineno);
-			continue;
-		}
-		if (sp_die) {
-			/* Address filtering 1: does sp_die include addr? */
-			if (!dwarf_haspc(sp_die, addr))
-				continue;
-			/* Address filtering 2: No child include addr? */
-			if (die_find_inlinefunc(sp_die, addr, &die_mem))
-				continue;
-		}
-
-		pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n",
-			 (int)i, lineno, (unsigned long long)addr);
-		pf->addr = addr;
-
-		ret = call_probe_finder(sp_die, pf);
-		/* Continuing, because target line might be inlined. */
-	}
-	/* TODO: deallocate lines, but how? */
-	return ret;
+	return die_walk_lines(sp_die, probe_point_lazy_walker, pf);
 }
 
 /* Callback parameter with return value */
@@ -1644,91 +1723,28 @@ static int line_range_add_line(const char *src, unsigned int lineno,
 	return line_list__add_line(&lr->line_list, lineno);
 }
 
-/* Search function declaration lines */
-static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data)
+static int line_range_walk_cb(const char *fname, int lineno,
+			      Dwarf_Addr addr __used,
+			      void *data)
 {
-	struct dwarf_callback_param *param = data;
-	struct line_finder *lf = param->data;
-	const char *src;
-	int lineno;
-
-	src = dwarf_decl_file(sp_die);
-	if (src && strtailcmp(src, lf->fname) != 0)
-		return DWARF_CB_OK;
+	struct line_finder *lf = data;
 
-	if (dwarf_decl_line(sp_die, &lineno) != 0 ||
+	if ((strtailcmp(fname, lf->fname) != 0) ||
 	    (lf->lno_s > lineno || lf->lno_e < lineno))
-		return DWARF_CB_OK;
+		return 0;
 
-	param->retval = line_range_add_line(src, lineno, lf->lr);
-	if (param->retval < 0)
-		return DWARF_CB_ABORT;
-	return DWARF_CB_OK;
-}
+	if (line_range_add_line(fname, lineno, lf->lr) < 0)
+		return -EINVAL;
 
-static int find_line_range_func_decl_lines(struct line_finder *lf)
-{
-	struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0};
-	dwarf_getfuncs(&lf->cu_die, line_range_funcdecl_cb, &param, 0);
-	return param.retval;
+	return 0;
 }
 
 /* Find line range from its line number */
 static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
 {
-	Dwarf_Lines *lines;
-	Dwarf_Line *line;
-	size_t nlines, i;
-	Dwarf_Addr addr;
-	int lineno, ret = 0;
-	const char *src;
-	Dwarf_Die die_mem;
-
-	line_list__init(&lf->lr->line_list);
-	if (dwarf_getsrclines(&lf->cu_die, &lines, &nlines) != 0) {
-		pr_warning("No source lines found.\n");
-		return -ENOENT;
-	}
-
-	/* Search probable lines on lines list */
-	for (i = 0; i < nlines; i++) {
-		line = dwarf_onesrcline(lines, i);
-		if (dwarf_lineno(line, &lineno) != 0 ||
-		    (lf->lno_s > lineno || lf->lno_e < lineno))
-			continue;
-
-		if (sp_die) {
-			/* Address filtering 1: does sp_die include addr? */
-			if (dwarf_lineaddr(line, &addr) != 0 ||
-			    !dwarf_haspc(sp_die, addr))
-				continue;
-
-			/* Address filtering 2: No child include addr? */
-			if (die_find_inlinefunc(sp_die, addr, &die_mem))
-				continue;
-		}
-
-		/* TODO: Get fileno from line, but how? */
-		src = dwarf_linesrc(line, NULL, NULL);
-		if (strtailcmp(src, lf->fname) != 0)
-			continue;
-
-		ret = line_range_add_line(src, lineno, lf->lr);
-		if (ret < 0)
-			return ret;
-	}
+	int ret;
 
-	/*
-	 * Dwarf lines doesn't include function declarations. We have to
-	 * check functions list or given function.
-	 */
-	if (sp_die) {
-		src = dwarf_decl_file(sp_die);
-		if (src && dwarf_decl_line(sp_die, &lineno) == 0 &&
-		    (lf->lno_s <= lineno && lf->lno_e >= lineno))
-			ret = line_range_add_line(src, lineno, lf->lr);
-	} else
-		ret = find_line_range_func_decl_lines(lf);
+	ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf);
 
 	/* Update status */
 	if (ret >= 0)
@@ -1758,9 +1774,6 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
 	struct line_finder *lf = param->data;
 	struct line_range *lr = lf->lr;
 
-	pr_debug("find (%llx) %s\n",
-		 (unsigned long long)dwarf_dieoffset(sp_die),
-		 dwarf_diename(sp_die));
 	if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
 	    die_compare_name(sp_die, lr->function)) {
 		lf->fname = dwarf_decl_file(sp_die);

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

* [tip:perf/core] perf probe: Enable to put probe inline function call site
  2011-01-13 12:46 ` [PATCH -perf/perf/core 2/6] perf probe: Enable to put probe inline function call site Masami Hiramatsu
@ 2011-01-26  7:22   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 24+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2011-01-26  7:22 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, paulus, hpa, mingo, a.p.zijlstra, fbuihuu,
	masami.hiramatsu.pt, rostedt, srikar, tglx, mingo

Commit-ID:  5069ed86be3c2f28bcdf7fae1374ec0c325aafba
Gitweb:     http://git.kernel.org/tip/5069ed86be3c2f28bcdf7fae1374ec0c325aafba
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Thu, 13 Jan 2011 21:46:05 +0900
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Mon, 24 Jan 2011 10:57:03 -0200

perf probe: Enable to put probe inline function call site

Enable to put probe inline function call site. This will increase line-based
probe-ability.

<Without this patch>
$ ./perf probe -L schedule:48
<schedule:48>
                pre_schedule(rq, prev);

     50         if (unlikely(!rq->nr_running))
                        idle_balance(cpu, rq);

                put_prev_task(rq, prev);
                next = pick_next_task(rq);

     56         if (likely(prev != next)) {
                        sched_info_switch(prev, next);
                        trace_sched_switch_out(prev, next);
                        perf_event_task_sched_out(prev, next);

<With this patch>
$ ./perf probe -L schedule:48
<schedule:48>
     48         pre_schedule(rq, prev);

     50         if (unlikely(!rq->nr_running))
     51                 idle_balance(cpu, rq);

     53         put_prev_task(rq, prev);
     54         next = pick_next_task(rq);

     56         if (likely(prev != next)) {
     57                 sched_info_switch(prev, next);
     58                 trace_sched_switch_out(prev, next);
     59                 perf_event_task_sched_out(prev, next);

Cc: 2nddept-manager@sdl.hitachi.co.jp
Cc: Franck Bui-Huu <fbuihuu@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
LKML-Reference: <20110113124604.22426.48873.stgit@ltc236.sdl.hitachi.co.jp>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/probe-finder.c |   56 ++++++++++++++++++++++++++++++++++-----
 1 files changed, 48 insertions(+), 8 deletions(-)

diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 508c017..69215bf 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -280,6 +280,19 @@ static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
 	return name ? (strcmp(tname, name) == 0) : false;
 }
 
+/* Get callsite line number of inline-function instance */
+static int die_get_call_lineno(Dwarf_Die *in_die)
+{
+	Dwarf_Attribute attr;
+	Dwarf_Word ret;
+
+	if (!dwarf_attr(in_die, DW_AT_call_line, &attr))
+		return -ENOENT;
+
+	dwarf_formudata(&attr, &ret);
+	return (int)ret;
+}
+
 /* Get type die */
 static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
 {
@@ -463,27 +476,54 @@ typedef int (* line_walk_handler_t) (const char *fname, int lineno,
 				     Dwarf_Addr addr, void *data);
 
 struct __line_walk_param {
+	const char *fname;
 	line_walk_handler_t handler;
 	void *data;
 	int retval;
 };
 
-/* Walk on decl lines in given DIE */
+static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data)
+{
+	struct __line_walk_param *lw = data;
+	Dwarf_Addr addr;
+	int lineno;
+
+	if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) {
+		lineno = die_get_call_lineno(in_die);
+		if (lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) {
+			lw->retval = lw->handler(lw->fname, lineno, addr,
+						 lw->data);
+			if (lw->retval != 0)
+				return DIE_FIND_CB_FOUND;
+		}
+	}
+	return DIE_FIND_CB_SIBLING;
+}
+
+/* Walk on lines of blocks included in given DIE */
 static int __die_walk_funclines(Dwarf_Die *sp_die,
 				line_walk_handler_t handler, void *data)
 {
-	const char *fname;
+	struct __line_walk_param lw = {
+		.handler = handler,
+		.data = data,
+		.retval = 0,
+	};
+	Dwarf_Die die_mem;
 	Dwarf_Addr addr;
-	int lineno, ret = 0;
+	int lineno;
 
 	/* Handle function declaration line */
-	fname = dwarf_decl_file(sp_die);
-	if (fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
+	lw.fname = dwarf_decl_file(sp_die);
+	if (lw.fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
 	    dwarf_entrypc(sp_die, &addr) == 0) {
-		ret = handler(fname, lineno, addr, data);
+		lw.retval = handler(lw.fname, lineno, addr, data);
+		if (lw.retval != 0)
+			goto done;
 	}
-
-	return ret;
+	die_find_child(sp_die, __die_walk_funclines_cb, &lw, &die_mem);
+done:
+	return lw.retval;
 }
 
 static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)

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

* [tip:perf/core] perf probe: Add --funcs to show available functions in symtab
  2011-01-13 12:46 ` [PATCH -perf/perf/core 3/6] perf probe: Add --funcs to show available functions in symtab Masami Hiramatsu
  2011-01-13 21:24   ` Franck Bui-Huu
@ 2011-01-26  7:23   ` tip-bot for Masami Hiramatsu
  1 sibling, 0 replies; 24+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2011-01-26  7:23 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, paulus, hpa, mingo, a.p.zijlstra, fbuihuu,
	masami.hiramatsu.pt, rostedt, srikar, tglx, mingo

Commit-ID:  e80711ca8512c8586da0c3e18e2f1caf73c88731
Gitweb:     http://git.kernel.org/tip/e80711ca8512c8586da0c3e18e2f1caf73c88731
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Thu, 13 Jan 2011 21:46:11 +0900
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Mon, 24 Jan 2011 10:57:55 -0200

perf probe: Add --funcs to show available functions in symtab

Add --funcs to show available functions in symtab.

Originally this feature came from Srikar's uprobes patches
( http://lkml.org/lkml/2010/8/27/244 )

e.g.
...
__ablkcipher_walk_complete
__absent_pages_in_range
__account_scheduler_latency
__add_pages
__alloc_pages_nodemask
__alloc_percpu
__alloc_reserved_percpu
__alloc_skb
__alloc_workqueue_key
__any_online_cpu
__ata_ehi_push_desc
...

This also supports symbols in module, e.g.

...
cleanup_module
cpuid_maxphyaddr
emulate_clts
emulate_instruction
emulate_int_real
emulate_invlpg
emulator_get_dr
emulator_set_dr
emulator_task_switch
emulator_write_emulated
emulator_write_phys
fx_init
...

Original-patch-from: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: 2nddept-manager@sdl.hitachi.co.jp
Cc: Franck Bui-Huu <fbuihuu@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
LKML-Reference: <20110113124611.22426.10835.stgit@ltc236.sdl.hitachi.co.jp>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
[ committer note: Add missing elf.h for STB_GLOBAL that broke a RHEL4 build ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/Documentation/perf-probe.txt |    4 ++
 tools/perf/builtin-probe.c              |   29 +++++++++++++-
 tools/perf/util/probe-event.c           |   68 ++++++++++++++++++++++++++++++-
 tools/perf/util/probe-event.h           |    1 +
 4 files changed, 99 insertions(+), 3 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 86b797a..fcc51fe 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -73,6 +73,10 @@ OPTIONS
 	(Only for --vars) Show external defined variables in addition to local
 	variables.
 
+-F::
+--funcs::
+	Show available functions in given module or kernel.
+
 -f::
 --force::
 	Forcibly add events with existing name.
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index add163c..6cf708a 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -52,6 +52,7 @@ static struct {
 	bool show_lines;
 	bool show_vars;
 	bool show_ext_vars;
+	bool show_funcs;
 	bool mod_events;
 	int nevents;
 	struct perf_probe_event events[MAX_PROBES];
@@ -221,6 +222,8 @@ static const struct option options[] = {
 	OPT__DRY_RUN(&probe_event_dry_run),
 	OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
 		 "Set how many probe points can be found for a probe."),
+	OPT_BOOLEAN('F', "funcs", &params.show_funcs,
+		    "Show potential probe-able functions."),
 	OPT_END()
 };
 
@@ -246,7 +249,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 		params.max_probe_points = MAX_PROBES;
 
 	if ((!params.nevents && !params.dellist && !params.list_events &&
-	     !params.show_lines))
+	     !params.show_lines && !params.show_funcs))
 		usage_with_options(probe_usage, options);
 
 	/*
@@ -267,12 +270,36 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 			pr_err(" Error: Don't use --list with --vars.\n");
 			usage_with_options(probe_usage, options);
 		}
+		if (params.show_funcs) {
+			pr_err("  Error: Don't use --list with --funcs.\n");
+			usage_with_options(probe_usage, options);
+		}
 		ret = show_perf_probe_events();
 		if (ret < 0)
 			pr_err("  Error: Failed to show event list. (%d)\n",
 			       ret);
 		return ret;
 	}
+	if (params.show_funcs) {
+		if (params.nevents != 0 || params.dellist) {
+			pr_err("  Error: Don't use --funcs with"
+			       " --add/--del.\n");
+			usage_with_options(probe_usage, options);
+		}
+		if (params.show_lines) {
+			pr_err("  Error: Don't use --funcs with --line.\n");
+			usage_with_options(probe_usage, options);
+		}
+		if (params.show_vars) {
+			pr_err("  Error: Don't use --funcs with --vars.\n");
+			usage_with_options(probe_usage, options);
+		}
+		ret = show_available_funcs(params.target_module);
+		if (ret < 0)
+			pr_err("  Error: Failed to show functions."
+			       " (%d)\n", ret);
+		return ret;
+	}
 
 #ifdef DWARF_SUPPORT
 	if (params.show_lines) {
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 6e29d9c..859d377 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -31,6 +31,7 @@
 #include <string.h>
 #include <stdarg.h>
 #include <limits.h>
+#include <elf.h>
 
 #undef _GNU_SOURCE
 #include "util.h"
@@ -111,7 +112,25 @@ static struct symbol *__find_kernel_function_by_name(const char *name,
 						     NULL);
 }
 
-const char *kernel_get_module_path(const char *module)
+static struct map *kernel_get_module_map(const char *module)
+{
+	struct rb_node *nd;
+	struct map_groups *grp = &machine.kmaps;
+
+	if (!module)
+		module = "kernel";
+
+	for (nd = rb_first(&grp->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) {
+		struct map *pos = rb_entry(nd, struct map, rb_node);
+		if (strncmp(pos->dso->short_name + 1, module,
+			    pos->dso->short_name_len - 2) == 0) {
+			return pos;
+		}
+	}
+	return NULL;
+}
+
+static struct dso *kernel_get_module_dso(const char *module)
 {
 	struct dso *dso;
 	struct map *map;
@@ -141,7 +160,13 @@ const char *kernel_get_module_path(const char *module)
 		}
 	}
 found:
-	return dso->long_name;
+	return dso;
+}
+
+const char *kernel_get_module_path(const char *module)
+{
+	struct dso *dso = kernel_get_module_dso(module);
+	return (dso) ? dso->long_name : NULL;
 }
 
 #ifdef DWARF_SUPPORT
@@ -1913,3 +1938,42 @@ int del_perf_probe_events(struct strlist *dellist)
 	return ret;
 }
 
+/*
+ * If a symbol corresponds to a function with global binding return 0.
+ * For all others return 1.
+ */
+static int filter_non_global_functions(struct map *map __unused,
+					struct symbol *sym)
+{
+	if (sym->binding != STB_GLOBAL)
+		return 1;
+
+	return 0;
+}
+
+int show_available_funcs(const char *module)
+{
+	struct map *map;
+	int ret;
+
+	setup_pager();
+
+	ret = init_vmlinux();
+	if (ret < 0)
+		return ret;
+
+	map = kernel_get_module_map(module);
+	if (!map) {
+		pr_err("Failed to find %s map.\n", (module) ? : "kernel");
+		return -EINVAL;
+	}
+	if (map__load(map, filter_non_global_functions)) {
+		pr_err("Failed to load map.\n");
+		return -EINVAL;
+	}
+	if (!dso__sorted_by_name(map->dso, map->type))
+		dso__sort_by_name(map->dso, map->type);
+
+	dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
+	return 0;
+}
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 5accbed..1fb4f18 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -127,6 +127,7 @@ extern int show_line_range(struct line_range *lr, const char *module);
 extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
 			       int max_probe_points, const char *module,
 			       bool externs);
+extern int show_available_funcs(const char *module);
 
 
 /* Maximum index number of event-name postfix */

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

end of thread, other threads:[~2011-01-26  7:23 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-01-13 12:45 [PATCH -perf/perf/core 0/6] Perf probe update (support inline call-site/--funcs/--filter) Masami Hiramatsu
2011-01-13 12:45 ` [PATCH -perf/perf/core 1/6] perf probe: Introduce lines walker interface Masami Hiramatsu
2011-01-26  7:22   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
2011-01-13 12:46 ` [PATCH -perf/perf/core 2/6] perf probe: Enable to put probe inline function call site Masami Hiramatsu
2011-01-26  7:22   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
2011-01-13 12:46 ` [PATCH -perf/perf/core 3/6] perf probe: Add --funcs to show available functions in symtab Masami Hiramatsu
2011-01-13 21:24   ` Franck Bui-Huu
2011-01-14  9:49     ` Masami Hiramatsu
2011-01-14  9:53       ` [PATCH -perf/perf/core ] perf probe: Update perf-probe.txt for --funcs Masami Hiramatsu
2011-01-15 16:42         ` Arnaldo Carvalho de Melo
2011-01-26  7:23   ` [tip:perf/core] perf probe: Add --funcs to show available functions in symtab tip-bot for Masami Hiramatsu
2011-01-13 12:46 ` [PATCH -perf/perf/core 4/6] perf: Add strfilter for general purpose string filter Masami Hiramatsu
2011-01-13 13:01   ` Peter Zijlstra
2011-01-13 13:18     ` Masami Hiramatsu
2011-01-17 12:40   ` Arnaldo Carvalho de Melo
2011-01-17 12:55     ` Arnaldo Carvalho de Melo
2011-01-17 16:39       ` Masami Hiramatsu
2011-01-18 13:45         ` Masami Hiramatsu
2011-01-13 12:46 ` [PATCH -perf/perf/core 5/6] perf probe: Add variable filter support Masami Hiramatsu
2011-01-13 21:18   ` Franck Bui-Huu
2011-01-14  2:42     ` Masami Hiramatsu
2011-01-17 12:07       ` Arnaldo Carvalho de Melo
2011-01-19  1:12         ` Masami Hiramatsu
2011-01-13 12:46 ` [PATCH -perf/perf/core 6/6] perf probe: Add filters support for available functions Masami Hiramatsu

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.