All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH perf/core v3 00/17] perf-probe --cache and SDT support
@ 2015-08-15 11:42 Masami Hiramatsu
  2015-08-15 11:42 ` [RFC PATCH perf/core v3 01/17] perf probe: Use strbuf for making strings in probe-event.c Masami Hiramatsu
                   ` (17 more replies)
  0 siblings, 18 replies; 25+ messages in thread
From: Masami Hiramatsu @ 2015-08-15 11:42 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, Adrian Hunter, Ingo Molnar,
	Paul Mackerras, Jiri Olsa, Namhyung Kim, Borislav Petkov,
	Hemant Kumar

Hi,

Here is the 3rd version of the patchset for probe-cache and 
initial SDT support which are going to be perf-cache finally.

The previous version is here; https://lkml.org/lkml/2015/7/15/221

This version improves SDT support for perf-list and perf-record.
It is still just a basic support (no wildcard support, nor
@FILE/@BUILDID support). So this is an ongoing work report :)

As we discussed on the previous series, now all SDT events have
"sdt_" prefix on the provider name. We also should support "@FILE"
or "@BUILDID" suffixes for same-name SDTs.

perf-list shows only SDTs on existing binaries (no old/deleted
files) and if the same-name events are shown, it adds 
"@FILE@BUILDID" suffixes after the events to clarify on which
binary the SDT exists.

  ----
  # perf buildid-cache -a /usr/bin/gcc
  # perf list sdt

  List of pre-defined events (to be used in -e):

    sdt_libgcc:unwind                                  [SDT event]
    sdt_libstdcxx:catch                                [SDT event]
    sdt_libstdcxx:rethrow                              [SDT event]
    sdt_libstdcxx:throw                                [SDT event]
  # perf buildid-cache -a /usr/lib/libstdc++.so.6
  # perf list sdt

  List of pre-defined events (to be used in -e):

    sdt_libgcc:unwind                                  [SDT event]
    sdt_libstdcxx:catch@/usr/bin/gcc@0x05d261236bbb    [SDT event]
    sdt_libstdcxx:catch@/usr/lib/libstdc++.so.6.0.19@0xcd6ac0e6236c [SDT event]
    sdt_libstdcxx:rethrow@/usr/bin/gcc@0x05d261236bbb  [SDT event]
    sdt_libstdcxx:rethrow@/usr/lib/libstdc++.so.6.0.19@0xcd6ac0e6236c [SDT event]
    sdt_libstdcxx:throw@/usr/bin/gcc@0x05d261236bbb    [SDT event]
    sdt_libstdcxx:throw@/usr/lib/libstdc++.so.6.0.19@0xcd6ac0e6236c [SDT event]
  ----

In this version, I used "@" separater for both FILE and BUILDID,
but I think it is also possible to use "%" for BUILDID.
(BTW, I've cut down the BUILDID to the first 12 chars, and added "0x") 

TODOs:
 - (perf record) Allow glob matching for SDT event to specify events.
 - (perf record) Support @FILE/@BUILDID suffix to record specific SDTs.
 - (perf record) Try to unregister SDT events after record.
 - (perf probe) Allow glob matching for pre-cached events.
 - (perf probe) Support @FILE/@BUILDID suffix for pre-cached events.
               (also removes -x option when using pre-cached events)
 - (ftrace) Support multiple SDTs on single event.

Since multiple same SDTs are defined in a single binary (e.g. libc:setjump
has 3 different entries on libc-2.17.so), we need the last feature on
ftrace, so that a single uprobe event can occur several different
probe points.

Thank you,

---

Hemant Kumar (1):
      perf/sdt: ELF support for SDT

Masami Hiramatsu (16):
      perf probe: Use strbuf for making strings in probe-event.c
      perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid
      perf buildid: Introduce sysfs/filename__sprintf_build_id
      perf: Add lsdir to read a directory
      perf-buildid-cache: Use lsdir for looking up buildid caches
      perf probe: Add --cache option to cache the probe definitions
      perf probe: Use cache entry if possible
      perf probe: Show all cached probes
      perf probe: Remove caches when --cache is given
      perf probe: Add group name support
      perf-probe: Set default kprobe group name if it is not given
      perf buildid-cache: Scan and import user SDT events to probe cache
      perf probe: Accept %sdt and %cached event name
      perf-list: Show SDT events
      perf-list: Skip SDTs placed in invalid binaries
      perf record: Support recording SDT events


 tools/perf/Documentation/perf-probe.txt |   14 +
 tools/perf/builtin-buildid-cache.c      |   14 -
 tools/perf/builtin-buildid-list.c       |   24 +
 tools/perf/builtin-list.c               |    3 
 tools/perf/builtin-probe.c              |    6 
 tools/perf/util/build-id.c              |  255 +++++++++++---
 tools/perf/util/build-id.h              |    8 
 tools/perf/util/dso.h                   |    5 
 tools/perf/util/parse-events.c          |  142 ++++++++
 tools/perf/util/parse-events.h          |    2 
 tools/perf/util/probe-event.c           |  574 ++++++++++++++++++++-----------
 tools/perf/util/probe-event.h           |   10 -
 tools/perf/util/probe-file.c            |  467 +++++++++++++++++++++++++
 tools/perf/util/probe-file.h            |   28 ++
 tools/perf/util/probe-finder.c          |   14 -
 tools/perf/util/symbol-elf.c            |  252 ++++++++++++++
 tools/perf/util/symbol.c                |    2 
 tools/perf/util/symbol.h                |   22 +
 tools/perf/util/util.c                  |   34 ++
 tools/perf/util/util.h                  |    4 
 20 files changed, 1580 insertions(+), 300 deletions(-)


-- 
Masami HIRAMATSU
Linux Technology Research Center, System Productivity Research Dept.
Center for Technology Innovation - Systems Engineering 
Hitachi, Ltd., Research & Development Group
E-mail: masami.hiramatsu.pt@hitachi.com

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

* [RFC PATCH perf/core v3 01/17] perf probe: Use strbuf for making strings in probe-event.c
  2015-08-15 11:42 [RFC PATCH perf/core v3 00/17] perf-probe --cache and SDT support Masami Hiramatsu
@ 2015-08-15 11:42 ` Masami Hiramatsu
  2015-08-28 15:56   ` Arnaldo Carvalho de Melo
  2015-08-15 11:42 ` [RFC PATCH perf/core v3 02/17] perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid Masami Hiramatsu
                   ` (16 subsequent siblings)
  17 siblings, 1 reply; 25+ messages in thread
From: Masami Hiramatsu @ 2015-08-15 11:42 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, Adrian Hunter, Ingo Molnar,
	Paul Mackerras, Jiri Olsa, Namhyung Kim, Borislav Petkov,
	Hemant Kumar

Replace many fixed-length char array with strbuf to
stringify perf_probe_event and probe_trace_event etc. in
util/probe-event.c.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
Changes in v3:
 - Remove unneeded strbuf_release(). (Thanks Namhyung!)

Changes in v2:
 - Make perf_probe_event__sprintf() simpler.
---
 tools/perf/util/probe-event.c  |  238 ++++++++++++++--------------------------
 tools/perf/util/probe-event.h  |    3 -
 tools/perf/util/probe-finder.c |   14 +-
 3 files changed, 90 insertions(+), 165 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index fe4941a..be417ee 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1562,69 +1562,51 @@ out:
 }
 
 /* Compose only probe arg */
-int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
+char *synthesize_perf_probe_arg(struct perf_probe_arg *pa)
 {
 	struct perf_probe_arg_field *field = pa->field;
-	int ret;
-	char *tmp = buf;
+	struct strbuf buf;
+	char *ret;
 
+	strbuf_init(&buf, 64);
 	if (pa->name && pa->var)
-		ret = e_snprintf(tmp, len, "%s=%s", pa->name, pa->var);
+		strbuf_addf(&buf, "%s=%s", pa->name, pa->var);
 	else
-		ret = e_snprintf(tmp, len, "%s", pa->name ? pa->name : pa->var);
-	if (ret <= 0)
-		goto error;
-	tmp += ret;
-	len -= ret;
+		strbuf_addstr(&buf, pa->name ?: pa->var);
 
 	while (field) {
 		if (field->name[0] == '[')
-			ret = e_snprintf(tmp, len, "%s", field->name);
+			strbuf_addstr(&buf, field->name);
 		else
-			ret = e_snprintf(tmp, len, "%s%s",
-					 field->ref ? "->" : ".", field->name);
-		if (ret <= 0)
-			goto error;
-		tmp += ret;
-		len -= ret;
+			strbuf_addf(&buf, "%s%s", field->ref ? "->" : ".",
+				    field->name);
 		field = field->next;
 	}
 
-	if (pa->type) {
-		ret = e_snprintf(tmp, len, ":%s", pa->type);
-		if (ret <= 0)
-			goto error;
-		tmp += ret;
-		len -= ret;
-	}
+	if (pa->type)
+		strbuf_addf(&buf, ":%s", pa->type);
+
+	ret = strbuf_detach(&buf, NULL);
 
-	return tmp - buf;
-error:
-	pr_debug("Failed to synthesize perf probe argument: %d\n", ret);
 	return ret;
 }
 
 /* Compose only probe point (not argument) */
 static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
 {
-	char *buf, *tmp;
-	char offs[32] = "", line[32] = "", file[32] = "";
-	int ret, len;
-
-	buf = zalloc(MAX_CMDLEN);
-	if (buf == NULL) {
-		ret = -ENOMEM;
-		goto error;
-	}
-	if (pp->offset) {
-		ret = e_snprintf(offs, 32, "+%lu", pp->offset);
-		if (ret <= 0)
-			goto error;
-	}
-	if (pp->line) {
-		ret = e_snprintf(line, 32, ":%d", pp->line);
-		if (ret <= 0)
-			goto error;
+	struct strbuf buf;
+	char *tmp;
+	int len;
+
+	strbuf_init(&buf, 64);
+	if (pp->function) {
+		strbuf_addstr(&buf, pp->function);
+		if (pp->offset)
+			strbuf_addf(&buf, "+%lu", pp->offset);
+		else if (pp->line)
+			strbuf_addf(&buf, ":%d", pp->line);
+		else if (pp->retprobe)
+			strbuf_addstr(&buf, "%return");
 	}
 	if (pp->file) {
 		tmp = pp->file;
@@ -1633,25 +1615,12 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
 			tmp = strchr(pp->file + len - 30, '/');
 			tmp = tmp ? tmp + 1 : pp->file + len - 30;
 		}
-		ret = e_snprintf(file, 32, "@%s", tmp);
-		if (ret <= 0)
-			goto error;
+		strbuf_addf(&buf, "@%s", tmp);
+		if (!pp->function && pp->line)
+			strbuf_addf(&buf, ":%d", pp->line);
 	}
 
-	if (pp->function)
-		ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s%s", pp->function,
-				 offs, pp->retprobe ? "%return" : "", line,
-				 file);
-	else
-		ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", file, line);
-	if (ret <= 0)
-		goto error;
-
-	return buf;
-error:
-	pr_debug("Failed to synthesize perf probe point: %d\n", ret);
-	free(buf);
-	return NULL;
+	return strbuf_detach(&buf, NULL);
 }
 
 #if 0
@@ -1680,45 +1649,30 @@ char *synthesize_perf_probe_command(struct perf_probe_event *pev)
 #endif
 
 static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref,
-					     char **buf, size_t *buflen,
-					     int depth)
+					    struct strbuf *buf, int depth)
 {
-	int ret;
 	if (ref->next) {
 		depth = __synthesize_probe_trace_arg_ref(ref->next, buf,
-							 buflen, depth + 1);
+							 depth + 1);
 		if (depth < 0)
 			goto out;
 	}
-
-	ret = e_snprintf(*buf, *buflen, "%+ld(", ref->offset);
-	if (ret < 0)
-		depth = ret;
-	else {
-		*buf += ret;
-		*buflen -= ret;
-	}
+	strbuf_addf(buf, "%+ld(", ref->offset);
 out:
 	return depth;
-
 }
 
 static int synthesize_probe_trace_arg(struct probe_trace_arg *arg,
-				       char *buf, size_t buflen)
+				      struct strbuf *buf)
 {
 	struct probe_trace_arg_ref *ref = arg->ref;
-	int ret, depth = 0;
-	char *tmp = buf;
+	int depth = 0;
 
 	/* Argument name or separator */
 	if (arg->name)
-		ret = e_snprintf(buf, buflen, " %s=", arg->name);
+		strbuf_addf(buf, " %s=", arg->name);
 	else
-		ret = e_snprintf(buf, buflen, " ");
-	if (ret < 0)
-		return ret;
-	buf += ret;
-	buflen -= ret;
+		strbuf_addch(buf, ' ');
 
 	/* Special case: @XXX */
 	if (arg->value[0] == '@' && arg->ref)
@@ -1726,86 +1680,58 @@ static int synthesize_probe_trace_arg(struct probe_trace_arg *arg,
 
 	/* Dereferencing arguments */
 	if (ref) {
-		depth = __synthesize_probe_trace_arg_ref(ref, &buf,
-							  &buflen, 1);
+		depth = __synthesize_probe_trace_arg_ref(ref, buf, 1);
 		if (depth < 0)
 			return depth;
 	}
 
 	/* Print argument value */
 	if (arg->value[0] == '@' && arg->ref)
-		ret = e_snprintf(buf, buflen, "%s%+ld", arg->value,
-				 arg->ref->offset);
+		strbuf_addf(buf, "%s%+ld", arg->value, arg->ref->offset);
 	else
-		ret = e_snprintf(buf, buflen, "%s", arg->value);
-	if (ret < 0)
-		return ret;
-	buf += ret;
-	buflen -= ret;
+		strbuf_addstr(buf, arg->value);
 
 	/* Closing */
-	while (depth--) {
-		ret = e_snprintf(buf, buflen, ")");
-		if (ret < 0)
-			return ret;
-		buf += ret;
-		buflen -= ret;
-	}
+	while (depth--)
+		strbuf_addch(buf, ')');
 	/* Print argument type */
-	if (arg->type) {
-		ret = e_snprintf(buf, buflen, ":%s", arg->type);
-		if (ret <= 0)
-			return ret;
-		buf += ret;
-	}
+	if (arg->type)
+		strbuf_addf(buf, ":%s", arg->type);
 
-	return buf - tmp;
+	return 0;
 }
 
 char *synthesize_probe_trace_command(struct probe_trace_event *tev)
 {
 	struct probe_trace_point *tp = &tev->point;
-	char *buf;
-	int i, len, ret;
-
-	buf = zalloc(MAX_CMDLEN);
-	if (buf == NULL)
-		return NULL;
-
-	len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s ", tp->retprobe ? 'r' : 'p',
-			 tev->group, tev->event);
-	if (len <= 0)
-		goto error;
+	struct strbuf buf;
+	char *ret = NULL;
+	int i;
 
 	/* Uprobes must have tp->address and tp->module */
 	if (tev->uprobes && (!tp->address || !tp->module))
-		goto error;
+		return NULL;
+
+	strbuf_init(&buf, 32);
+	strbuf_addf(&buf, "%c:%s/%s ", tp->retprobe ? 'r' : 'p',
+		    tev->group, tev->event);
 
 	/* Use the tp->address for uprobes */
 	if (tev->uprobes)
-		ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s:0x%lx",
-				 tp->module, tp->address);
+		strbuf_addf(&buf, "%s:0x%lx", tp->module, tp->address);
 	else
-		ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s%s%s+%lu",
-				 tp->module ?: "", tp->module ? ":" : "",
-				 tp->symbol, tp->offset);
-
-	if (ret <= 0)
-		goto error;
-	len += ret;
+		strbuf_addf(&buf, "%s%s%s+%lu", tp->module ?: "",
+			    tp->module ? ":" : "", tp->symbol, tp->offset);
 
 	for (i = 0; i < tev->nargs; i++) {
-		ret = synthesize_probe_trace_arg(&tev->args[i], buf + len,
-						  MAX_CMDLEN - len);
-		if (ret <= 0)
+		if (synthesize_probe_trace_arg(&tev->args[i], &buf) < 0)
 			goto error;
-		len += ret;
 	}
 
-	return buf;
+	ret = strbuf_detach(&buf, NULL);
 error:
-	free(buf);
-	return NULL;
+	strbuf_release(&buf);
+	return ret;
 }
 
 static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
@@ -1883,7 +1809,7 @@ static int convert_to_perf_probe_point(struct probe_trace_point *tp,
 static int convert_to_perf_probe_event(struct probe_trace_event *tev,
 			       struct perf_probe_event *pev, bool is_kprobe)
 {
-	char buf[64] = "";
+	struct strbuf buf = STRBUF_INIT;
 	int i, ret;
 
 	/* Convert event/group name */
@@ -1906,9 +1832,9 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,
 		if (tev->args[i].name)
 			pev->args[i].name = strdup(tev->args[i].name);
 		else {
-			ret = synthesize_probe_trace_arg(&tev->args[i],
-							  buf, 64);
-			pev->args[i].name = strdup(buf);
+			strbuf_init(&buf, 32);
+			ret = synthesize_probe_trace_arg(&tev->args[i], &buf);
+			pev->args[i].name = strbuf_detach(&buf, NULL);
 		}
 		if (pev->args[i].name == NULL && ret >= 0)
 			ret = -ENOMEM;
@@ -2086,37 +2012,37 @@ static int perf_probe_event__sprintf(const char *group, const char *event,
 				     const char *module,
 				     struct strbuf *result)
 {
-	int i, ret;
-	char buf[128];
-	char *place;
+	int i;
+	char *buf;
 
-	/* Synthesize only event probe point */
-	place = synthesize_perf_probe_point(&pev->point);
-	if (!place)
-		return -EINVAL;
+	if (asprintf(&buf, "%s:%s", group, event) < 0)
+		return -errno;
+	strbuf_addf(result, "  %-20s (on ", buf);
+	free(buf);
 
-	ret = e_snprintf(buf, 128, "%s:%s", group, event);
-	if (ret < 0)
-		goto out;
+	/* Synthesize only event probe point */
+	buf = synthesize_perf_probe_point(&pev->point);
+	if (!buf)
+		return -ENOMEM;
+	strbuf_addstr(result, buf);
+	free(buf);
 
-	strbuf_addf(result, "  %-20s (on %s", buf, place);
 	if (module)
 		strbuf_addf(result, " in %s", module);
 
 	if (pev->nargs > 0) {
 		strbuf_addstr(result, " with");
 		for (i = 0; i < pev->nargs; i++) {
-			ret = synthesize_perf_probe_arg(&pev->args[i],
-							buf, 128);
-			if (ret < 0)
-				goto out;
+			buf = synthesize_perf_probe_arg(&pev->args[i]);
+			if (!buf)
+				return -ENOMEM;
 			strbuf_addf(result, " %s", buf);
+			free(buf);
 		}
 	}
 	strbuf_addch(result, ')');
-out:
-	free(place);
-	return ret;
+
+	return 0;
 }
 
 /* Show an event */
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 83ee95e..50216ff 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -117,8 +117,7 @@ extern int parse_probe_trace_command(const char *cmd,
 /* Events to command string */
 extern char *synthesize_perf_probe_command(struct perf_probe_event *pev);
 extern char *synthesize_probe_trace_command(struct probe_trace_event *tev);
-extern int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf,
-				     size_t len);
+extern char *synthesize_perf_probe_arg(struct perf_probe_arg *pa);
 
 /* Check the perf_probe_event needs debuginfo */
 extern bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 7b80f8c..0c5168d 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -550,7 +550,7 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
 static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
 {
 	Dwarf_Die vr_die;
-	char buf[32], *ptr;
+	char *buf, *ptr;
 	int ret = 0;
 
 	if (!is_c_varname(pf->pvar->var)) {
@@ -575,13 +575,13 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
 	if (pf->pvar->name)
 		pf->tvar->name = strdup(pf->pvar->name);
 	else {
-		ret = synthesize_perf_probe_arg(pf->pvar, buf, 32);
-		if (ret < 0)
-			return ret;
+		buf = synthesize_perf_probe_arg(pf->pvar);
+		if (!buf)
+			return -ENOMEM;
 		ptr = strchr(buf, ':');	/* Change type separator to _ */
 		if (ptr)
 			*ptr = '_';
-		pf->tvar->name = strdup(buf);
+		pf->tvar->name = buf;
 	}
 	if (pf->tvar->name == NULL)
 		return -ENOMEM;
@@ -1318,8 +1318,8 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
 			if (ret2 == 0) {
 				strlist__add(vl->vars,
 					strbuf_detach(&buf, NULL));
-			}
-			strbuf_release(&buf);
+			} else
+				strbuf_release(&buf);
 		}
 	}
 


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

* [RFC PATCH perf/core v3 02/17] perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid
  2015-08-15 11:42 [RFC PATCH perf/core v3 00/17] perf-probe --cache and SDT support Masami Hiramatsu
  2015-08-15 11:42 ` [RFC PATCH perf/core v3 01/17] perf probe: Use strbuf for making strings in probe-event.c Masami Hiramatsu
@ 2015-08-15 11:42 ` Masami Hiramatsu
  2015-08-28 16:07   ` Arnaldo Carvalho de Melo
  2015-08-15 11:42 ` [RFC PATCH perf/core v3 03/17] perf buildid: Introduce sysfs/filename__sprintf_build_id Masami Hiramatsu
                   ` (15 subsequent siblings)
  17 siblings, 1 reply; 25+ messages in thread
From: Masami Hiramatsu @ 2015-08-15 11:42 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, Adrian Hunter, Ingo Molnar,
	Paul Mackerras, Jiri Olsa, Namhyung Kim, Borislav Petkov,
	Hemant Kumar

Use path/to/bin/buildid/elf instead of path/to/bin/buildid
to store corresponding elf binary.
This also stores vdso in buildid/vdso, kallsyms in buildid/kallsyms.
Note that the build-id based symlink changes to point to the
path/to/bin/buildid, not path/to/bin/buildid/elf.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 Changes in v3:
  - Update for the latest perf/core
  - Use sbuild_id for stringified build_id buffer.
---
 tools/perf/util/build-id.c |   65 +++++++++++++++++++++++++++++++-------------
 tools/perf/util/dso.h      |    5 +++
 tools/perf/util/symbol.c   |    2 +
 3 files changed, 52 insertions(+), 20 deletions(-)

diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 4a2c2f0..f65d7c2 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -112,7 +112,8 @@ static int asnprintf(char **strp, size_t size, const char *fmt, ...)
 	return ret;
 }
 
-static char *build_id__filename(const char *sbuild_id, char *bf, size_t size)
+static char *build_id_cache__linkname(const char *sbuild_id, char *bf,
+				      size_t size)
 {
 	char *tmp = bf;
 	int ret = asnprintf(&bf, size, "%s/.build-id/%.2s/%s", buildid_dir,
@@ -122,15 +123,35 @@ static char *build_id__filename(const char *sbuild_id, char *bf, size_t size)
 	return bf;
 }
 
+static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso)
+{
+	return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf");
+}
+
 char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
 {
-	char build_id_hex[SBUILD_ID_SIZE];
+	bool is_kallsyms = dso__is_kallsyms((struct dso *)dso);
+	bool is_vdso = dso__is_vdso((struct dso *)dso);
+	char sbuild_id[SBUILD_ID_SIZE];
+	char *linkname;
+	bool alloc = (bf == NULL);
+	int ret;
 
 	if (!dso->has_build_id)
 		return NULL;
 
-	build_id__sprintf(dso->build_id, sizeof(dso->build_id), build_id_hex);
-	return build_id__filename(build_id_hex, bf, size);
+	build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
+	linkname = build_id_cache__linkname(sbuild_id, NULL, 0);
+	if (!linkname)
+		return NULL;
+
+	ret = asnprintf(&bf, size, "%s/%s", linkname,
+			 build_id_cache__basename(is_kallsyms, is_vdso));
+	if (ret < 0 || (!alloc && size < (unsigned int)ret))
+		bf = NULL;
+	free(linkname);
+
+	return bf;
 }
 
 #define dsos__for_each_with_build_id(pos, head)	\
@@ -261,7 +282,8 @@ void disable_buildid_cache(void)
 }
 
 static char *build_id_cache__dirname_from_path(const char *name,
-					       bool is_kallsyms, bool is_vdso)
+					       bool is_kallsyms, bool is_vdso,
+					       const char *sbuild_id)
 {
 	char *realname = (char *)name, *filename;
 	bool slash = is_kallsyms || is_vdso;
@@ -272,8 +294,9 @@ static char *build_id_cache__dirname_from_path(const char *name,
 			return NULL;
 	}
 
-	if (asprintf(&filename, "%s%s%s", buildid_dir, slash ? "/" : "",
-		     is_vdso ? DSO__NAME_VDSO : realname) < 0)
+	if (asprintf(&filename, "%s%s%s%s%s", buildid_dir, slash ? "/" : "",
+		     is_vdso ? DSO__NAME_VDSO : realname,
+		     sbuild_id ? "/" : "", sbuild_id ?: "") < 0)
 		filename = NULL;
 
 	if (!slash)
@@ -292,7 +315,8 @@ int build_id_cache__list_build_ids(const char *pathname,
 	int ret = 0;
 
 	list = strlist__new(NULL, NULL);
-	dir_name = build_id_cache__dirname_from_path(pathname, false, false);
+	dir_name = build_id_cache__dirname_from_path(pathname, false, false,
+						     NULL);
 	if (!list || !dir_name) {
 		ret = -ENOMEM;
 		goto out;
@@ -327,7 +351,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
 {
 	const size_t size = PATH_MAX;
 	char *realname = NULL, *filename = NULL, *dir_name = NULL,
-	     *linkname = zalloc(size), *targetname, *tmp;
+	     *linkname = zalloc(size), *tmp;
 	int err = -1;
 
 	if (!is_kallsyms) {
@@ -336,14 +360,17 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
 			goto out_free;
 	}
 
-	dir_name = build_id_cache__dirname_from_path(name, is_kallsyms, is_vdso);
+	dir_name = build_id_cache__dirname_from_path(name, is_kallsyms,
+						     is_vdso, sbuild_id);
 	if (!dir_name)
 		goto out_free;
 
 	if (mkdir_p(dir_name, 0755))
 		goto out_free;
 
-	if (asprintf(&filename, "%s/%s", dir_name, sbuild_id) < 0) {
+	/* Save the allocated buildid dirname */
+	if (asprintf(&filename, "%s/%s", dir_name,
+		     build_id_cache__basename(is_kallsyms, is_vdso)) < 0) {
 		filename = NULL;
 		goto out_free;
 	}
@@ -357,7 +384,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
 			goto out_free;
 	}
 
-	if (!build_id__filename(sbuild_id, linkname, size))
+	if (!build_id_cache__linkname(sbuild_id, linkname, size))
 		goto out_free;
 	tmp = strrchr(linkname, '/');
 	*tmp = '\0';
@@ -366,10 +393,10 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
 		goto out_free;
 
 	*tmp = '/';
-	targetname = filename + strlen(buildid_dir) - 5;
-	memcpy(targetname, "../..", 5);
+	tmp = dir_name + strlen(buildid_dir) - 5;
+	memcpy(tmp, "../..", 5);
 
-	if (symlink(targetname, linkname) == 0)
+	if (symlink(tmp, linkname) == 0)
 		err = 0;
 out_free:
 	if (!is_kallsyms)
@@ -394,7 +421,7 @@ static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
 bool build_id_cache__cached(const char *sbuild_id)
 {
 	bool ret = false;
-	char *filename = build_id__filename(sbuild_id, NULL, 0);
+	char *filename = build_id_cache__linkname(sbuild_id, NULL, 0);
 
 	if (filename && !access(filename, F_OK))
 		ret = true;
@@ -413,7 +440,7 @@ int build_id_cache__remove_s(const char *sbuild_id)
 	if (filename == NULL || linkname == NULL)
 		goto out_free;
 
-	if (!build_id__filename(sbuild_id, linkname, size))
+	if (!build_id_cache__linkname(sbuild_id, linkname, size))
 		goto out_free;
 
 	if (access(linkname, F_OK))
@@ -431,7 +458,7 @@ int build_id_cache__remove_s(const char *sbuild_id)
 	tmp = strrchr(linkname, '/') + 1;
 	snprintf(tmp, size - (tmp - linkname), "%s", filename);
 
-	if (unlink(linkname))
+	if (rm_rf(linkname))
 		goto out_free;
 
 	err = 0;
@@ -443,7 +470,7 @@ out_free:
 
 static int dso__cache_build_id(struct dso *dso, struct machine *machine)
 {
-	bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
+	bool is_kallsyms = dso__is_kallsyms(dso);
 	bool is_vdso = dso__is_vdso(dso);
 	const char *name = dso->long_name;
 	char nm[PATH_MAX];
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index c73276d..07f37c2 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -345,6 +345,11 @@ static inline bool dso__is_kcore(struct dso *dso)
 	       dso->binary_type == DSO_BINARY_TYPE__GUEST_KCORE;
 }
 
+static inline bool dso__is_kallsyms(struct dso *dso)
+{
+	return dso->kernel && dso->long_name[0] != '/';
+}
+
 void dso__free_a2l(struct dso *dso);
 
 enum dso_type dso__type(struct dso *dso, struct machine *machine);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 725640f..9ed826c 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1707,7 +1707,7 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)
 	if (!find_matching_kcore(map, path, sizeof(path)))
 		return strdup(path);
 
-	scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s",
+	scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s/kallsyms",
 		  buildid_dir, sbuild_id);
 
 	if (access(path, F_OK)) {


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

* [RFC PATCH perf/core v3 03/17] perf buildid: Introduce sysfs/filename__sprintf_build_id
  2015-08-15 11:42 [RFC PATCH perf/core v3 00/17] perf-probe --cache and SDT support Masami Hiramatsu
  2015-08-15 11:42 ` [RFC PATCH perf/core v3 01/17] perf probe: Use strbuf for making strings in probe-event.c Masami Hiramatsu
  2015-08-15 11:42 ` [RFC PATCH perf/core v3 02/17] perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid Masami Hiramatsu
@ 2015-08-15 11:42 ` Masami Hiramatsu
  2015-08-28 16:14   ` Arnaldo Carvalho de Melo
  2015-08-31  8:32   ` [tip:perf/core] perf buildid: Introduce sysfs/ filename__sprintf_build_id tip-bot for Masami Hiramatsu
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 04/17] perf: Add lsdir to read a directory Masami Hiramatsu
                   ` (14 subsequent siblings)
  17 siblings, 2 replies; 25+ messages in thread
From: Masami Hiramatsu @ 2015-08-15 11:42 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, Adrian Hunter, Ingo Molnar,
	Paul Mackerras, Jiri Olsa, Namhyung Kim, Borislav Petkov,
	Hemant Kumar

Introduce sysfs/filename__sprintf_build_id for consolidating
similar code.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 tools/perf/builtin-buildid-cache.c |   14 ++------------
 tools/perf/builtin-buildid-list.c  |   24 ++++++++++--------------
 tools/perf/util/build-id.c         |   32 ++++++++++++++++++++++++++++++++
 tools/perf/util/build-id.h         |    3 +++
 4 files changed, 47 insertions(+), 26 deletions(-)

diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index 65b4835..7b8450c 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -25,8 +25,6 @@
 static int build_id_cache__kcore_buildid(const char *proc_dir, char *sbuildid)
 {
 	char root_dir[PATH_MAX];
-	char notes[PATH_MAX];
-	u8 build_id[BUILD_ID_SIZE];
 	char *p;
 
 	strlcpy(root_dir, proc_dir, sizeof(root_dir));
@@ -35,15 +33,7 @@ static int build_id_cache__kcore_buildid(const char *proc_dir, char *sbuildid)
 	if (!p)
 		return -1;
 	*p = '\0';
-
-	scnprintf(notes, sizeof(notes), "%s/sys/kernel/notes", root_dir);
-
-	if (sysfs__read_build_id(notes, build_id, sizeof(build_id)))
-		return -1;
-
-	build_id__sprintf(build_id, sizeof(build_id), sbuildid);
-
-	return 0;
+	return sysfs__sprintf_build_id(root_dir, sbuildid);
 }
 
 static int build_id_cache__kcore_dir(char *dir, size_t sz)
@@ -138,7 +128,7 @@ static int build_id_cache__add_kcore(const char *filename, bool force)
 		return -1;
 	*p = '\0';
 
-	if (build_id_cache__kcore_buildid(from_dir, sbuildid))
+	if (build_id_cache__kcore_buildid(from_dir, sbuildid) < 0)
 		return -1;
 
 	scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s",
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index b5ca988..918b4de 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -19,29 +19,25 @@
 
 static int sysfs__fprintf_build_id(FILE *fp)
 {
-	u8 kallsyms_build_id[BUILD_ID_SIZE];
 	char sbuild_id[SBUILD_ID_SIZE];
+	int ret;
 
-	if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
-				 sizeof(kallsyms_build_id)) != 0)
-		return -1;
+	ret = sysfs__sprintf_build_id("/", sbuild_id);
+	if (ret != sizeof(sbuild_id))
+		return ret < 0 ? ret : -EINVAL;
 
-	build_id__sprintf(kallsyms_build_id, sizeof(kallsyms_build_id),
-			  sbuild_id);
-	fprintf(fp, "%s\n", sbuild_id);
-	return 0;
+	return fprintf(fp, "%s\n", sbuild_id);
 }
 
 static int filename__fprintf_build_id(const char *name, FILE *fp)
 {
-	u8 build_id[BUILD_ID_SIZE];
 	char sbuild_id[SBUILD_ID_SIZE];
+	int ret;
 
-	if (filename__read_build_id(name, build_id,
-				    sizeof(build_id)) != sizeof(build_id))
-		return 0;
+	ret = filename__sprintf_build_id(name, sbuild_id);
+	if (ret != sizeof(sbuild_id))
+		return ret < 0 ? ret : -EINVAL;
 
-	build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
 	return fprintf(fp, "%s\n", sbuild_id);
 }
 
@@ -63,7 +59,7 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
 	/*
 	 * See if this is an ELF file first:
 	 */
-	if (filename__fprintf_build_id(input_name, stdout))
+	if (filename__fprintf_build_id(input_name, stdout) > 0)
 		goto out;
 
 	session = perf_session__new(&file, false, &build_id__mark_dso_hit_ops);
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index f65d7c2..b639cad 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -93,6 +93,38 @@ int build_id__sprintf(const u8 *build_id, int len, char *bf)
 	return raw - build_id;
 }
 
+int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id)
+{
+	char notes[PATH_MAX];
+	u8 build_id[BUILD_ID_SIZE];
+	int ret;
+
+	if (!root_dir)
+		root_dir = "";
+
+	scnprintf(notes, sizeof(notes), "%s/sys/kernel/notes", root_dir);
+
+	ret = sysfs__read_build_id(notes, build_id, sizeof(build_id));
+	if (ret < 0)
+		return ret;
+
+	return build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
+}
+
+int filename__sprintf_build_id(const char *pathname, char *sbuild_id)
+{
+	u8 build_id[BUILD_ID_SIZE];
+	int ret;
+
+	ret = filename__read_build_id(pathname, build_id, sizeof(build_id));
+	if (ret < 0)
+		return ret;
+	else if (ret != sizeof(build_id))
+		return -EINVAL;
+
+	return build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
+}
+
 /* asnprintf consolidates asprintf and snprintf */
 static int asnprintf(char **strp, size_t size, const char *fmt, ...)
 {
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index ce2f493..27a14a8 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -12,6 +12,9 @@ extern struct perf_tool build_id__mark_dso_hit_ops;
 struct dso;
 
 int build_id__sprintf(const u8 *build_id, int len, char *bf);
+int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id);
+int filename__sprintf_build_id(const char *pathname, char *sbuild_id);
+
 char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size);
 
 int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,


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

* [RFC PATCH perf/core v3 04/17] perf: Add lsdir to read a directory
  2015-08-15 11:42 [RFC PATCH perf/core v3 00/17] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (2 preceding siblings ...)
  2015-08-15 11:42 ` [RFC PATCH perf/core v3 03/17] perf buildid: Introduce sysfs/filename__sprintf_build_id Masami Hiramatsu
@ 2015-08-15 11:43 ` Masami Hiramatsu
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 05/17] perf-buildid-cache: Use lsdir for looking up buildid caches Masami Hiramatsu
                   ` (13 subsequent siblings)
  17 siblings, 0 replies; 25+ messages in thread
From: Masami Hiramatsu @ 2015-08-15 11:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, Adrian Hunter, Ingo Molnar,
	Paul Mackerras, Jiri Olsa, Namhyung Kim, Borislav Petkov,
	Hemant Kumar

As a utility function, add lsdir() which reads given
directory and store entry name into a strlist.
lsdir accepts a filter function so that user can
filter out unneeded entries.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 tools/perf/util/util.c |   34 ++++++++++++++++++++++++++++++++++
 tools/perf/util/util.h |    4 ++++
 2 files changed, 38 insertions(+)

diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index f7adf12..7e74bbe 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -115,6 +115,40 @@ int rm_rf(char *path)
 	return rmdir(path);
 }
 
+/* A filter which removes dot files */
+bool lsdir_no_dot_filter(const char *dirname __maybe_unused, struct dirent *d)
+{
+	return d->d_name[0] != '.';
+}
+
+/* lsdir reads a directory and store it in strlist */
+struct strlist *lsdir(const char *dirname,
+		      bool (*filter)(const char *, struct dirent *))
+{
+	struct strlist *list = NULL;
+	DIR *dir;
+	struct dirent *d;
+
+	dir = opendir(dirname);
+	if (!dir)
+		return NULL;
+
+	list = strlist__new(NULL, NULL);
+	if (!list) {
+		errno = -ENOMEM;
+		goto out;
+	}
+
+	while ((d = readdir(dir)) != NULL) {
+		if (!filter || filter(dirname, d))
+			strlist__add(list, d->d_name);
+	}
+
+out:
+	closedir(dir);
+	return list;
+}
+
 static int slow_copyfile(const char *from, const char *to)
 {
 	int err = -1;
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 88a8915..0236898 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -79,6 +79,7 @@
 #include <termios.h>
 #include <linux/bitops.h>
 #include <termios.h>
+#include "strlist.h"
 
 extern const char *graph_line;
 extern const char *graph_dotted_line;
@@ -250,6 +251,9 @@ static inline int sane_case(int x, int high)
 
 int mkdir_p(char *path, mode_t mode);
 int rm_rf(char *path);
+struct strlist *lsdir(const char *dirname,
+		      bool (*filter)(const char *, struct dirent *));
+bool lsdir_no_dot_filter(const char *dirname __maybe_unused, struct dirent *d);
 int copyfile(const char *from, const char *to);
 int copyfile_mode(const char *from, const char *to, mode_t mode);
 int copyfile_offset(int fromfd, loff_t from_ofs, int tofd, loff_t to_ofs, u64 size);


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

* [RFC PATCH perf/core v3 05/17] perf-buildid-cache: Use lsdir for looking up buildid caches
  2015-08-15 11:42 [RFC PATCH perf/core v3 00/17] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (3 preceding siblings ...)
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 04/17] perf: Add lsdir to read a directory Masami Hiramatsu
@ 2015-08-15 11:43 ` Masami Hiramatsu
  2015-08-28 16:17   ` Arnaldo Carvalho de Melo
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 06/17] perf probe: Add --cache option to cache the probe definitions Masami Hiramatsu
                   ` (12 subsequent siblings)
  17 siblings, 1 reply; 25+ messages in thread
From: Masami Hiramatsu @ 2015-08-15 11:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, Adrian Hunter, Ingo Molnar,
	Paul Mackerras, Jiri Olsa, Namhyung Kim, Borislav Petkov,
	Hemant Kumar

Use new lsdir() for looking up buildid caches. This changes
logic a bit to ignore all dot files, since the build-id
cache must not start with dot.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 tools/perf/util/build-id.c |   30 +++++-------------------------
 1 file changed, 5 insertions(+), 25 deletions(-)

diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index b639cad..e9ef98e 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -342,38 +342,18 @@ int build_id_cache__list_build_ids(const char *pathname,
 {
 	struct strlist *list;
 	char *dir_name;
-	DIR *dir;
-	struct dirent *d;
 	int ret = 0;
 
-	list = strlist__new(NULL, NULL);
 	dir_name = build_id_cache__dirname_from_path(pathname, false, false,
 						     NULL);
-	if (!list || !dir_name) {
-		ret = -ENOMEM;
-		goto out;
-	}
+	if (!dir_name)
+		return -ENOMEM;
 
-	/* List up all dirents */
-	dir = opendir(dir_name);
-	if (!dir) {
+	list = lsdir(dir_name, lsdir_no_dot_filter);
+	if (!list)
 		ret = -errno;
-		goto out;
-	}
-
-	while ((d = readdir(dir)) != NULL) {
-		if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
-			continue;
-		strlist__add(list, d->d_name);
-	}
-	closedir(dir);
-
-out:
+	*result = list;
 	free(dir_name);
-	if (ret)
-		strlist__delete(list);
-	else
-		*result = list;
 
 	return ret;
 }


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

* [RFC PATCH perf/core v3 06/17] perf probe: Add --cache option to cache the probe definitions
  2015-08-15 11:42 [RFC PATCH perf/core v3 00/17] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (4 preceding siblings ...)
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 05/17] perf-buildid-cache: Use lsdir for looking up buildid caches Masami Hiramatsu
@ 2015-08-15 11:43 ` Masami Hiramatsu
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 07/17] perf probe: Use cache entry if possible Masami Hiramatsu
                   ` (11 subsequent siblings)
  17 siblings, 0 replies; 25+ messages in thread
From: Masami Hiramatsu @ 2015-08-15 11:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, Adrian Hunter, Ingo Molnar,
	Paul Mackerras, Jiri Olsa, Namhyung Kim, Borislav Petkov,
	Hemant Kumar

Add --cache option to cache the probe definitions. This
just saves the result of the dwarf analysis to probe cache.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>

---
Changes in v3:
  - Use pr_debug instead of pr_warning for cache file.
Changes in v2:
  - Update documentations/perf-probe.txt.
---
 tools/perf/Documentation/perf-probe.txt |    4 
 tools/perf/builtin-probe.c              |    1 
 tools/perf/util/build-id.c              |   13 +
 tools/perf/util/build-id.h              |    2 
 tools/perf/util/probe-event.c           |  136 ++++++++++++--
 tools/perf/util/probe-event.h           |    5 +
 tools/perf/util/probe-file.c            |  299 +++++++++++++++++++++++++++++++
 tools/perf/util/probe-file.h            |   20 ++
 8 files changed, 448 insertions(+), 32 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 3a8a9ba..947db6f 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -109,6 +109,10 @@ OPTIONS
 	Dry run. With this option, --add and --del doesn't execute actual
 	adding and removal operations.
 
+--cache::
+	Cache the probes (with --add option). Any events which successfully added
+	are also stored in the cache file.
+
 --max-probes=NUM::
 	Set the maximum number of probe points for an event. Default is 128.
 
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index b81cec3..5ac8a79 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -396,6 +396,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
 		     opt_set_filter),
 	OPT_CALLBACK('x', "exec", NULL, "executable|path",
 			"target executable name or path", opt_set_target),
+	OPT_BOOLEAN(0, "cache", &probe_conf.cache, "Manipulate probe cache"),
 	OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
 		    "Enable symbol demangling"),
 	OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index e9ef98e..e7fe606 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -313,9 +313,8 @@ void disable_buildid_cache(void)
 	no_buildid_cache = true;
 }
 
-static char *build_id_cache__dirname_from_path(const char *name,
-					       bool is_kallsyms, bool is_vdso,
-					       const char *sbuild_id)
+char *build_id_cache__dirname_from_path(const char *sbuild_id, const char *name,
+					bool is_kallsyms, bool is_vdso)
 {
 	char *realname = (char *)name, *filename;
 	bool slash = is_kallsyms || is_vdso;
@@ -344,8 +343,8 @@ int build_id_cache__list_build_ids(const char *pathname,
 	char *dir_name;
 	int ret = 0;
 
-	dir_name = build_id_cache__dirname_from_path(pathname, false, false,
-						     NULL);
+	dir_name = build_id_cache__dirname_from_path(NULL, pathname,
+						     false, false);
 	if (!dir_name)
 		return -ENOMEM;
 
@@ -372,8 +371,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
 			goto out_free;
 	}
 
-	dir_name = build_id_cache__dirname_from_path(name, is_kallsyms,
-						     is_vdso, sbuild_id);
+	dir_name = build_id_cache__dirname_from_path(sbuild_id, name,
+						     is_kallsyms, is_vdso);
 	if (!dir_name)
 		goto out_free;
 
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index 27a14a8..a1f428d 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -27,6 +27,8 @@ bool perf_session__read_build_ids(struct perf_session *session, bool with_hits);
 int perf_session__write_buildid_table(struct perf_session *session, int fd);
 int perf_session__cache_build_ids(struct perf_session *session);
 
+char *build_id_cache__dirname_from_path(const char *sbuild_id, const char *name,
+					bool is_kallsyms, bool is_vdso);
 int build_id_cache__list_build_ids(const char *pathname,
 				   struct strlist **result);
 bool build_id_cache__cached(const char *sbuild_id);
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index be417ee..914b414 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -68,7 +68,6 @@ int e_snprintf(char *str, size_t size, const char *format, ...)
 	return ret;
 }
 
-static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
 static struct machine *host_machine;
 
 /* Initialize symbol maps and path of vmlinux/modules */
@@ -1592,7 +1591,7 @@ char *synthesize_perf_probe_arg(struct perf_probe_arg *pa)
 }
 
 /* Compose only probe point (not argument) */
-static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
+char *synthesize_perf_probe_point(struct perf_probe_point *pp)
 {
 	struct strbuf buf;
 	char *tmp;
@@ -1623,30 +1622,36 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
 	return strbuf_detach(&buf, NULL);
 }
 
-#if 0
 char *synthesize_perf_probe_command(struct perf_probe_event *pev)
 {
-	char *buf;
-	int i, len, ret;
+	struct strbuf buf;
+	char *tmp;
+	int i;
 
-	buf = synthesize_perf_probe_point(&pev->point);
-	if (!buf)
-		return NULL;
+	strbuf_init(&buf, 64);
+	if (pev->event)
+		strbuf_addf(&buf, "%s:%s=", pev->group ?: PERFPROBE_GROUP,
+			    pev->event);
+
+	tmp = synthesize_perf_probe_point(&pev->point);
+	if (!tmp)
+		goto out;
+	strbuf_addstr(&buf, tmp);
+	free(tmp);
 
-	len = strlen(buf);
 	for (i = 0; i < pev->nargs; i++) {
-		ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
-				 pev->args[i].name);
-		if (ret <= 0) {
-			free(buf);
-			return NULL;
-		}
-		len += ret;
+		tmp = synthesize_perf_probe_arg(pev->args + i);
+		if (!tmp)
+			goto out;
+		strbuf_addf(&buf, " %s", tmp);
+		free(tmp);
 	}
 
-	return buf;
+	tmp = strbuf_detach(&buf, NULL);
+out:
+	strbuf_release(&buf);
+	return tmp;
 }
-#endif
 
 static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref,
 					    struct strbuf *buf, int depth)
@@ -1727,7 +1732,6 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
 		if (synthesize_probe_trace_arg(&tev->args[i], &buf) < 0)
 			goto error;
 	}
-
 	ret = strbuf_detach(&buf, NULL);
 error:
 	strbuf_release(&buf);
@@ -1872,6 +1876,79 @@ void clear_perf_probe_event(struct perf_probe_event *pev)
 	memset(pev, 0, sizeof(*pev));
 }
 
+#define strdup_or_goto(str, label)	\
+({ char *__p = NULL; if (str && !(__p = strdup(str))) goto label; __p; })
+
+static int perf_probe_point__copy(struct perf_probe_point *dst,
+				  struct perf_probe_point *src)
+{
+	dst->file = strdup_or_goto(src->file, out_err);
+	dst->function = strdup_or_goto(src->function, out_err);
+	dst->lazy_line = strdup_or_goto(src->lazy_line, out_err);
+	dst->line = src->line;
+	dst->retprobe = src->retprobe;
+	dst->offset = src->offset;
+	return 0;
+
+out_err:
+	clear_perf_probe_point(dst);
+	return -ENOMEM;
+}
+
+static int perf_probe_arg__copy(struct perf_probe_arg *dst,
+				struct perf_probe_arg *src)
+{
+	struct perf_probe_arg_field *field, **ppfield;
+
+	dst->name = strdup_or_goto(src->name, out_err);
+	dst->var = strdup_or_goto(src->var, out_err);
+	dst->type = strdup_or_goto(src->type, out_err);
+
+	field = src->field;
+	ppfield = &(dst->field);
+	while (field) {
+		*ppfield = zalloc(sizeof(*field));
+		if (!*ppfield)
+			goto out_err;
+		(*ppfield)->name = strdup_or_goto(field->name, out_err);
+		(*ppfield)->index = field->index;
+		(*ppfield)->ref = field->ref;
+		field = field->next;
+		ppfield = &((*ppfield)->next);
+	}
+	return 0;
+out_err:
+	return -ENOMEM;
+}
+
+int perf_probe_event__copy(struct perf_probe_event *dst,
+			   struct perf_probe_event *src)
+{
+	int i;
+
+	dst->event = strdup_or_goto(src->event, out_err);
+	dst->group = strdup_or_goto(src->group, out_err);
+	dst->target = strdup_or_goto(src->target, out_err);
+	dst->uprobes = src->uprobes;
+
+	if (perf_probe_point__copy(&dst->point, &src->point) < 0)
+		goto out_err;
+
+	dst->args = zalloc(sizeof(struct perf_probe_arg) * src->nargs);
+	if (!dst->args)
+		goto out_err;
+	dst->nargs = src->nargs;
+
+	for (i = 0; i < src->nargs; i++)
+		if (perf_probe_arg__copy(&dst->args[i], &src->args[i]) < 0)
+			goto out_err;
+	return 0;
+
+out_err:
+	clear_perf_probe_event(dst);
+	return -ENOMEM;
+}
+
 void clear_probe_trace_event(struct probe_trace_event *tev)
 {
 	struct probe_trace_arg_ref *ref, *next;
@@ -2258,15 +2335,17 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev,
 }
 
 static int __add_probe_trace_events(struct perf_probe_event *pev,
-				     struct probe_trace_event *tevs,
-				     int ntevs, bool allow_suffix)
+				    struct probe_trace_event *tevs,
+				    int ntevs, bool allow_suffix)
 {
 	int i, fd, ret;
 	struct probe_trace_event *tev = NULL;
 	const char *event = NULL, *group = NULL;
+	struct probe_cache *cache = NULL;
 	struct strlist *namelist;
+	int flag = PF_FL_RW | (pev->uprobes ? PF_FL_UPROBE : 0);
 
-	fd = probe_file__open(PF_FL_RW | (pev->uprobes ? PF_FL_UPROBE : 0));
+	fd = probe_file__open(flag);
 	if (fd < 0)
 		return fd;
 
@@ -2316,6 +2395,16 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
 
 	/* Note that it is possible to skip all events because of blacklist */
 	if (ret >= 0 && event) {
+		if (probe_conf.cache) {
+			cache = probe_cache__new(pev->target);
+			if (!cache)
+				pr_info("Warning: Failed to add cache\n");
+			else {
+				probe_cache__add_entry(cache, pev, tevs, ntevs);
+				probe_cache__commit(cache);
+				probe_cache__delete(cache);
+			}
+		}
 		/* Show how to use the event. */
 		pr_info("\nYou can now use it in all perf tools, such as:\n\n");
 		pr_info("\tperf record -e %s:%s -aR sleep 1\n\n", group, event);
@@ -2348,9 +2437,6 @@ static int find_probe_functions(struct map *map, char *name,
 	return found;
 }
 
-#define strdup_or_goto(str, label)	\
-	({ char *__p = strdup(str); if (!__p) goto label; __p; })
-
 void __weak arch__fix_tev_from_maps(struct perf_probe_event *pev __maybe_unused,
 				struct probe_trace_event *tev __maybe_unused,
 				struct map *map __maybe_unused) { }
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 50216ff..fdea725 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -12,6 +12,7 @@ struct probe_conf {
 	bool	show_location_range;
 	bool	force_add;
 	bool	no_inlines;
+	bool	cache;
 	int	max_probes;
 };
 extern struct probe_conf probe_conf;
@@ -118,6 +119,10 @@ extern int parse_probe_trace_command(const char *cmd,
 extern char *synthesize_perf_probe_command(struct perf_probe_event *pev);
 extern char *synthesize_probe_trace_command(struct probe_trace_event *tev);
 extern char *synthesize_perf_probe_arg(struct perf_probe_arg *pa);
+char *synthesize_perf_probe_point(struct perf_probe_point *pp);
+
+int perf_probe_event__copy(struct perf_probe_event *dst,
+			   struct perf_probe_event *src);
 
 /* Check the perf_probe_event needs debuginfo */
 extern bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index bbb2437..71915d5 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -14,6 +14,7 @@
  * GNU General Public License for more details.
  *
  */
+#include <sys/uio.h>
 #include "util.h"
 #include "event.h"
 #include "strlist.h"
@@ -299,3 +300,301 @@ int probe_file__del_events(int fd, struct strfilter *filter)
 
 	return ret;
 }
+
+static void probe_cache_entry__delete(struct probe_cache_entry *node)
+{
+	if (!list_empty(&node->list))
+		list_del(&node->list);
+	if (node->tevlist)
+		strlist__delete(node->tevlist);
+	clear_perf_probe_event(&node->pev);
+	free(node->spev);
+	free(node);
+}
+
+static struct probe_cache_entry *
+probe_cache_entry__new(struct perf_probe_event *pev)
+{
+	struct probe_cache_entry *ret = zalloc(sizeof(*ret));
+
+	if (ret) {
+		INIT_LIST_HEAD(&ret->list);
+		ret->tevlist = strlist__new(NULL, NULL);
+		if (!ret->tevlist)
+			zfree(&ret);
+		if (ret && pev) {
+			ret->spev = synthesize_perf_probe_command(pev);
+			if (!ret->spev ||
+			    perf_probe_event__copy(&ret->pev, pev) < 0) {
+				probe_cache_entry__delete(ret);
+				return NULL;
+			}
+		}
+	}
+
+	return ret;
+}
+
+/* For the kernel probe caches, pass target = NULL */
+static int probe_cache__open(struct probe_cache *pcache, const char *target)
+{
+	char cpath[PATH_MAX];
+	char sbuildid[SBUILD_ID_SIZE];
+	char *dir_name;
+	bool is_kallsyms = !target;
+	int ret, fd;
+
+	if (target)
+		ret = filename__sprintf_build_id(target, sbuildid);
+	else {
+		target = "[kernel.kallsyms]";
+		ret = sysfs__sprintf_build_id("/", sbuildid);
+	}
+	if (ret < 0) {
+		pr_debug("Failed to get build-id from %s.\n", target ?: "kernel");
+		return ret;
+	}
+
+	/* If we have no buildid cache, make it */
+	if (!build_id_cache__cached(sbuildid)) {
+		ret = build_id_cache__add_s(sbuildid, target,
+					    is_kallsyms, NULL);
+		if (ret < 0) {
+			pr_debug("Failed to add build-id cache: %s\n", target);
+			return ret;
+		}
+	}
+
+	dir_name = build_id_cache__dirname_from_path(sbuildid, target,
+						     is_kallsyms, false);
+	if (!dir_name)
+		return -ENOMEM;
+
+	snprintf(cpath, PATH_MAX, "%s/probes", dir_name);
+	fd = open(cpath, O_CREAT | O_RDWR | O_APPEND, 0644);
+	if (fd < 0)
+		pr_debug("Failed to open cache(%d): %s\n", fd, cpath);
+	free(dir_name);
+	pcache->fd = fd;
+
+	return fd;
+}
+
+static int probe_cache__load(struct probe_cache *pcache)
+{
+	struct probe_cache_entry *entry = NULL;
+	char buf[MAX_CMDLEN], *p;
+	int ret = 0;
+	FILE *fp;
+
+	fp = fdopen(dup(pcache->fd), "r");
+	while (!feof(fp)) {
+		if (!fgets(buf, MAX_CMDLEN, fp))
+			break;
+		p = strchr(buf, '\n');
+		if (p)
+			*p = '\0';
+		if (buf[0] == '#') {	/* #perf_probe_event */
+			entry = probe_cache_entry__new(NULL);
+			entry->spev = strdup(buf + 1);
+			ret = parse_perf_probe_command(buf + 1, &entry->pev);
+			if (!entry->spev || ret < 0) {
+				probe_cache_entry__delete(entry);
+				goto out;
+			}
+			list_add_tail(&entry->list, &pcache->list);
+		} else {	/* trace_probe_event */
+			if (!entry) {
+				ret = -EINVAL;
+				goto out;
+			}
+			strlist__add(entry->tevlist, buf);
+		}
+	}
+out:
+	fclose(fp);
+	return ret;
+}
+
+static struct probe_cache *probe_cache__alloc(void)
+{
+	struct probe_cache *ret = zalloc(sizeof(*ret));
+
+	if (ret) {
+		INIT_LIST_HEAD(&ret->list);
+		ret->fd = -EINVAL;
+	}
+	return ret;
+}
+
+void probe_cache__delete(struct probe_cache *pcache)
+{
+	struct probe_cache_entry *entry;
+
+	if (!pcache)
+		return;
+
+	while (!list_empty(&pcache->list)) {
+		entry = list_first_entry(&pcache->list, typeof(*entry), list);
+		probe_cache_entry__delete(entry);
+	}
+	if (pcache->fd > 0)
+		close(pcache->fd);
+	free(pcache);
+}
+
+struct probe_cache *probe_cache__new(const char *target)
+{
+	struct probe_cache *pcache = probe_cache__alloc();
+	int ret;
+
+	if (!pcache)
+		return NULL;
+
+	ret = probe_cache__open(pcache, target);
+	if (ret < 0) {
+		pr_debug("Cache open error: %d\n", ret);
+		goto out_err;
+	}
+
+	ret = probe_cache__load(pcache);
+	if (ret < 0) {
+		pr_debug("Cache read error: %d\n", ret);
+		goto out_err;
+	}
+
+	return pcache;
+
+out_err:
+	probe_cache__delete(pcache);
+	return NULL;
+}
+
+static bool streql(const char *a, const char *b)
+{
+	if (a == b)
+		return true;
+
+	if (!a || !b)
+		return false;
+
+	return !strcmp(a, b);
+}
+
+static struct probe_cache_entry *
+probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev)
+{
+	struct probe_cache_entry *entry = NULL;
+	char *cmd = NULL;
+
+	cmd = synthesize_perf_probe_command(pev);
+	if (!cmd)
+		return NULL;
+
+	list_for_each_entry(entry, &pcache->list, list) {
+		/* Hit if same event name or same command-string */
+		if ((pev->event &&
+		     (streql(entry->pev.group, pev->group) &&
+		      streql(entry->pev.event, pev->event))) ||
+		    (!strcmp(entry->spev, cmd)))
+			goto found;
+	}
+	entry = NULL;
+
+found:
+	free(cmd);
+	return entry;
+}
+
+int probe_cache__add_entry(struct probe_cache *pcache,
+			   struct perf_probe_event *pev,
+			   struct probe_trace_event *tevs, int ntevs)
+{
+	struct probe_cache_entry *entry = NULL;
+	char *command;
+	int i, ret = 0;
+
+	if (!pcache || !pev || !tevs || ntevs <= 0) {
+		ret = -EINVAL;
+		goto out_err;
+	}
+
+	/* Remove old cache entry */
+	entry = probe_cache__find(pcache, pev);
+	if (entry)
+		probe_cache_entry__delete(entry);
+
+	ret = -ENOMEM;
+	entry = probe_cache_entry__new(pev);
+	if (!entry)
+		goto out_err;
+
+	for (i = 0; i < ntevs; i++) {
+		if (!tevs[i].point.symbol)
+			continue;
+
+		command = synthesize_probe_trace_command(&tevs[i]);
+		if (!command)
+			goto out_err;
+		strlist__add(entry->tevlist, command);
+		free(command);
+	}
+	list_add_tail(&entry->list, &pcache->list);
+	pr_debug("Added probe cache: %d\n", ntevs);
+	return 0;
+
+out_err:
+	pr_debug("Failed to add probe caches\n");
+	if (entry)
+		probe_cache_entry__delete(entry);
+	return ret;
+}
+
+static int probe_cache_entry__write(struct probe_cache_entry *entry, int fd)
+{
+	struct str_node *snode;
+	struct iovec iov[3];
+	int ret;
+
+	pr_debug("Writing cache: #%s\n", entry->spev);
+	iov[0].iov_base = (void *)"#"; iov[0].iov_len = 1;
+	iov[1].iov_base = entry->spev; iov[1].iov_len = strlen(entry->spev);
+	iov[2].iov_base = (void *)"\n"; iov[2].iov_len = 1;
+	ret = writev(fd, iov, 3);
+	if (ret < 0)
+		return ret;
+
+	strlist__for_each(snode, entry->tevlist) {
+		iov[0].iov_base = (void *)snode->s;
+		iov[0].iov_len = strlen(snode->s);
+		iov[1].iov_base = (void *)"\n"; iov[1].iov_len = 1;
+		ret = writev(fd, iov, 2);
+		if (ret < 0)
+			return ret;
+	}
+	return 0;
+}
+
+int probe_cache__commit(struct probe_cache *pcache)
+{
+	struct probe_cache_entry *entry;
+	int ret = 0;
+
+	/* TBD: if we do not update existing entries, skip it */
+	ret = lseek(pcache->fd, 0, SEEK_SET);
+	if (ret < 0)
+		goto out;
+
+	ret = ftruncate(pcache->fd, 0);
+	if (ret < 0)
+		goto out;
+
+	list_for_each_entry(entry, &pcache->list, list) {
+		ret = probe_cache_entry__write(entry, pcache->fd);
+		pr_debug("Cache committed: %d\n", ret);
+		if (ret < 0)
+			break;
+	}
+out:
+	return ret;
+}
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
index ada94a2..7b473b39 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -15,4 +15,24 @@ struct strlist *probe_file__get_rawlist(int fd);
 int probe_file__add_event(int fd, struct probe_trace_event *tev);
 int probe_file__del_events(int fd, struct strfilter *filter);
 
+/* Cache of probe definitions */
+struct probe_cache_entry {
+	struct list_head	list;
+	struct perf_probe_event pev;
+	char			*spev;
+	struct strlist		*tevlist;
+};
+
+struct probe_cache {
+	int	fd;
+	struct list_head list;
+};
+
+struct probe_cache *probe_cache__new(const char *target);
+int probe_cache__add_entry(struct probe_cache *pcache,
+			   struct perf_probe_event *pev,
+			   struct probe_trace_event *tevs, int ntevs);
+int probe_cache__commit(struct probe_cache *pcache);
+void probe_cache__delete(struct probe_cache *pcache);
+
 #endif


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

* [RFC PATCH perf/core v3 07/17] perf probe: Use cache entry if possible
  2015-08-15 11:42 [RFC PATCH perf/core v3 00/17] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (5 preceding siblings ...)
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 06/17] perf probe: Add --cache option to cache the probe definitions Masami Hiramatsu
@ 2015-08-15 11:43 ` Masami Hiramatsu
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 08/17] perf probe: Show all cached probes Masami Hiramatsu
                   ` (10 subsequent siblings)
  17 siblings, 0 replies; 25+ messages in thread
From: Masami Hiramatsu @ 2015-08-15 11:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, Adrian Hunter, Ingo Molnar,
	Paul Mackerras, Jiri Olsa, Namhyung Kim, Borislav Petkov,
	Hemant Kumar

Before analyzing debuginfo, try to find a corresponding entry
from probe cache always. This does not depend on --cache,
the --cache enables to store/update cache, but looking up
the cache is always enabled.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>

---
Changes in v2:
 - Reuse tev->event and tev->group as base event name if possible,
   since when using the cache entry with wildcard, pev will not
   have its name/symbol.
 - Do not skip trace events whose tev->point.symbol == NULL if
   pev->uprobes is set, since cached uprobe event doesn't know
   the original symbols.
 - Fix to set tev->uprobes attribute flag from the pev->uprobes.
---
 tools/perf/util/probe-event.c |   70 ++++++++++++++++++++++++++++++++++++++++-
 tools/perf/util/probe-file.c  |   20 +++++++++++-
 tools/perf/util/probe-file.h  |    5 ++-
 3 files changed, 91 insertions(+), 4 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 914b414..a580ec4 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -2306,13 +2306,18 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev,
 
 	if (pev->event)
 		event = pev->event;
-	else
+	else if (tev->event)
+		event = tev->event;
+	else {
 		if (pev->point.function && !strisglob(pev->point.function))
 			event = pev->point.function;
 		else
 			event = tev->point.realname;
+	}
 	if (pev->group)
 		group = pev->group;
+	else if (tev->group)
+		group = tev->group;
 	else
 		group = PERFPROBE_GROUP;
 
@@ -2362,7 +2367,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
 	for (i = 0; i < ntevs; i++) {
 		tev = &tevs[i];
 		/* Skip if the symbol is out of .text or blacklisted */
-		if (!tev->point.symbol)
+		if (!tev->point.symbol && !pev->uprobes)
 			continue;
 
 		/* Set new name for tev (and update namelist) */
@@ -2585,6 +2590,62 @@ err_out:
 
 bool __weak arch__prefers_symtab(void) { return false; }
 
+static int find_probe_trace_events_from_cache(struct perf_probe_event *pev,
+					      struct probe_trace_event **tevs)
+{
+	struct probe_cache *cache;
+	struct probe_cache_entry *entry;
+	struct probe_trace_event *tev;
+	struct str_node *node;
+	int ret, i;
+
+	cache = probe_cache__new(pev->target);
+	if (!cache)
+		return 0;
+
+	entry = probe_cache__find(cache, pev);
+
+	if (!entry && !pev->event &&
+	    (!pev->point.file && pev->point.function && !pev->point.retprobe &&
+	     !pev->point.line && !pev->point.offset && !pev->point.lazy_line)) {
+		entry = probe_cache__find_by_name(cache, pev->group,
+						  pev->point.function);
+	}
+	if (!entry) {
+		ret = 0;
+		goto out;
+	}
+
+	ret = strlist__nr_entries(entry->tevlist);
+	if (ret > probe_conf.max_probes) {
+		pr_debug("Too many entries matched in the cache of %s\n",
+			 pev->target ? : "kernel");
+		ret = -E2BIG;
+		goto out;
+	}
+
+	*tevs = zalloc(ret * sizeof(*tev));
+	if (!*tevs) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	i = 0;
+	strlist__for_each(node, entry->tevlist) {
+		tev = &(*tevs)[i++];
+		ret = parse_probe_trace_command(node->s, tev);
+		if (ret < 0)
+			goto out;
+		/* Set the uprobes attribute as same as original */
+		tev->uprobes = pev->uprobes;
+	}
+	ret = i;
+
+out:
+	probe_cache__delete(cache);
+	return ret;
+}
+
 static int convert_to_probe_trace_events(struct perf_probe_event *pev,
 					 struct probe_trace_event **tevs)
 {
@@ -2599,6 +2660,11 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
 		}
 	}
 
+	/* At first, we need to lookup cache entry */
+	ret = find_probe_trace_events_from_cache(pev, tevs);
+	if (ret > 0)
+		return ret;	/* Found in probe cache */
+
 	if (arch__prefers_symtab() && !perf_probe_event_need_dwarf(pev)) {
 		ret = find_probe_trace_events_from_map(pev, tevs);
 		if (ret > 0)
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 71915d5..afcfd76 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -481,7 +481,7 @@ static bool streql(const char *a, const char *b)
 	return !strcmp(a, b);
 }
 
-static struct probe_cache_entry *
+struct probe_cache_entry *
 probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev)
 {
 	struct probe_cache_entry *entry = NULL;
@@ -506,6 +506,24 @@ found:
 	return entry;
 }
 
+struct probe_cache_entry *
+probe_cache__find_by_name(struct probe_cache *pcache,
+			  const char *group, const char *event)
+{
+	struct probe_cache_entry *entry = NULL;
+
+	list_for_each_entry(entry, &pcache->list, list) {
+		/* Hit if same event name or same command-string */
+		if (streql(entry->pev.group, group) &&
+		    streql(entry->pev.event, event))
+			goto found;
+	}
+	entry = NULL;
+
+found:
+	return entry;
+}
+
 int probe_cache__add_entry(struct probe_cache *pcache,
 			   struct perf_probe_event *pev,
 			   struct probe_trace_event *tevs, int ntevs)
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
index 7b473b39..833e061 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -34,5 +34,8 @@ int probe_cache__add_entry(struct probe_cache *pcache,
 			   struct probe_trace_event *tevs, int ntevs);
 int probe_cache__commit(struct probe_cache *pcache);
 void probe_cache__delete(struct probe_cache *pcache);
-
+struct probe_cache_entry *probe_cache__find(struct probe_cache *pcache,
+					    struct perf_probe_event *pev);
+struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache,
+					const char *group, const char *event);
 #endif


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

* [RFC PATCH perf/core v3 08/17] perf probe: Show all cached probes
  2015-08-15 11:42 [RFC PATCH perf/core v3 00/17] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (6 preceding siblings ...)
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 07/17] perf probe: Use cache entry if possible Masami Hiramatsu
@ 2015-08-15 11:43 ` Masami Hiramatsu
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 09/17] perf probe: Remove caches when --cache is given Masami Hiramatsu
                   ` (9 subsequent siblings)
  17 siblings, 0 replies; 25+ messages in thread
From: Masami Hiramatsu @ 2015-08-15 11:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, Adrian Hunter, Ingo Molnar,
	Paul Mackerras, Jiri Olsa, Namhyung Kim, Borislav Petkov,
	Hemant Kumar

perf probe --list shows all cached probes when --cache
is given. Each caches are shown with on which binary that
probed. e.g.
  -----
  # perf probe --cache vfs_read \$params
  # perf probe --cache -x /lib64/libc-2.17.so getaddrinfo \$params
  # ./perf probe --cache --list
  /[kernel.kallsyms] (1466a0a250b5d0070c6d0f03c5fed30b237970a1):
  vfs_read $params
  /usr/lib64/libc-2.17.so (c31ffe7942bfd77b2fca8f9bd5709d387a86d3bc):
  getaddrinfo $params
  -----
Note that $params requires debuginfo.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>

---
Changes in v3:
 - Fix to delete strlist.
Changes in v2:
 - Fix to ignore if build-id list is failed to get with -ENOENT,
   since this can happen when ~/.debug is not initialized.
 - Do not show binary name if there is no cached entries.
 - Update perf-probe.txt too.
---
 tools/perf/Documentation/perf-probe.txt |    8 ++-
 tools/perf/builtin-probe.c              |    2 -
 tools/perf/util/build-id.c              |   79 ++++++++++++++++++++++++++++++-
 tools/perf/util/build-id.h              |    3 +
 tools/perf/util/probe-event.c           |    3 +
 tools/perf/util/probe-file.c            |   67 ++++++++++++++++++++++++++
 tools/perf/util/probe-file.h            |    1 
 7 files changed, 156 insertions(+), 7 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 947db6f..5a70d45 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -67,7 +67,10 @@ OPTIONS
 
 -l::
 --list[=[GROUP:]EVENT]::
-	List up current probe events. This can also accept filtering patterns of event names.
+	List up current probe events. This can also accept filtering patterns of
+	event names.
+	When this is used with --cache, perf shows all cached probes instead of
+	the live probes.
 
 -L::
 --line=::
@@ -110,8 +113,9 @@ OPTIONS
 	adding and removal operations.
 
 --cache::
-	Cache the probes (with --add option). Any events which successfully added
+	(With --add) Cache the probes. Any events which successfully added
 	are also stored in the cache file.
+	(With --list) Show cached probes.
 
 --max-probes=NUM::
 	Set the maximum number of probe points for an event. Default is 128.
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 5ac8a79..5d0c246 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -44,7 +44,7 @@
 
 #define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*"
 #define DEFAULT_FUNC_FILTER "!_*"
-#define DEFAULT_LIST_FILTER "*:*"
+#define DEFAULT_LIST_FILTER "*"
 
 /* Session management structure */
 static struct {
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index e7fe606..b68f5f0 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -144,8 +144,7 @@ static int asnprintf(char **strp, size_t size, const char *fmt, ...)
 	return ret;
 }
 
-static char *build_id_cache__linkname(const char *sbuild_id, char *bf,
-				      size_t size)
+char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size)
 {
 	char *tmp = bf;
 	int ret = asnprintf(&bf, size, "%s/.build-id/%.2s/%s", buildid_dir,
@@ -155,6 +154,29 @@ static char *build_id_cache__linkname(const char *sbuild_id, char *bf,
 	return bf;
 }
 
+char *build_id_cache__origname(const char *sbuild_id)
+{
+	char *linkname;
+	char buf[PATH_MAX];
+	char *ret = NULL, *p;
+
+	linkname = build_id_cache__linkname(sbuild_id, NULL, 0);
+	if (!linkname)
+		return NULL;
+
+	if (readlink(linkname, buf, PATH_MAX) < 0)
+		goto out;
+	/* The link should be "../..<origpath>/<sbuild_id>" */
+	p = strrchr(buf, '/');	/* Cut off the "/<sbuild_id>" */
+	if (p) {
+		*p = '\0';
+		ret = strdup(buf + 5);	/* Skip "../.." */
+	}
+out:
+	free(linkname);
+	return ret;
+}
+
 static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso)
 {
 	return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf");
@@ -313,6 +335,59 @@ void disable_buildid_cache(void)
 	no_buildid_cache = true;
 }
 
+int build_id_cache__list_all(struct strlist **result)
+{
+	struct strlist *toplist, *list, *bidlist;
+	struct str_node *nd, *nd2;
+	char *topdir, *linkdir;
+	char sbuild_id[SBUILD_ID_SIZE];
+	int ret = 0;
+
+	/* Open the top-level directory */
+	if (asprintf(&topdir, "%s/.build-id/", buildid_dir) < 0)
+		return -errno;
+	toplist = lsdir(topdir, lsdir_no_dot_filter);
+	if (!toplist) {
+		pr_debug("Failed to opendir %s\n", topdir);
+		ret = -errno;
+		goto out;
+	}
+	bidlist = strlist__new(NULL, NULL);
+	strlist__for_each(nd, toplist) {
+		if (asprintf(&linkdir, "%s/%s", topdir, nd->s) < 0) {
+			ret = -errno;
+			goto out;
+		}
+		/* Open the lower-level directory */
+		list = lsdir(linkdir, lsdir_no_dot_filter);
+		if (!list) {
+			pr_debug("Failed to open %s: %d\n", linkdir, -errno);
+			goto next;
+		}
+		strlist__for_each(nd2, list) {
+			ret = snprintf(sbuild_id, SBUILD_ID_SIZE, "%s%s",
+					nd->s, nd2->s);
+			if (ret != SBUILD_ID_SIZE - 1) {
+				pr_debug("%s/%s is not buildid cache\n",
+					nd->s, nd2->s);
+				continue;
+			}
+			strlist__add(bidlist, sbuild_id);
+		}
+		strlist__delete(list);
+next:
+		free(linkdir);
+	}
+
+	*result = bidlist;
+out:
+	if (toplist)
+		strlist__delete(toplist);
+	free(topdir);
+
+	return ret;
+}
+
 char *build_id_cache__dirname_from_path(const char *sbuild_id, const char *name,
 					bool is_kallsyms, bool is_vdso)
 {
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index a1f428d..2d5c61c 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -27,8 +27,11 @@ bool perf_session__read_build_ids(struct perf_session *session, bool with_hits);
 int perf_session__write_buildid_table(struct perf_session *session, int fd);
 int perf_session__cache_build_ids(struct perf_session *session);
 
+char *build_id_cache__origname(const char *sbuild_id);
+char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size);
 char *build_id_cache__dirname_from_path(const char *sbuild_id, const char *name,
 					bool is_kallsyms, bool is_vdso);
+int build_id_cache__list_all(struct strlist **result);
 int build_id_cache__list_build_ids(const char *pathname,
 				   struct strlist **result);
 bool build_id_cache__cached(const char *sbuild_id);
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index a580ec4..e69de54 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -2206,6 +2206,9 @@ int show_perf_probe_events(struct strfilter *filter)
 
 	setup_pager();
 
+	if (probe_conf.cache)
+		return probe_cache__show_all_caches(filter);
+
 	ret = init_symbol_maps(false);
 	if (ret < 0)
 		return ret;
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index afcfd76..7b9a4a3 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -340,10 +340,17 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target)
 {
 	char cpath[PATH_MAX];
 	char sbuildid[SBUILD_ID_SIZE];
-	char *dir_name;
+	char *dir_name = NULL;
 	bool is_kallsyms = !target;
 	int ret, fd;
 
+	if (target && build_id_cache__cached(target)) {
+		/* This is a cached buildid */
+		strncpy(sbuildid, target, SBUILD_ID_SIZE);
+		dir_name = build_id_cache__linkname(sbuildid, NULL, 0);
+		goto found;
+	}
+
 	if (target)
 		ret = filename__sprintf_build_id(target, sbuildid);
 	else {
@@ -367,8 +374,11 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target)
 
 	dir_name = build_id_cache__dirname_from_path(sbuildid, target,
 						     is_kallsyms, false);
-	if (!dir_name)
+found:
+	if (!dir_name) {
+		pr_debug("Failed to get cache from %s\n", target);
 		return -ENOMEM;
+	}
 
 	snprintf(cpath, PATH_MAX, "%s/probes", dir_name);
 	fd = open(cpath, O_CREAT | O_RDWR | O_APPEND, 0644);
@@ -616,3 +626,56 @@ int probe_cache__commit(struct probe_cache *pcache)
 out:
 	return ret;
 }
+
+static int probe_cache__show_entries(struct probe_cache *pcache,
+				     struct strfilter *filter)
+{
+	struct probe_cache_entry *entry;
+	char buf[128], *ptr;
+
+	list_for_each_entry(entry, &pcache->list, list) {
+		if (entry->pev.event) {
+			ptr = buf;
+			snprintf(buf, 128, "%s:%s", entry->pev.group, entry->pev.event);
+		} else
+			ptr = entry->spev;
+		if (strfilter__compare(filter, ptr))
+			printf("%s\n", entry->spev);
+	}
+	return 0;
+}
+
+/* Show all cached probes */
+int probe_cache__show_all_caches(struct strfilter *filter)
+{
+	struct probe_cache *pcache;
+	struct strlist *bidlist;
+	struct str_node *nd;
+	char *buf;
+	int ret;
+
+	buf = strfilter__string(filter);
+	pr_debug("list cache with filter: %s\n", buf);
+	free(buf);
+
+	ret = build_id_cache__list_all(&bidlist);
+	if (ret < 0) {
+		pr_debug("Failed to get buildids: %d\n", ret);
+		return ret == -ENOENT ? 0 : ret;
+	}
+	strlist__for_each(nd, bidlist) {
+		pcache = probe_cache__new(nd->s);
+		if (!pcache)
+			continue;
+		if (!list_empty(&pcache->list)) {
+			buf = build_id_cache__origname(nd->s);
+			printf("%s (%s):\n", buf, nd->s);
+			free(buf);
+			probe_cache__show_entries(pcache, filter);
+		}
+		probe_cache__delete(pcache);
+	}
+	strlist__delete(bidlist);
+
+	return 0;
+}
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
index 833e061..26dc4f7 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -38,4 +38,5 @@ struct probe_cache_entry *probe_cache__find(struct probe_cache *pcache,
 					    struct perf_probe_event *pev);
 struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache,
 					const char *group, const char *event);
+int probe_cache__show_all_caches(struct strfilter *filter);
 #endif


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

* [RFC PATCH perf/core v3 09/17] perf probe: Remove caches when --cache is given
  2015-08-15 11:42 [RFC PATCH perf/core v3 00/17] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (7 preceding siblings ...)
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 08/17] perf probe: Show all cached probes Masami Hiramatsu
@ 2015-08-15 11:43 ` Masami Hiramatsu
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 10/17] perf/sdt: ELF support for SDT Masami Hiramatsu
                   ` (8 subsequent siblings)
  17 siblings, 0 replies; 25+ messages in thread
From: Masami Hiramatsu @ 2015-08-15 11:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, Adrian Hunter, Ingo Molnar,
	Paul Mackerras, Jiri Olsa, Namhyung Kim, Borislav Petkov,
	Hemant Kumar

perf-probe --del removes caches when --cache is given.
Note that the delete pattern is not same as normal events.

If you cached probes with event name, --del "eventname"
works as expected. However, if you skipped it, the cached
probes doesn't have actual event name. In that case
 --del "probe-desc" is required (wildcard is acceptable).
For example a cache entry has the probe-desc "vfs_read $params",
you can remove it with --del 'vfs_read*'.

  -----
  # perf probe --cache --list
  /[kernel.kallsyms] (1466a0a250b5d0070c6d0f03c5fed30b237970a1):
  vfs_read $params
  /usr/lib64/libc-2.17.so (c31ffe7942bfd77b2fca8f9bd5709d387a86d3bc):
  getaddrinfo $params

  # perf probe --cache --del vfs_read\*
  Removed event: probe:vfs_read

  # perf probe --cache --list
  /[kernel.kallsyms] (1466a0a250b5d0070c6d0f03c5fed30b237970a1):
  /usr/lib64/libc-2.17.so (c31ffe7942bfd77b2fca8f9bd5709d387a86d3bc):
  getaddrinfo $params
  -----

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>

---
 Changes in v2:
  - Update perf-probe.txt
---
 tools/perf/Documentation/perf-probe.txt |    1 +
 tools/perf/util/probe-event.c           |   26 ++++++++++++++++++++++++
 tools/perf/util/probe-file.c            |   33 +++++++++++++++++++++++--------
 tools/perf/util/probe-file.h            |    2 ++
 4 files changed, 54 insertions(+), 8 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 5a70d45..8d09173 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -116,6 +116,7 @@ OPTIONS
 	(With --add) Cache the probes. Any events which successfully added
 	are also stored in the cache file.
 	(With --list) Show cached probes.
+	(With --del) Remove cached probes.
 
 --max-probes=NUM::
 	Set the maximum number of probe points for an event. Default is 128.
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index e69de54..8de406a 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -2742,6 +2742,30 @@ end:
 	return ret;
 }
 
+static int del_perf_probe_caches(struct strfilter *filter)
+{
+	struct probe_cache *cache;
+	struct strlist *bidlist;
+	struct str_node *nd;
+	int ret;
+
+	ret = build_id_cache__list_all(&bidlist);
+	if (ret < 0) {
+		pr_debug("Failed to get buildids: %d\n", ret);
+		return ret;
+	}
+
+	strlist__for_each(nd, bidlist) {
+		cache = probe_cache__new(nd->s);
+		if (!cache)
+			continue;
+		probe_cache__remove_entries(cache, filter);
+		probe_cache__commit(cache);
+		probe_cache__delete(cache);
+	}
+	return 0;
+}
+
 int del_perf_probe_events(struct strfilter *filter)
 {
 	int ret, ret2, ufd = -1, kfd = -1;
@@ -2751,6 +2775,8 @@ int del_perf_probe_events(struct strfilter *filter)
 		return -EINVAL;
 
 	pr_debug("Delete filter: \'%s\'\n", str);
+	if (probe_conf.cache)
+		return del_perf_probe_caches(filter);
 
 	/* Get current event names */
 	ret = probe_file__open_both(&kfd, &ufd, PF_FL_RW);
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 7b9a4a3..5ee892f 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -371,7 +371,6 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target)
 			return ret;
 		}
 	}
-
 	dir_name = build_id_cache__dirname_from_path(sbuildid, target,
 						     is_kallsyms, false);
 found:
@@ -627,19 +626,37 @@ out:
 	return ret;
 }
 
+static bool probe_cache_entry__compare(struct probe_cache_entry *entry,
+				       struct strfilter *filter)
+{
+	char buf[128], *ptr = entry->spev;
+
+	if (entry->pev.event) {
+		snprintf(buf, 128, "%s:%s", entry->pev.group, entry->pev.event);
+		ptr = buf;
+	}
+	return strfilter__compare(filter, ptr);
+}
+
+int probe_cache__remove_entries(struct probe_cache *pcache,
+				struct strfilter *filter)
+{
+	struct probe_cache_entry *entry, *tmp;
+
+	list_for_each_entry_safe(entry, tmp, &pcache->list, list) {
+		if (probe_cache_entry__compare(entry, filter))
+			probe_cache_entry__delete(entry);
+	}
+	return 0;
+}
+
 static int probe_cache__show_entries(struct probe_cache *pcache,
 				     struct strfilter *filter)
 {
 	struct probe_cache_entry *entry;
-	char buf[128], *ptr;
 
 	list_for_each_entry(entry, &pcache->list, list) {
-		if (entry->pev.event) {
-			ptr = buf;
-			snprintf(buf, 128, "%s:%s", entry->pev.group, entry->pev.event);
-		} else
-			ptr = entry->spev;
-		if (strfilter__compare(filter, ptr))
+		if (probe_cache_entry__compare(entry, filter))
 			printf("%s\n", entry->spev);
 	}
 	return 0;
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
index 26dc4f7..391fde0 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -34,6 +34,8 @@ int probe_cache__add_entry(struct probe_cache *pcache,
 			   struct probe_trace_event *tevs, int ntevs);
 int probe_cache__commit(struct probe_cache *pcache);
 void probe_cache__delete(struct probe_cache *pcache);
+int probe_cache__remove_entries(struct probe_cache *pcache,
+				struct strfilter *filter);
 struct probe_cache_entry *probe_cache__find(struct probe_cache *pcache,
 					    struct perf_probe_event *pev);
 struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache,


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

* [RFC PATCH perf/core v3 10/17] perf/sdt: ELF support for SDT
  2015-08-15 11:42 [RFC PATCH perf/core v3 00/17] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (8 preceding siblings ...)
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 09/17] perf probe: Remove caches when --cache is given Masami Hiramatsu
@ 2015-08-15 11:43 ` Masami Hiramatsu
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 11/17] perf probe: Add group name support Masami Hiramatsu
                   ` (7 subsequent siblings)
  17 siblings, 0 replies; 25+ messages in thread
From: Masami Hiramatsu @ 2015-08-15 11:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, Adrian Hunter, Ingo Molnar,
	Paul Mackerras, Jiri Olsa, Namhyung Kim, Borislav Petkov,
	Hemant Kumar

From: Hemant Kumar <hemant@linux.vnet.ibm.com>

This patch serves the initial support to identify and list SDT events in binaries.
When programs containing SDT markers are compiled, gcc with the help of assembler
directives identifies them and places them in the section ".note.stapsdt". To find
these markers from the binaries, one needs to traverse through this section and
parse the relevant details like the name, type and location of the marker. Also,
the original location could be skewed due to the effect of prelinking. If that is
the case, the locations need to be adjusted.

The functions in this patch open a given ELF, find out the SDT section, parse the
relevant details, adjust the location (if necessary) and populate them in a list.

A typical note entry in ".note.stapsdt" section is as follows :


                                 |--nhdr.n_namesz--|
                ------------------------------------
                |      nhdr      |     "stapsdt"   |
        -----   |----------------------------------|
         |      |  <location>       <base_address> |
         |      |  <semaphore>                     |
nhdr.n_descsize |  "provider_name"   "note_name"   |
         |      |   <args>                         |
        -----   |----------------------------------|
                |      nhdr      |     "stapsdt"   |
                |...

The above shows an excerpt from the section ".note.stapsdt".
'nhdr' is a structure which has the note name size (n_namesz), note
description size (n_desc_sz) and note type (n_type). So, in order to
parse the note note info, we need nhdr to tell us where to start from.
As can be seen from <sys/sdt.h>, the name of the SDT notes given is "stapsdt".
But this is not the identifier of the note.
After that, we go to description of the note to find out its location, the
address of the ".stapsdt.base" section and the semaphore address.
Then, we find the provider name and the SDT marker name and then follow the
arguments.

Signed-off-by: Hemant Kumar <hemant@linux.vnet.ibm.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/util/symbol-elf.c |  252 ++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/symbol.h     |   22 ++++
 2 files changed, 274 insertions(+)

diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index b0ad810..14369ca 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -1775,6 +1775,258 @@ void kcore_extract__delete(struct kcore_extract *kce)
 	unlink(kce->extract_filename);
 }
 
+/**
+ * populate_sdt_note : Parse raw data and identify SDT note
+ * @elf: elf of the opened file
+ * @data: raw data of a section with description offset applied
+ * @len: note description size
+ * @type: type of the note
+ * @sdt_notes: List to add the SDT note
+ *
+ * Responsible for parsing the @data in section .note.stapsdt in @elf and
+ * if its an SDT note, it appends to @sdt_notes list.
+ */
+static int populate_sdt_note(Elf **elf, const char *data, size_t len,
+			     struct list_head *sdt_notes)
+{
+	const char *provider, *name;
+	struct sdt_note *tmp = NULL;
+	GElf_Ehdr ehdr;
+	GElf_Addr base_off = 0;
+	GElf_Shdr shdr;
+	int ret = -EINVAL;
+
+	union {
+		Elf64_Addr a64[NR_ADDR];
+		Elf32_Addr a32[NR_ADDR];
+	} buf;
+
+	Elf_Data dst = {
+		.d_buf = &buf, .d_type = ELF_T_ADDR, .d_version = EV_CURRENT,
+		.d_size = gelf_fsize((*elf), ELF_T_ADDR, NR_ADDR, EV_CURRENT),
+		.d_off = 0, .d_align = 0
+	};
+	Elf_Data src = {
+		.d_buf = (void *) data, .d_type = ELF_T_ADDR,
+		.d_version = EV_CURRENT, .d_size = dst.d_size, .d_off = 0,
+		.d_align = 0
+	};
+
+	tmp = (struct sdt_note *)calloc(1, sizeof(struct sdt_note));
+	if (!tmp) {
+		ret = -ENOMEM;
+		goto out_err;
+	}
+
+	INIT_LIST_HEAD(&tmp->note_list);
+
+	if (len < dst.d_size + 3)
+		goto out_free_note;
+
+	/* Translation from file representation to memory representation */
+	if (gelf_xlatetom(*elf, &dst, &src,
+			  elf_getident(*elf, NULL)[EI_DATA]) == NULL) {
+		pr_err("gelf_xlatetom : %s\n", elf_errmsg(-1));
+		goto out_free_note;
+	}
+
+	/* Populate the fields of sdt_note */
+	provider = data + dst.d_size;
+
+	name = (const char *)memchr(provider, '\0', data + len - provider);
+	if (name++ == NULL)
+		goto out_free_note;
+
+	tmp->provider = strdup(provider);
+	if (!tmp->provider) {
+		ret = -ENOMEM;
+		goto out_free_note;
+	}
+	tmp->name = strdup(name);
+	if (!tmp->name) {
+		ret = -ENOMEM;
+		goto out_free_prov;
+	}
+
+	if (gelf_getclass(*elf) == ELFCLASS32) {
+		memcpy(&tmp->addr, &buf, 3 * sizeof(Elf32_Addr));
+		tmp->bit32 = true;
+	} else {
+		memcpy(&tmp->addr, &buf, 3 * sizeof(Elf64_Addr));
+		tmp->bit32 = false;
+	}
+
+	if (!gelf_getehdr(*elf, &ehdr)) {
+		pr_debug("%s : cannot get elf header.\n", __func__);
+		ret = -EBADF;
+		goto out_free_name;
+	}
+
+	/* Adjust the prelink effect :
+	 * Find out the .stapsdt.base section.
+	 * This scn will help us to handle prelinking (if present).
+	 * Compare the retrieved file offset of the base section with the
+	 * base address in the description of the SDT note. If its different,
+	 * then accordingly, adjust the note location.
+	 */
+	if (elf_section_by_name(*elf, &ehdr, &shdr, SDT_BASE_SCN, NULL)) {
+		base_off = shdr.sh_offset;
+		if (base_off) {
+			if (tmp->bit32)
+				tmp->addr.a32[0] = tmp->addr.a32[0] + base_off -
+					tmp->addr.a32[1];
+			else
+				tmp->addr.a64[0] = tmp->addr.a64[0] + base_off -
+					tmp->addr.a64[1];
+		}
+	}
+
+	list_add_tail(&tmp->note_list, sdt_notes);
+	return 0;
+
+out_free_name:
+	free(tmp->name);
+out_free_prov:
+	free(tmp->provider);
+out_free_note:
+	free(tmp);
+out_err:
+	return ret;
+}
+
+/**
+ * construct_sdt_notes_list : constructs a list of SDT notes
+ * @elf : elf to look into
+ * @sdt_notes : empty list_head
+ *
+ * Scans the sections in 'elf' for the section
+ * .note.stapsdt. It, then calls populate_sdt_note to find
+ * out the SDT events and populates the 'sdt_notes'.
+ */
+static int construct_sdt_notes_list(Elf *elf, struct list_head *sdt_notes)
+{
+	GElf_Ehdr ehdr;
+	Elf_Scn *scn = NULL;
+	Elf_Data *data;
+	GElf_Shdr shdr;
+	size_t shstrndx, next;
+	GElf_Nhdr nhdr;
+	size_t name_off, desc_off, offset;
+	int ret = 0;
+
+	if (gelf_getehdr(elf, &ehdr) == NULL) {
+		ret = -EBADF;
+		goto out_ret;
+	}
+	if (elf_getshdrstrndx(elf, &shstrndx) != 0) {
+		ret = -EBADF;
+		goto out_ret;
+	}
+
+	/* Look for the required section */
+	scn = elf_section_by_name(elf, &ehdr, &shdr, SDT_NOTE_SCN, NULL);
+	if (!scn) {
+		ret = -ENOENT;
+		goto out_ret;
+	}
+
+	if ((shdr.sh_type != SHT_NOTE) || (shdr.sh_flags & SHF_ALLOC)) {
+		ret = -ENOENT;
+		goto out_ret;
+	}
+
+	data = elf_getdata(scn, NULL);
+
+	/* Get the SDT notes */
+	for (offset = 0; (next = gelf_getnote(data, offset, &nhdr, &name_off,
+					      &desc_off)) > 0; offset = next) {
+		if (nhdr.n_namesz == sizeof(SDT_NOTE_NAME) &&
+		    !memcmp(data->d_buf + name_off, SDT_NOTE_NAME,
+			    sizeof(SDT_NOTE_NAME))) {
+			/* Check the type of the note */
+			if (nhdr.n_type != SDT_NOTE_TYPE)
+				goto out_ret;
+
+			ret = populate_sdt_note(&elf, ((data->d_buf) + desc_off),
+						nhdr.n_descsz, sdt_notes);
+			if (ret < 0)
+				goto out_ret;
+		}
+	}
+	if (list_empty(sdt_notes))
+		ret = -ENOENT;
+
+out_ret:
+	return ret;
+}
+
+/**
+ * get_sdt_note_list : Wrapper to construct a list of sdt notes
+ * @head : empty list_head
+ * @target : file to find SDT notes from
+ *
+ * This opens the file, initializes
+ * the ELF and then calls construct_sdt_notes_list.
+ */
+int get_sdt_note_list(struct list_head *head, const char *target)
+{
+	Elf *elf;
+	int fd, ret;
+
+	fd = open(target, O_RDONLY);
+	if (fd < 0)
+		return -EBADF;
+
+	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+	if (!elf) {
+		ret = -EBADF;
+		goto out_close;
+	}
+	ret = construct_sdt_notes_list(elf, head);
+	elf_end(elf);
+out_close:
+	close(fd);
+	return ret;
+}
+
+/**
+ * cleanup_sdt_note_list : free the sdt notes' list
+ * @sdt_notes: sdt notes' list
+ *
+ * Free up the SDT notes in @sdt_notes.
+ * Returns the number of SDT notes free'd.
+ */
+int cleanup_sdt_note_list(struct list_head *sdt_notes)
+{
+	struct sdt_note *tmp, *pos;
+	int nr_free = 0;
+
+	list_for_each_entry_safe(pos, tmp, sdt_notes, note_list) {
+		list_del(&pos->note_list);
+		free(pos->name);
+		free(pos->provider);
+		free(pos);
+		nr_free++;
+	}
+	return nr_free;
+}
+
+/**
+ * sdt_notes__get_count: Counts the number of sdt events
+ * @start: list_head to sdt_notes list
+ *
+ * Returns the number of SDT notes in a list
+ */
+int sdt_notes__get_count(struct list_head *start)
+{
+	struct sdt_note *sdt_ptr;
+	int count = 0;
+
+	list_for_each_entry(sdt_ptr, start, note_list)
+		count++;
+	return count;
+}
+
 void symbol__elf_init(void)
 {
 	elf_version(EV_CURRENT);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index a4cde92..d02dff5 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -313,4 +313,26 @@ void arch__elf_sym_adjust(GElf_Sym *sym);
 
 int arch__choose_best_symbol(struct symbol *syma, struct symbol *symb);
 
+/* structure containing an SDT note's info */
+struct sdt_note {
+	char *name;			/* name of the note*/
+	char *provider;			/* provider name */
+	bool bit32;			/* whether the location is 32 bits? */
+	union {				/* location, base and semaphore addrs */
+		Elf64_Addr a64[3];
+		Elf32_Addr a32[3];
+	} addr;
+	struct list_head note_list;	/* SDT notes' list */
+};
+
+int get_sdt_note_list(struct list_head *head, const char *target);
+int cleanup_sdt_note_list(struct list_head *sdt_notes);
+int sdt_notes__get_count(struct list_head *start);
+
+#define SDT_BASE_SCN ".stapsdt.base"
+#define SDT_NOTE_SCN  ".note.stapsdt"
+#define SDT_NOTE_TYPE 3
+#define SDT_NOTE_NAME "stapsdt"
+#define NR_ADDR 3
+
 #endif /* __PERF_SYMBOL */


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

* [RFC PATCH perf/core v3 11/17] perf probe: Add group name support
  2015-08-15 11:42 [RFC PATCH perf/core v3 00/17] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (9 preceding siblings ...)
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 10/17] perf/sdt: ELF support for SDT Masami Hiramatsu
@ 2015-08-15 11:43 ` Masami Hiramatsu
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 12/17] perf-probe: Set default kprobe group name if it is not given Masami Hiramatsu
                   ` (6 subsequent siblings)
  17 siblings, 0 replies; 25+ messages in thread
From: Masami Hiramatsu @ 2015-08-15 11:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, Adrian Hunter, Ingo Molnar,
	Paul Mackerras, Jiri Olsa, Namhyung Kim, Borislav Petkov,
	Hemant Kumar

Allow user to set group name for adding new event.
Note that this can easily shot yourself in the foot.
E.g. Existing group name can conflict with other events.
Especially, using the group name reserved for kernel
modules can break something when loading/unloading
modules.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 tools/perf/util/probe-event.c |   23 ++++++++++++++---------
 1 file changed, 14 insertions(+), 9 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 8de406a..9b4c809 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1141,10 +1141,8 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 	bool file_spec = false;
 	/*
 	 * <Syntax>
-	 * perf probe [EVENT=]SRC[:LN|;PTN]
-	 * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
-	 *
-	 * TODO:Group name support
+	 * perf probe [GRP:][EVENT=]SRC[:LN|;PTN]
+	 * perf probe [GRP:][EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
 	 */
 	if (!arg)
 		return -EINVAL;
@@ -1153,11 +1151,19 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 	if (ptr && *ptr == '=') {	/* Event name */
 		*ptr = '\0';
 		tmp = ptr + 1;
-		if (strchr(arg, ':')) {
-			semantic_error("Group name is not supported yet.\n");
-			return -ENOTSUP;
-		}
+		ptr = strchr(arg, ':');
+		if (ptr) {
+			*ptr = '\0';
+			if (!is_c_func_name(arg))
+				goto not_fname;
+			pev->group = strdup(arg);
+			if (!pev->group)
+				return -ENOMEM;
+			arg = ptr + 1;
+		} else
+			pev->group = NULL;
 		if (!is_c_func_name(arg)) {
+not_fname:
 			semantic_error("%s is bad for event name -it must "
 				       "follow C symbol-naming rule.\n", arg);
 			return -EINVAL;
@@ -1165,7 +1171,6 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 		pev->event = strdup(arg);
 		if (pev->event == NULL)
 			return -ENOMEM;
-		pev->group = NULL;
 		arg = tmp;
 	}
 


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

* [RFC PATCH perf/core v3 12/17] perf-probe: Set default kprobe group name if it is not given
  2015-08-15 11:42 [RFC PATCH perf/core v3 00/17] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (10 preceding siblings ...)
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 11/17] perf probe: Add group name support Masami Hiramatsu
@ 2015-08-15 11:43 ` Masami Hiramatsu
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 13/17] perf buildid-cache: Scan and import user SDT events to probe cache Masami Hiramatsu
                   ` (5 subsequent siblings)
  17 siblings, 0 replies; 25+ messages in thread
From: Masami Hiramatsu @ 2015-08-15 11:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, Adrian Hunter, Ingo Molnar,
	Paul Mackerras, Jiri Olsa, Namhyung Kim, Borislav Petkov,
	Hemant Kumar

Set kprobe group name as "probe" if it is not given.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 Changes in v4
  - Newly added.
---
 tools/perf/util/probe-event.c |   10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 9b4c809..c559f01 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -2659,9 +2659,13 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
 {
 	int ret;
 
-	if (pev->uprobes && !pev->group) {
-		/* Replace group name if not given */
-		ret = convert_exec_to_group(pev->target, &pev->group);
+	if (!pev->group) {
+		/* Set group name if not given */
+		if (!pev->uprobes) {
+			pev->group = strdup(PERFPROBE_GROUP);
+			ret = pev->group ? 0 : -ENOMEM;
+		} else
+			ret = convert_exec_to_group(pev->target, &pev->group);
 		if (ret != 0) {
 			pr_warning("Failed to make a group name.\n");
 			return ret;


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

* [RFC PATCH perf/core v3 13/17] perf buildid-cache: Scan and import user SDT events to probe cache
  2015-08-15 11:42 [RFC PATCH perf/core v3 00/17] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (11 preceding siblings ...)
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 12/17] perf-probe: Set default kprobe group name if it is not given Masami Hiramatsu
@ 2015-08-15 11:43 ` Masami Hiramatsu
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 14/17] perf probe: Accept %sdt and %cached event name Masami Hiramatsu
                   ` (4 subsequent siblings)
  17 siblings, 0 replies; 25+ messages in thread
From: Masami Hiramatsu @ 2015-08-15 11:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, Adrian Hunter, Ingo Molnar,
	Paul Mackerras, Jiri Olsa, Namhyung Kim, Borislav Petkov,
	Hemant Kumar

perf buildid-cache --add <binary> scans given binary and add
the SDT events to probe cache. "sdt_" prefix is appended for
all SDT providers to avoid event-name clash with other pre-defined
events. It is possible to use the cached SDT events as other cached
events, via perf probe --add "sdt_<provider>:<event>=<event>".

e.g.
  ----
  # perf buildid-cache --add /lib/libc-2.17.so
  # perf probe --cache --list | head -n 5
  /usr/lib/libc-2.17.so (a6fb821bdf53660eb2c29f778757aef294d3d392):
  sdt_libc:setjmp=setjmp
  sdt_libc:longjmp=longjmp
  sdt_libc:longjmp_target=longjmp_target
  sdt_libc:memory_heap_new=memory_heap_new
  # perf probe -x /usr/lib/libc-2.17.so \
    -a sdt_libc:memory_heap_new=memory_heap_new
  Added new event:
    sdt_libc:memory_heap_new (on memory_heap_new
   in /usr/lib/libc-2.17.so)

  You can now use it in all perf tools, such as:

          perf record -e sdt_libc:memory_heap_new -aR sleep 1

  # perf probe -l
    sdt_libc:memory_heap_new (on new_heap+183 in /usr/lib/libc-2.17.so)
  ----

Note that SDT event entries in probe-cache file is somewhat different
from normal cached events. Normal one starts with "#", but SDTs are
starting with "%".

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 Changes in v3:
  - Use sdt_ prefix for group name
  - Use HAVE_LIBELF_SUPPORT instead of CONFIG_LIBELF
---
 tools/perf/util/build-id.c   |   27 +++++++++++++++--
 tools/perf/util/probe-file.c |   67 ++++++++++++++++++++++++++++++++++++++++--
 tools/perf/util/probe-file.h |    2 +
 3 files changed, 90 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index b68f5f0..31eb8d9 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -17,6 +17,7 @@
 #include "tool.h"
 #include "header.h"
 #include "vdso.h"
+#include "probe-file.h"
 
 
 static bool no_buildid_cache;
@@ -432,6 +433,23 @@ int build_id_cache__list_build_ids(const char *pathname,
 	return ret;
 }
 
+#ifdef HAVE_LIBELF_SUPPORT
+static void build_id_cache__add_sdt_cache(const char *sbuild_id,
+					  const char *realname)
+{
+	struct probe_cache *cache;
+
+	cache = probe_cache__new(sbuild_id);
+	if (!cache)
+		return;
+	if (probe_cache__scan_sdt(cache, realname) >= 0)
+		probe_cache__commit(cache);
+	probe_cache__delete(cache);
+}
+#else
+#define build_id_cache__add_sdt_cache(sbuild_id, realname) do { } while (0)
+#endif
+
 int build_id_cache__add_s(const char *sbuild_id, const char *name,
 			  bool is_kallsyms, bool is_vdso)
 {
@@ -470,20 +488,23 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
 			goto out_free;
 	}
 
+	/* Make a symbolic link */
 	if (!build_id_cache__linkname(sbuild_id, linkname, size))
 		goto out_free;
+
 	tmp = strrchr(linkname, '/');
 	*tmp = '\0';
-
 	if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
 		goto out_free;
-
 	*tmp = '/';
 	tmp = dir_name + strlen(buildid_dir) - 5;
 	memcpy(tmp, "../..", 5);
-
 	if (symlink(tmp, linkname) == 0)
 		err = 0;
+
+	/* Update SDT cache */
+	build_id_cache__add_sdt_cache(sbuild_id, realname);
+
 out_free:
 	if (!is_kallsyms)
 		free(realname);
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 5ee892f..7e2b4f8 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -403,9 +403,12 @@ static int probe_cache__load(struct probe_cache *pcache)
 		p = strchr(buf, '\n');
 		if (p)
 			*p = '\0';
-		if (buf[0] == '#') {	/* #perf_probe_event */
+		/* #perf_probe_event or %sdt_event */
+		if (buf[0] == '#' || buf[0] == '%') {
 			entry = probe_cache_entry__new(NULL);
 			entry->spev = strdup(buf + 1);
+			if (buf[0] == '%')
+				entry->sdt = true;
 			ret = parse_perf_probe_command(buf + 1, &entry->pev);
 			if (!entry->spev || ret < 0) {
 				probe_cache_entry__delete(entry);
@@ -577,14 +580,72 @@ out_err:
 	return ret;
 }
 
+static unsigned long long sdt_note__get_addr(struct sdt_note *note)
+{
+	return note->bit32 ? (unsigned long long)note->addr.a32[0]
+		 : (unsigned long long)note->addr.a64[0];
+}
+
+int probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname)
+{
+	struct probe_cache_entry *entry = NULL;
+	struct list_head sdtlist;
+	struct sdt_note *note;
+	char *buf;
+	char sdtgrp[64];
+	int ret;
+
+	INIT_LIST_HEAD(&sdtlist);
+	ret = get_sdt_note_list(&sdtlist, pathname);
+	if (ret < 0) {
+		pr_debug("Failed to get sdt note: %d\n", ret);
+		return ret;
+	}
+	list_for_each_entry(note, &sdtlist, note_list) {
+		ret = snprintf(sdtgrp, 64, "sdt_%s", note->provider);
+		if (ret < 0)
+			break;
+		entry = probe_cache__find_by_name(pcache, sdtgrp, note->name);
+		if (entry)	/* We've already scanned */
+			continue;
+
+		entry = probe_cache_entry__new(NULL);
+		if (!entry) {
+			ret = -ENOMEM;
+			break;
+		}
+		entry->sdt = true;
+		ret = asprintf(&entry->spev, "%s:%s=%s", sdtgrp,
+				note->name, note->name);
+		if (ret < 0)
+			break;
+		entry->pev.event = strdup(note->name);
+		entry->pev.group = strdup(note->provider);
+		ret = asprintf(&buf, "p:%s/%s %s:0x%llx",
+				sdtgrp, note->name, pathname,
+				sdt_note__get_addr(note));
+		if (ret < 0)
+			break;
+		strlist__add(entry->tevlist, buf);
+		free(buf);
+		list_add_tail(&entry->list, &pcache->list);
+		entry = NULL;
+	}
+	if (entry)
+		probe_cache_entry__delete(entry);
+	cleanup_sdt_note_list(&sdtlist);
+	return ret;
+}
+
 static int probe_cache_entry__write(struct probe_cache_entry *entry, int fd)
 {
 	struct str_node *snode;
 	struct iovec iov[3];
+	const char *prefix = entry->sdt ? "%" : "#";
 	int ret;
 
-	pr_debug("Writing cache: #%s\n", entry->spev);
-	iov[0].iov_base = (void *)"#"; iov[0].iov_len = 1;
+	pr_debug("Writing cache: %s%s\n", prefix, entry->spev);
+	iov[0].iov_base = (void *)prefix; iov[0].iov_len = 1;
 	iov[1].iov_base = entry->spev; iov[1].iov_len = strlen(entry->spev);
 	iov[2].iov_base = (void *)"\n"; iov[2].iov_len = 1;
 	ret = writev(fd, iov, 3);
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
index 391fde0..9a9b0c5 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -18,6 +18,7 @@ int probe_file__del_events(int fd, struct strfilter *filter);
 /* Cache of probe definitions */
 struct probe_cache_entry {
 	struct list_head	list;
+	bool			sdt;
 	struct perf_probe_event pev;
 	char			*spev;
 	struct strlist		*tevlist;
@@ -32,6 +33,7 @@ struct probe_cache *probe_cache__new(const char *target);
 int probe_cache__add_entry(struct probe_cache *pcache,
 			   struct perf_probe_event *pev,
 			   struct probe_trace_event *tevs, int ntevs);
+int probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname);
 int probe_cache__commit(struct probe_cache *pcache);
 void probe_cache__delete(struct probe_cache *pcache);
 int probe_cache__remove_entries(struct probe_cache *pcache,


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

* [RFC PATCH perf/core v3 14/17] perf probe: Accept %sdt and %cached event name
  2015-08-15 11:42 [RFC PATCH perf/core v3 00/17] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (12 preceding siblings ...)
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 13/17] perf buildid-cache: Scan and import user SDT events to probe cache Masami Hiramatsu
@ 2015-08-15 11:43 ` Masami Hiramatsu
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 15/17] perf-list: Show SDT events Masami Hiramatsu
                   ` (3 subsequent siblings)
  17 siblings, 0 replies; 25+ messages in thread
From: Masami Hiramatsu @ 2015-08-15 11:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, Adrian Hunter, Ingo Molnar,
	Paul Mackerras, Jiri Olsa, Namhyung Kim, Borislav Petkov,
	Hemant Kumar

To improbe usability, support %[PROVIDER:]SDTEVENT format to
add new probes on SDT and cached events.

e.g.
  ----
  # perf probe -x /lib/libc-2.17.so  %lll_lock_wait_private
  Added new event:
    sdt_libc:lll_lock_wait_private (on %lll_lock_wait_private in
  /usr/lib/libc-2.17.so)

  You can now use it in all perf tools, such as:

          perf record -e sdt_libc:lll_lock_wait_private -aR sleep 1

  # perf probe -l | more
    sdt_libc:lll_lock_wait_private (on __lll_lock_wait_private+21
   in /usr/lib/libc-2.17.so)
  ----

Note that this is not only for SDT events, but also normal
events with event-name.

e.g. define "myevent" on cache (-n doesn't add the real probe)
  ----
  # perf probe -x ./perf --cache -n --add 'myevent=dso__load $params'
  ----
  Reuse the "myevent" from cache as below.
  ----
  # perf probe -x ./perf %myevent
  ----

TODO:
 Wildcard is not supported yet.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 tools/perf/Documentation/perf-probe.txt |    3 +
 tools/perf/util/probe-event.c           |   78 ++++++++++++++++++++++---------
 tools/perf/util/probe-event.h           |    1 
 tools/perf/util/probe-file.c            |    9 ++++
 4 files changed, 69 insertions(+), 22 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 8d09173..1d38221 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -151,11 +151,14 @@ Probe points are defined by following syntax.
     3) Define event based on source file with lazy pattern
      [EVENT=]SRC;PTN [ARG ...]
 
+    4) Pre-defined SDT events
+     %[PROVIDER:]SDTEVENT
 
 'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. Currently, event group name is set as 'probe'.
 'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, ':RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. And ';PTN' means lazy matching pattern (see LAZY MATCHING). Note that ';PTN' must be the end of the probe point definition.  In addition, '@SRC' specifies a source file which has that function.
 It is also possible to specify a probe point by the source line number or lazy matching by using 'SRC:ALN' or 'SRC;PTN' syntax, where 'SRC' is the source file path, ':ALN' is the line number and ';PTN' is the lazy matching pattern.
 'ARG' specifies the arguments of this probe point, (see PROBE ARGUMENT).
+'SDTEVENT' and 'PROVIDER' is the pre-defined event name which is defined by user SDT (Statically Defined Tracing) or the pre-cached probes with event name.
 
 PROBE ARGUMENT
 --------------
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index c559f01..92e800e 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1132,6 +1132,34 @@ err:
 	return err;
 }
 
+static int parse_perf_probe_event_name(char **arg, struct perf_probe_event *pev)
+{
+	char *ptr;
+
+	ptr = strchr(*arg, ':');
+	if (ptr) {
+		*ptr = '\0';
+		if (!is_c_func_name(*arg))
+			goto ng_name;
+		pev->group = strdup(*arg);
+		if (!pev->group)
+			return -ENOMEM;
+		*arg = ptr + 1;
+	} else
+		pev->group = NULL;
+	if (!is_c_func_name(*arg)) {
+ng_name:
+		semantic_error("%s is bad for event name -it must "
+			       "follow C symbol-naming rule.\n", *arg);
+		return -EINVAL;
+	}
+	pev->event = strdup(*arg);
+	if (pev->event == NULL)
+		return -ENOMEM;
+
+	return 0;
+}
+
 /* Parse probepoint definition. */
 static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 {
@@ -1139,38 +1167,43 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 	char *ptr, *tmp;
 	char c, nc = 0;
 	bool file_spec = false;
+	int ret;
+
 	/*
 	 * <Syntax>
 	 * perf probe [GRP:][EVENT=]SRC[:LN|;PTN]
 	 * perf probe [GRP:][EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
+	 * perf probe %[GRP:]SDT_EVENT
 	 */
 	if (!arg)
 		return -EINVAL;
 
+	if (arg[0] == '%') {
+		pev->sdt = true;
+		arg++;
+	}
+
 	ptr = strpbrk(arg, ";=@+%");
-	if (ptr && *ptr == '=') {	/* Event name */
-		*ptr = '\0';
-		tmp = ptr + 1;
-		ptr = strchr(arg, ':');
+	if (pev->sdt) {
 		if (ptr) {
-			*ptr = '\0';
-			if (!is_c_func_name(arg))
-				goto not_fname;
-			pev->group = strdup(arg);
-			if (!pev->group)
-				return -ENOMEM;
-			arg = ptr + 1;
-		} else
-			pev->group = NULL;
-		if (!is_c_func_name(arg)) {
-not_fname:
-			semantic_error("%s is bad for event name -it must "
-				       "follow C symbol-naming rule.\n", arg);
+			semantic_error("%s must contain only an SDT event name.\n", arg);
 			return -EINVAL;
 		}
-		pev->event = strdup(arg);
-		if (pev->event == NULL)
-			return -ENOMEM;
+		ret = parse_perf_probe_event_name(&arg, pev);
+		if (ret == 0) {
+			if (asprintf(&pev->point.function, "%%%s", pev->event) < 0)
+				ret = -errno;
+		}
+		return ret;
+	}
+
+	if (ptr && *ptr == '=') {	/* Event name */
+		*ptr = '\0';
+		tmp = ptr + 1;
+		ret = parse_perf_probe_event_name(&arg, pev);
+		if (ret < 0)
+			return ret;
+
 		arg = tmp;
 	}
 
@@ -2620,7 +2653,8 @@ static int find_probe_trace_events_from_cache(struct perf_probe_event *pev,
 						  pev->point.function);
 	}
 	if (!entry) {
-		ret = 0;
+		/* SDT must be in the cache */
+		ret = pev->sdt ? -ENOENT : 0;
 		goto out;
 	}
 
@@ -2659,7 +2693,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
 {
 	int ret;
 
-	if (!pev->group) {
+	if (!pev->group && !pev->sdt) {
 		/* Set group name if not given */
 		if (!pev->uprobes) {
 			pev->group = strdup(PERFPROBE_GROUP);
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index fdea725..2cd60e6 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -84,6 +84,7 @@ struct perf_probe_event {
 	char			*group;	/* Group name */
 	struct perf_probe_point	point;	/* Probe point */
 	int			nargs;	/* Number of arguments */
+	bool			sdt;	/* SDT/cached event flag */
 	bool			uprobes;	/* Uprobe event flag */
 	char			*target;	/* Target binary */
 	struct perf_probe_arg	*args;	/* Arguments */
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 7e2b4f8..018c443 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -504,6 +504,15 @@ probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev)
 		return NULL;
 
 	list_for_each_entry(entry, &pcache->list, list) {
+		if (pev->sdt) {
+			if (entry->pev.event &&
+			    streql(entry->pev.event, pev->event) &&
+			    (!pev->group ||
+			     streql(entry->pev.group, pev->group)))
+				goto found;
+
+			continue;
+		}
 		/* Hit if same event name or same command-string */
 		if ((pev->event &&
 		     (streql(entry->pev.group, pev->group) &&


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

* [RFC PATCH perf/core v3 15/17] perf-list: Show SDT events
  2015-08-15 11:42 [RFC PATCH perf/core v3 00/17] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (13 preceding siblings ...)
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 14/17] perf probe: Accept %sdt and %cached event name Masami Hiramatsu
@ 2015-08-15 11:43 ` Masami Hiramatsu
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 16/17] perf-list: Skip SDTs placed in invalid binaries Masami Hiramatsu
                   ` (2 subsequent siblings)
  17 siblings, 0 replies; 25+ messages in thread
From: Masami Hiramatsu @ 2015-08-15 11:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, Adrian Hunter, Ingo Molnar,
	Paul Mackerras, Jiri Olsa, Namhyung Kim, Borislav Petkov,
	Hemant Kumar

Show SDT events by perf-list as below.

  ----
  # perf list sdt | head -n 7

  List of pre-defined events (to be used in -e):

    sdt_libc:lll_futex_wake                            [SDT event]
    sdt_libc:lll_lock_wait_private                     [SDT event]
    sdt_libc:longjmp                                   [SDT event]
    sdt_libc:longjmp_target                            [SDT event]
  ----

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 tools/perf/builtin-list.c      |    3 +
 tools/perf/util/parse-events.c |   83 ++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/parse-events.h |    2 +
 3 files changed, 88 insertions(+)

diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index af5bd05..85331e1 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -60,6 +60,8 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
 			print_hwcache_events(NULL, raw_dump);
 		else if (strcmp(argv[i], "pmu") == 0)
 			print_pmu_events(NULL, raw_dump);
+		else if (strcmp(argv[i], "sdt") == 0)
+			print_sdt_events(NULL, NULL, raw_dump);
 		else {
 			char *sep = strchr(argv[i], ':'), *s;
 			int sep_idx;
@@ -75,6 +77,7 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
 
 			s[sep_idx] = '\0';
 			print_tracepoint_events(s, s + sep_idx + 1, raw_dump);
+			print_sdt_events(s, s + sep_idx + 1, raw_dump);
 			free(s);
 		}
 	}
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index d826e6f..485dbdc 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -5,6 +5,7 @@
 #include "evsel.h"
 #include "parse-options.h"
 #include "parse-events.h"
+#include "probe-file.h"
 #include "exec_cmd.h"
 #include "string.h"
 #include "symbol.h"
@@ -1519,6 +1520,86 @@ static bool is_event_supported(u8 type, unsigned config)
 	return ret;
 }
 
+void print_sdt_events(const char *subsys_glob, const char *event_glob,
+		      bool name_only)
+{
+	struct probe_cache *pcache;
+	struct probe_cache_entry *ent;
+	struct strlist *bidlist, *sdtlist;
+	struct strlist_config cfg = {.dont_dupstr = true};
+	struct str_node *nd, *nd2;
+	char *buf, *path, *ptr = NULL;
+	bool show_detail = false;
+	int ret;
+
+	sdtlist = strlist__new(NULL, &cfg);
+	if (!sdtlist) {
+		pr_debug("Failed to allocate new strlist for SDT\n");
+		return;
+	}
+	ret = build_id_cache__list_all(&bidlist);
+	if (ret < 0) {
+		pr_debug("Failed to get buildids: %d\n", ret);
+		return;
+	}
+	strlist__for_each(nd, bidlist) {
+		pcache = probe_cache__new(nd->s);
+		if (!pcache)
+			continue;
+		if (!list_empty(&pcache->list))
+			list_for_each_entry(ent, &pcache->list, list) {
+				if (!ent->sdt)
+					continue;
+				if (subsys_glob &&
+				    !strglobmatch(ent->pev.group, subsys_glob))
+					continue;
+				if (event_glob &&
+				    !strglobmatch(ent->pev.event, event_glob))
+					continue;
+				ret = asprintf(&buf, "%s:%s@%s", ent->pev.group,
+						ent->pev.event, nd->s);
+				if (ret > 0)
+					strlist__add(sdtlist, buf);
+			}
+		probe_cache__delete(pcache);
+	}
+	strlist__delete(bidlist);
+
+	strlist__for_each(nd, sdtlist) {
+		buf = strchr(nd->s, '@');
+		if (buf)
+			*buf = '\0';
+		if (name_only) {
+			printf("%s ", nd->s);
+			continue;
+		}
+		nd2 = strlist__next(nd);
+		if (nd2) {
+			ptr = strchr(nd2->s, '@');
+			if (ptr)
+				*ptr = '\0';
+			if (strcmp(nd->s, nd2->s) == 0)
+				show_detail = true;
+		}
+		if (show_detail) {
+			path = build_id_cache__origname(buf + 1);
+			ret = asprintf(&buf, "%s@%s@0x%.12s", nd->s, path, buf + 1);
+			if (ret > 0) {
+				printf("  %-50s [%s]\n", buf, "SDT event");
+				free(buf);
+			}
+		} else
+			printf("  %-50s [%s]\n", nd->s, "SDT event");
+		if (nd2) {
+			if (strcmp(nd->s, nd2->s) != 0)
+				show_detail = false;
+			if (ptr)
+				*ptr = '@';
+		}
+	}
+	strlist__delete(sdtlist);
+}
+
 int print_hwcache_events(const char *event_glob, bool name_only)
 {
 	unsigned int type, op, i, evt_i = 0, evt_num = 0;
@@ -1700,6 +1781,8 @@ void print_events(const char *event_glob, bool name_only)
 	}
 
 	print_tracepoint_events(NULL, NULL, name_only);
+
+	print_sdt_events(NULL, NULL, name_only);
 }
 
 int parse_events__is_hardcoded_term(struct parse_events_term *term)
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index a09b0e2..5dc631d 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -151,6 +151,8 @@ void print_symbol_events(const char *event_glob, unsigned type,
 				bool name_only);
 void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
 			     bool name_only);
+void print_sdt_events(const char *subsys_glob, const char *event_glob,
+		      bool name_only);
 int print_hwcache_events(const char *event_glob, bool name_only);
 extern int is_valid_tracepoint(const char *event_string);
 


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

* [RFC PATCH perf/core v3 16/17] perf-list: Skip SDTs placed in invalid binaries
  2015-08-15 11:42 [RFC PATCH perf/core v3 00/17] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (14 preceding siblings ...)
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 15/17] perf-list: Show SDT events Masami Hiramatsu
@ 2015-08-15 11:43 ` Masami Hiramatsu
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 17/17] perf record: Support recording SDT events Masami Hiramatsu
  2015-08-19  8:30 ` [RFC PATCH perf/core v3 00/17] perf-probe --cache and SDT support Namhyung Kim
  17 siblings, 0 replies; 25+ messages in thread
From: Masami Hiramatsu @ 2015-08-15 11:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, Adrian Hunter, Ingo Molnar,
	Paul Mackerras, Jiri Olsa, Namhyung Kim, Borislav Petkov,
	Hemant Kumar

Skip SDTs placed in invalid (non-exist, or older version)
binaries. Note that perf-probe --cache --list still shows
all the caches including invalid binaries.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 tools/perf/util/build-id.c     |   27 ++++++++++++++++++++++++++-
 tools/perf/util/build-id.h     |    2 +-
 tools/perf/util/parse-events.c |    2 +-
 tools/perf/util/probe-event.c  |    2 +-
 tools/perf/util/probe-file.c   |    2 +-
 5 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 31eb8d9..7635e66 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -178,6 +178,25 @@ out:
 	return ret;
 }
 
+static bool build_id_cache__valid_id(char *sbuild_id)
+{
+	char real_sbuild_id[SBUILD_ID_SIZE] = "";
+	char *pathname;
+	bool ret;
+
+	pathname = build_id_cache__origname(sbuild_id);
+	if (!pathname)
+		return false;
+
+	if (filename__sprintf_build_id(pathname, real_sbuild_id) < 0)
+		ret = false;
+	else
+		ret = (strcmp(sbuild_id, real_sbuild_id) == 0);
+	free(pathname);
+
+	return ret;
+}
+
 static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso)
 {
 	return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf");
@@ -336,7 +355,7 @@ void disable_buildid_cache(void)
 	no_buildid_cache = true;
 }
 
-int build_id_cache__list_all(struct strlist **result)
+int build_id_cache__list_all(struct strlist **result, bool valid)
 {
 	struct strlist *toplist, *list, *bidlist;
 	struct str_node *nd, *nd2;
@@ -344,6 +363,10 @@ int build_id_cache__list_all(struct strlist **result)
 	char sbuild_id[SBUILD_ID_SIZE];
 	int ret = 0;
 
+	/* for filename__ functions */
+	if (valid)
+		symbol__init(NULL);
+
 	/* Open the top-level directory */
 	if (asprintf(&topdir, "%s/.build-id/", buildid_dir) < 0)
 		return -errno;
@@ -373,6 +396,8 @@ int build_id_cache__list_all(struct strlist **result)
 					nd->s, nd2->s);
 				continue;
 			}
+			if (valid && !build_id_cache__valid_id(sbuild_id))
+				continue;
 			strlist__add(bidlist, sbuild_id);
 		}
 		strlist__delete(list);
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index 2d5c61c..1bf90ab 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -31,7 +31,7 @@ char *build_id_cache__origname(const char *sbuild_id);
 char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size);
 char *build_id_cache__dirname_from_path(const char *sbuild_id, const char *name,
 					bool is_kallsyms, bool is_vdso);
-int build_id_cache__list_all(struct strlist **result);
+int build_id_cache__list_all(struct strlist **result, bool valid);
 int build_id_cache__list_build_ids(const char *pathname,
 				   struct strlist **result);
 bool build_id_cache__cached(const char *sbuild_id);
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 485dbdc..a19f7f9 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1537,7 +1537,7 @@ void print_sdt_events(const char *subsys_glob, const char *event_glob,
 		pr_debug("Failed to allocate new strlist for SDT\n");
 		return;
 	}
-	ret = build_id_cache__list_all(&bidlist);
+	ret = build_id_cache__list_all(&bidlist, true);
 	if (ret < 0) {
 		pr_debug("Failed to get buildids: %d\n", ret);
 		return;
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 92e800e..d2fa266 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -2792,7 +2792,7 @@ static int del_perf_probe_caches(struct strfilter *filter)
 	struct str_node *nd;
 	int ret;
 
-	ret = build_id_cache__list_all(&bidlist);
+	ret = build_id_cache__list_all(&bidlist, false);
 	if (ret < 0) {
 		pr_debug("Failed to get buildids: %d\n", ret);
 		return ret;
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 018c443..70a6a5c 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -745,7 +745,7 @@ int probe_cache__show_all_caches(struct strfilter *filter)
 	pr_debug("list cache with filter: %s\n", buf);
 	free(buf);
 
-	ret = build_id_cache__list_all(&bidlist);
+	ret = build_id_cache__list_all(&bidlist, false);
 	if (ret < 0) {
 		pr_debug("Failed to get buildids: %d\n", ret);
 		return ret == -ENOENT ? 0 : ret;


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

* [RFC PATCH perf/core v3 17/17] perf record: Support recording SDT events
  2015-08-15 11:42 [RFC PATCH perf/core v3 00/17] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (15 preceding siblings ...)
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 16/17] perf-list: Skip SDTs placed in invalid binaries Masami Hiramatsu
@ 2015-08-15 11:43 ` Masami Hiramatsu
  2015-08-19  8:30 ` [RFC PATCH perf/core v3 00/17] perf-probe --cache and SDT support Namhyung Kim
  17 siblings, 0 replies; 25+ messages in thread
From: Masami Hiramatsu @ 2015-08-15 11:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, Adrian Hunter, Ingo Molnar,
	Paul Mackerras, Jiri Olsa, Namhyung Kim, Borislav Petkov,
	Hemant Kumar

perf record -e "sdt_PROVIDER:EVENT" is available as same as
other tracepoint events.
In this version, the wildcard and @filename or build-id are not
supported yet.

Note that this doesn't clear (unregister) probe event after recorded
events, since that can skip to register same event next time and
anyway we can not unregister it if someone use the event via ftrace.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 tools/perf/builtin-probe.c     |    3 --
 tools/perf/util/parse-events.c |   59 +++++++++++++++++++++++++++++++++++++++-
 tools/perf/util/probe-event.c  |   18 ++++++++----
 tools/perf/util/probe-event.h  |    1 +
 4 files changed, 70 insertions(+), 11 deletions(-)

diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 5d0c246..a94e54f 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -441,9 +441,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
 		verbose = -1;
 	}
 
-	if (probe_conf.max_probes == 0)
-		probe_conf.max_probes = MAX_PROBES;
-
 	/*
 	 * Only consider the user's kernel image path if given.
 	 */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index a19f7f9..36d88f0 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -473,8 +473,8 @@ static int add_tracepoint_multi_sys(struct list_head *list, int *idx,
 	return ret;
 }
 
-int parse_events_add_tracepoint(struct list_head *list, int *idx,
-				char *sys, char *event)
+static int __parse_events_add_tracepoint(struct list_head *list, int *idx,
+					 char *sys, char *event)
 {
 	if (strpbrk(sys, "*?"))
 		return add_tracepoint_multi_sys(list, idx, sys, event);
@@ -482,6 +482,61 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx,
 		return add_tracepoint_event(list, idx, sys, event);
 }
 
+static int activate_sdt_events(char *sys, char *event)
+{
+	struct probe_cache *cache;
+	struct probe_cache_entry *entry;
+	struct strlist *bidlist;
+	struct str_node *nd;
+	struct perf_probe_event pev;
+	char *path = NULL;
+	int ret;
+
+	ret = build_id_cache__list_all(&bidlist, true);
+	if (ret < 0) {
+		pr_debug("Failed to get buildids: %d\n", ret);
+		return ret;
+	}
+
+	strlist__for_each(nd, bidlist) {
+		cache = probe_cache__new(nd->s);
+		if (!cache)
+			continue;
+		entry = probe_cache__find_by_name(cache, sys, event);
+		probe_cache__delete(cache);
+		if (entry) {
+			path = build_id_cache__origname(nd->s);
+			break;
+		}
+	}
+	if (!path) {
+		pr_debug("Failed to find %s:%s in probe cache\n", sys, event);
+		return -ENOENT;
+	}
+
+	memset(&pev, 0, sizeof(pev));
+	pev.point.function = event;
+	pev.event = event;
+	pev.group = sys;
+	pev.sdt = true;
+	pev.uprobes = true;
+	pev.target = path;
+	probe_conf.internal_call = true;
+	ret = add_perf_probe_events(&pev, 1);
+	free(path);
+	return ret;
+}
+
+int parse_events_add_tracepoint(struct list_head *list, int *idx,
+				char *sys, char *event)
+{
+	int ret = __parse_events_add_tracepoint(list, idx, sys, event);
+	/* Retry with activating SDTs */
+	if (ret < 0 && activate_sdt_events(sys, event) > 0)
+		return  __parse_events_add_tracepoint(list, idx, sys, event);
+	return ret;
+}
+
 static int
 parse_breakpoint_type(const char *type, struct perf_event_attr *attr)
 {
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index d2fa266..ecb953c 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -52,7 +52,9 @@
 #define PERFPROBE_GROUP "probe"
 
 bool probe_event_dry_run;	/* Dry run flag */
-struct probe_conf probe_conf;
+struct probe_conf probe_conf = {
+	.max_probes = MAX_PROBES,
+};
 
 #define semantic_error(msg ...) pr_err("Semantic error :" msg)
 
@@ -2404,7 +2406,8 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
 	}
 
 	ret = 0;
-	pr_info("Added new event%s\n", (ntevs > 1) ? "s:" : ":");
+	if (!probe_conf.internal_call)
+		pr_info("Added new event%s\n", (ntevs > 1) ? "s:" : ":");
 	for (i = 0; i < ntevs; i++) {
 		tev = &tevs[i];
 		/* Skip if the symbol is out of .text or blacklisted */
@@ -2422,8 +2425,9 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
 			break;
 
 		/* We use tev's name for showing new events */
-		show_perf_probe_event(tev->group, tev->event, pev,
-				      tev->point.module, false);
+		if (!probe_conf.internal_call)
+			show_perf_probe_event(tev->group, tev->event, pev,
+					      tev->point.module, false);
 		/* Save the last valid name */
 		event = tev->event;
 		group = tev->group;
@@ -2452,8 +2456,10 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
 			}
 		}
 		/* Show how to use the event. */
-		pr_info("\nYou can now use it in all perf tools, such as:\n\n");
-		pr_info("\tperf record -e %s:%s -aR sleep 1\n\n", group, event);
+		if (!probe_conf.internal_call) {
+			pr_info("\nYou can now use it in all perf tools, such as:\n\n");
+			pr_info("\tperf record -e %s:%s -aR sleep 1\n\n", group, event);
+		}
 	}
 
 	strlist__delete(namelist);
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 2cd60e6..8cab4a6 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -13,6 +13,7 @@ struct probe_conf {
 	bool	force_add;
 	bool	no_inlines;
 	bool	cache;
+	bool	internal_call;	/* Internal use */
 	int	max_probes;
 };
 extern struct probe_conf probe_conf;


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

* Re: [RFC PATCH perf/core v3 00/17] perf-probe --cache and SDT support
  2015-08-15 11:42 [RFC PATCH perf/core v3 00/17] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (16 preceding siblings ...)
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 17/17] perf record: Support recording SDT events Masami Hiramatsu
@ 2015-08-19  8:30 ` Namhyung Kim
  2015-08-19 15:15   ` 平松雅巳 / HIRAMATU,MASAMI
  17 siblings, 1 reply; 25+ messages in thread
From: Namhyung Kim @ 2015-08-19  8:30 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, linux-kernel,
	Adrian Hunter, Ingo Molnar, Paul Mackerras, Jiri Olsa,
	Borislav Petkov, Hemant Kumar

Hi Masami,

On Sat, Aug 15, 2015 at 08:42:53PM +0900, Masami Hiramatsu wrote:
> Hi,
> 
> Here is the 3rd version of the patchset for probe-cache and 
> initial SDT support which are going to be perf-cache finally.
> 
> The previous version is here; https://lkml.org/lkml/2015/7/15/221
> 
> This version improves SDT support for perf-list and perf-record.
> It is still just a basic support (no wildcard support, nor
> @FILE/@BUILDID support). So this is an ongoing work report :)
> 
> As we discussed on the previous series, now all SDT events have
> "sdt_" prefix on the provider name. We also should support "@FILE"
> or "@BUILDID" suffixes for same-name SDTs.
> 
> perf-list shows only SDTs on existing binaries (no old/deleted
> files) and if the same-name events are shown, it adds 
> "@FILE@BUILDID" suffixes after the events to clarify on which
> binary the SDT exists.
> 
>   ----
>   # perf buildid-cache -a /usr/bin/gcc
>   # perf list sdt
> 
>   List of pre-defined events (to be used in -e):
> 
>     sdt_libgcc:unwind                                  [SDT event]
>     sdt_libstdcxx:catch                                [SDT event]
>     sdt_libstdcxx:rethrow                              [SDT event]
>     sdt_libstdcxx:throw                                [SDT event]
>   # perf buildid-cache -a /usr/lib/libstdc++.so.6
>   # perf list sdt
> 
>   List of pre-defined events (to be used in -e):
> 
>     sdt_libgcc:unwind                                  [SDT event]
>     sdt_libstdcxx:catch@/usr/bin/gcc@0x05d261236bbb    [SDT event]
>     sdt_libstdcxx:catch@/usr/lib/libstdc++.so.6.0.19@0xcd6ac0e6236c [SDT event]
>     sdt_libstdcxx:rethrow@/usr/bin/gcc@0x05d261236bbb  [SDT event]
>     sdt_libstdcxx:rethrow@/usr/lib/libstdc++.so.6.0.19@0xcd6ac0e6236c [SDT event]
>     sdt_libstdcxx:throw@/usr/bin/gcc@0x05d261236bbb    [SDT event]
>     sdt_libstdcxx:throw@/usr/lib/libstdc++.so.6.0.19@0xcd6ac0e6236c [SDT event]
>   ----
> 
> In this version, I used "@" separater for both FILE and BUILDID,
> but I think it is also possible to use "%" for BUILDID.
> (BTW, I've cut down the BUILDID to the first 12 chars, and added "0x") 
> 
> TODOs:
>  - (perf record) Allow glob matching for SDT event to specify events.
>  - (perf record) Support @FILE/@BUILDID suffix to record specific SDTs.
>  - (perf record) Try to unregister SDT events after record.
>  - (perf probe) Allow glob matching for pre-cached events.
>  - (perf probe) Support @FILE/@BUILDID suffix for pre-cached events.
>                (also removes -x option when using pre-cached events)
>  - (ftrace) Support multiple SDTs on single event.
> 
> Since multiple same SDTs are defined in a single binary (e.g. libc:setjump
> has 3 different entries on libc-2.17.so), we need the last feature on
> ftrace, so that a single uprobe event can occur several different
> probe points.

Do you want to have multiple events of same name in the kernel?  Or
to make perf handle those same names with different kernel events?

Thanks,
Namhyung

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

* RE: Re: [RFC PATCH perf/core v3 00/17] perf-probe --cache and SDT support
  2015-08-19  8:30 ` [RFC PATCH perf/core v3 00/17] perf-probe --cache and SDT support Namhyung Kim
@ 2015-08-19 15:15   ` 平松雅巳 / HIRAMATU,MASAMI
  0 siblings, 0 replies; 25+ messages in thread
From: 平松雅巳 / HIRAMATU,MASAMI @ 2015-08-19 15:15 UTC (permalink / raw)
  To: 'Namhyung Kim'
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, linux-kernel,
	Adrian Hunter, Ingo Molnar, Paul Mackerras, Jiri Olsa,
	Borislav Petkov, Hemant Kumar

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 1246 bytes --]

Hi Namhyung,

> From: Namhyung Kim [mailto:namhyung@gmail.com] On Behalf Of Namhyung Kim
> >  - (ftrace) Support multiple SDTs on single event.
> >
> > Since multiple same SDTs are defined in a single binary (e.g. libc:setjump
> > has 3 different entries on libc-2.17.so), we need the last feature on
> > ftrace, so that a single uprobe event can occur several different
> > probe points.
> 
> Do you want to have multiple events of same name in the kernel?  Or
> to make perf handle those same names with different kernel events?

Good point, I meant the former. But the latter is also possible.

Here is my idea;

Suppose to define an event "foo" at "bar" function + 10byte offset with
2 arguments as below:
 # echo p:foo bar+10 arg1=%ax arg2=%dx > kprobe_events

To add a probe point on the same event, use "+p" or "+r" instead of "p" or "r"
and we can also change the assignment for each argument.
 # echo +p:foo bar+20 arg1=%cx arg2=0 >> kprobe_events

Also, I guess we'll need to support a fixed value assignment because sometimes
local valiables are optimized out.

Thank you,


ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

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

* Re: [RFC PATCH perf/core v3 01/17] perf probe: Use strbuf for making strings in probe-event.c
  2015-08-15 11:42 ` [RFC PATCH perf/core v3 01/17] perf probe: Use strbuf for making strings in probe-event.c Masami Hiramatsu
@ 2015-08-28 15:56   ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 25+ messages in thread
From: Arnaldo Carvalho de Melo @ 2015-08-28 15:56 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Peter Zijlstra, linux-kernel, Adrian Hunter, Ingo Molnar,
	Paul Mackerras, Jiri Olsa, Namhyung Kim, Borislav Petkov,
	Hemant Kumar

Em Sat, Aug 15, 2015 at 08:42:55PM +0900, Masami Hiramatsu escreveu:
> Replace many fixed-length char array with strbuf to
> stringify perf_probe_event and probe_trace_event etc. in
> util/probe-event.c.

Doesn't apply to perf/core.

- Arnaldo
 
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> ---
> Changes in v3:
>  - Remove unneeded strbuf_release(). (Thanks Namhyung!)
> 
> Changes in v2:
>  - Make perf_probe_event__sprintf() simpler.
> ---
>  tools/perf/util/probe-event.c  |  238 ++++++++++++++--------------------------
>  tools/perf/util/probe-event.h  |    3 -
>  tools/perf/util/probe-finder.c |   14 +-
>  3 files changed, 90 insertions(+), 165 deletions(-)
> 
> diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
> index fe4941a..be417ee 100644
> --- a/tools/perf/util/probe-event.c
> +++ b/tools/perf/util/probe-event.c
> @@ -1562,69 +1562,51 @@ out:
>  }
>  
>  /* Compose only probe arg */
> -int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
> +char *synthesize_perf_probe_arg(struct perf_probe_arg *pa)
>  {
>  	struct perf_probe_arg_field *field = pa->field;
> -	int ret;
> -	char *tmp = buf;
> +	struct strbuf buf;
> +	char *ret;
>  
> +	strbuf_init(&buf, 64);
>  	if (pa->name && pa->var)
> -		ret = e_snprintf(tmp, len, "%s=%s", pa->name, pa->var);
> +		strbuf_addf(&buf, "%s=%s", pa->name, pa->var);
>  	else
> -		ret = e_snprintf(tmp, len, "%s", pa->name ? pa->name : pa->var);
> -	if (ret <= 0)
> -		goto error;
> -	tmp += ret;
> -	len -= ret;
> +		strbuf_addstr(&buf, pa->name ?: pa->var);
>  
>  	while (field) {
>  		if (field->name[0] == '[')
> -			ret = e_snprintf(tmp, len, "%s", field->name);
> +			strbuf_addstr(&buf, field->name);
>  		else
> -			ret = e_snprintf(tmp, len, "%s%s",
> -					 field->ref ? "->" : ".", field->name);
> -		if (ret <= 0)
> -			goto error;
> -		tmp += ret;
> -		len -= ret;
> +			strbuf_addf(&buf, "%s%s", field->ref ? "->" : ".",
> +				    field->name);
>  		field = field->next;
>  	}
>  
> -	if (pa->type) {
> -		ret = e_snprintf(tmp, len, ":%s", pa->type);
> -		if (ret <= 0)
> -			goto error;
> -		tmp += ret;
> -		len -= ret;
> -	}
> +	if (pa->type)
> +		strbuf_addf(&buf, ":%s", pa->type);
> +
> +	ret = strbuf_detach(&buf, NULL);
>  
> -	return tmp - buf;
> -error:
> -	pr_debug("Failed to synthesize perf probe argument: %d\n", ret);
>  	return ret;
>  }
>  
>  /* Compose only probe point (not argument) */
>  static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
>  {
> -	char *buf, *tmp;
> -	char offs[32] = "", line[32] = "", file[32] = "";
> -	int ret, len;
> -
> -	buf = zalloc(MAX_CMDLEN);
> -	if (buf == NULL) {
> -		ret = -ENOMEM;
> -		goto error;
> -	}
> -	if (pp->offset) {
> -		ret = e_snprintf(offs, 32, "+%lu", pp->offset);
> -		if (ret <= 0)
> -			goto error;
> -	}
> -	if (pp->line) {
> -		ret = e_snprintf(line, 32, ":%d", pp->line);
> -		if (ret <= 0)
> -			goto error;
> +	struct strbuf buf;
> +	char *tmp;
> +	int len;
> +
> +	strbuf_init(&buf, 64);
> +	if (pp->function) {
> +		strbuf_addstr(&buf, pp->function);
> +		if (pp->offset)
> +			strbuf_addf(&buf, "+%lu", pp->offset);
> +		else if (pp->line)
> +			strbuf_addf(&buf, ":%d", pp->line);
> +		else if (pp->retprobe)
> +			strbuf_addstr(&buf, "%return");
>  	}
>  	if (pp->file) {
>  		tmp = pp->file;
> @@ -1633,25 +1615,12 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
>  			tmp = strchr(pp->file + len - 30, '/');
>  			tmp = tmp ? tmp + 1 : pp->file + len - 30;
>  		}
> -		ret = e_snprintf(file, 32, "@%s", tmp);
> -		if (ret <= 0)
> -			goto error;
> +		strbuf_addf(&buf, "@%s", tmp);
> +		if (!pp->function && pp->line)
> +			strbuf_addf(&buf, ":%d", pp->line);
>  	}
>  
> -	if (pp->function)
> -		ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s%s", pp->function,
> -				 offs, pp->retprobe ? "%return" : "", line,
> -				 file);
> -	else
> -		ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", file, line);
> -	if (ret <= 0)
> -		goto error;
> -
> -	return buf;
> -error:
> -	pr_debug("Failed to synthesize perf probe point: %d\n", ret);
> -	free(buf);
> -	return NULL;
> +	return strbuf_detach(&buf, NULL);
>  }
>  
>  #if 0
> @@ -1680,45 +1649,30 @@ char *synthesize_perf_probe_command(struct perf_probe_event *pev)
>  #endif
>  
>  static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref,
> -					     char **buf, size_t *buflen,
> -					     int depth)
> +					    struct strbuf *buf, int depth)
>  {
> -	int ret;
>  	if (ref->next) {
>  		depth = __synthesize_probe_trace_arg_ref(ref->next, buf,
> -							 buflen, depth + 1);
> +							 depth + 1);
>  		if (depth < 0)
>  			goto out;
>  	}
> -
> -	ret = e_snprintf(*buf, *buflen, "%+ld(", ref->offset);
> -	if (ret < 0)
> -		depth = ret;
> -	else {
> -		*buf += ret;
> -		*buflen -= ret;
> -	}
> +	strbuf_addf(buf, "%+ld(", ref->offset);
>  out:
>  	return depth;
> -
>  }
>  
>  static int synthesize_probe_trace_arg(struct probe_trace_arg *arg,
> -				       char *buf, size_t buflen)
> +				      struct strbuf *buf)
>  {
>  	struct probe_trace_arg_ref *ref = arg->ref;
> -	int ret, depth = 0;
> -	char *tmp = buf;
> +	int depth = 0;
>  
>  	/* Argument name or separator */
>  	if (arg->name)
> -		ret = e_snprintf(buf, buflen, " %s=", arg->name);
> +		strbuf_addf(buf, " %s=", arg->name);
>  	else
> -		ret = e_snprintf(buf, buflen, " ");
> -	if (ret < 0)
> -		return ret;
> -	buf += ret;
> -	buflen -= ret;
> +		strbuf_addch(buf, ' ');
>  
>  	/* Special case: @XXX */
>  	if (arg->value[0] == '@' && arg->ref)
> @@ -1726,86 +1680,58 @@ static int synthesize_probe_trace_arg(struct probe_trace_arg *arg,
>  
>  	/* Dereferencing arguments */
>  	if (ref) {
> -		depth = __synthesize_probe_trace_arg_ref(ref, &buf,
> -							  &buflen, 1);
> +		depth = __synthesize_probe_trace_arg_ref(ref, buf, 1);
>  		if (depth < 0)
>  			return depth;
>  	}
>  
>  	/* Print argument value */
>  	if (arg->value[0] == '@' && arg->ref)
> -		ret = e_snprintf(buf, buflen, "%s%+ld", arg->value,
> -				 arg->ref->offset);
> +		strbuf_addf(buf, "%s%+ld", arg->value, arg->ref->offset);
>  	else
> -		ret = e_snprintf(buf, buflen, "%s", arg->value);
> -	if (ret < 0)
> -		return ret;
> -	buf += ret;
> -	buflen -= ret;
> +		strbuf_addstr(buf, arg->value);
>  
>  	/* Closing */
> -	while (depth--) {
> -		ret = e_snprintf(buf, buflen, ")");
> -		if (ret < 0)
> -			return ret;
> -		buf += ret;
> -		buflen -= ret;
> -	}
> +	while (depth--)
> +		strbuf_addch(buf, ')');
>  	/* Print argument type */
> -	if (arg->type) {
> -		ret = e_snprintf(buf, buflen, ":%s", arg->type);
> -		if (ret <= 0)
> -			return ret;
> -		buf += ret;
> -	}
> +	if (arg->type)
> +		strbuf_addf(buf, ":%s", arg->type);
>  
> -	return buf - tmp;
> +	return 0;
>  }
>  
>  char *synthesize_probe_trace_command(struct probe_trace_event *tev)
>  {
>  	struct probe_trace_point *tp = &tev->point;
> -	char *buf;
> -	int i, len, ret;
> -
> -	buf = zalloc(MAX_CMDLEN);
> -	if (buf == NULL)
> -		return NULL;
> -
> -	len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s ", tp->retprobe ? 'r' : 'p',
> -			 tev->group, tev->event);
> -	if (len <= 0)
> -		goto error;
> +	struct strbuf buf;
> +	char *ret = NULL;
> +	int i;
>  
>  	/* Uprobes must have tp->address and tp->module */
>  	if (tev->uprobes && (!tp->address || !tp->module))
> -		goto error;
> +		return NULL;
> +
> +	strbuf_init(&buf, 32);
> +	strbuf_addf(&buf, "%c:%s/%s ", tp->retprobe ? 'r' : 'p',
> +		    tev->group, tev->event);
>  
>  	/* Use the tp->address for uprobes */
>  	if (tev->uprobes)
> -		ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s:0x%lx",
> -				 tp->module, tp->address);
> +		strbuf_addf(&buf, "%s:0x%lx", tp->module, tp->address);
>  	else
> -		ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s%s%s+%lu",
> -				 tp->module ?: "", tp->module ? ":" : "",
> -				 tp->symbol, tp->offset);
> -
> -	if (ret <= 0)
> -		goto error;
> -	len += ret;
> +		strbuf_addf(&buf, "%s%s%s+%lu", tp->module ?: "",
> +			    tp->module ? ":" : "", tp->symbol, tp->offset);
>  
>  	for (i = 0; i < tev->nargs; i++) {
> -		ret = synthesize_probe_trace_arg(&tev->args[i], buf + len,
> -						  MAX_CMDLEN - len);
> -		if (ret <= 0)
> +		if (synthesize_probe_trace_arg(&tev->args[i], &buf) < 0)
>  			goto error;
> -		len += ret;
>  	}
>  
> -	return buf;
> +	ret = strbuf_detach(&buf, NULL);
>  error:
> -	free(buf);
> -	return NULL;
> +	strbuf_release(&buf);
> +	return ret;
>  }
>  
>  static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
> @@ -1883,7 +1809,7 @@ static int convert_to_perf_probe_point(struct probe_trace_point *tp,
>  static int convert_to_perf_probe_event(struct probe_trace_event *tev,
>  			       struct perf_probe_event *pev, bool is_kprobe)
>  {
> -	char buf[64] = "";
> +	struct strbuf buf = STRBUF_INIT;
>  	int i, ret;
>  
>  	/* Convert event/group name */
> @@ -1906,9 +1832,9 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,
>  		if (tev->args[i].name)
>  			pev->args[i].name = strdup(tev->args[i].name);
>  		else {
> -			ret = synthesize_probe_trace_arg(&tev->args[i],
> -							  buf, 64);
> -			pev->args[i].name = strdup(buf);
> +			strbuf_init(&buf, 32);
> +			ret = synthesize_probe_trace_arg(&tev->args[i], &buf);
> +			pev->args[i].name = strbuf_detach(&buf, NULL);
>  		}
>  		if (pev->args[i].name == NULL && ret >= 0)
>  			ret = -ENOMEM;
> @@ -2086,37 +2012,37 @@ static int perf_probe_event__sprintf(const char *group, const char *event,
>  				     const char *module,
>  				     struct strbuf *result)
>  {
> -	int i, ret;
> -	char buf[128];
> -	char *place;
> +	int i;
> +	char *buf;
>  
> -	/* Synthesize only event probe point */
> -	place = synthesize_perf_probe_point(&pev->point);
> -	if (!place)
> -		return -EINVAL;
> +	if (asprintf(&buf, "%s:%s", group, event) < 0)
> +		return -errno;
> +	strbuf_addf(result, "  %-20s (on ", buf);
> +	free(buf);
>  
> -	ret = e_snprintf(buf, 128, "%s:%s", group, event);
> -	if (ret < 0)
> -		goto out;
> +	/* Synthesize only event probe point */
> +	buf = synthesize_perf_probe_point(&pev->point);
> +	if (!buf)
> +		return -ENOMEM;
> +	strbuf_addstr(result, buf);
> +	free(buf);
>  
> -	strbuf_addf(result, "  %-20s (on %s", buf, place);
>  	if (module)
>  		strbuf_addf(result, " in %s", module);
>  
>  	if (pev->nargs > 0) {
>  		strbuf_addstr(result, " with");
>  		for (i = 0; i < pev->nargs; i++) {
> -			ret = synthesize_perf_probe_arg(&pev->args[i],
> -							buf, 128);
> -			if (ret < 0)
> -				goto out;
> +			buf = synthesize_perf_probe_arg(&pev->args[i]);
> +			if (!buf)
> +				return -ENOMEM;
>  			strbuf_addf(result, " %s", buf);
> +			free(buf);
>  		}
>  	}
>  	strbuf_addch(result, ')');
> -out:
> -	free(place);
> -	return ret;
> +
> +	return 0;
>  }
>  
>  /* Show an event */
> diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
> index 83ee95e..50216ff 100644
> --- a/tools/perf/util/probe-event.h
> +++ b/tools/perf/util/probe-event.h
> @@ -117,8 +117,7 @@ extern int parse_probe_trace_command(const char *cmd,
>  /* Events to command string */
>  extern char *synthesize_perf_probe_command(struct perf_probe_event *pev);
>  extern char *synthesize_probe_trace_command(struct probe_trace_event *tev);
> -extern int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf,
> -				     size_t len);
> +extern char *synthesize_perf_probe_arg(struct perf_probe_arg *pa);
>  
>  /* Check the perf_probe_event needs debuginfo */
>  extern bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);
> diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
> index 7b80f8c..0c5168d 100644
> --- a/tools/perf/util/probe-finder.c
> +++ b/tools/perf/util/probe-finder.c
> @@ -550,7 +550,7 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
>  static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
>  {
>  	Dwarf_Die vr_die;
> -	char buf[32], *ptr;
> +	char *buf, *ptr;
>  	int ret = 0;
>  
>  	if (!is_c_varname(pf->pvar->var)) {
> @@ -575,13 +575,13 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
>  	if (pf->pvar->name)
>  		pf->tvar->name = strdup(pf->pvar->name);
>  	else {
> -		ret = synthesize_perf_probe_arg(pf->pvar, buf, 32);
> -		if (ret < 0)
> -			return ret;
> +		buf = synthesize_perf_probe_arg(pf->pvar);
> +		if (!buf)
> +			return -ENOMEM;
>  		ptr = strchr(buf, ':');	/* Change type separator to _ */
>  		if (ptr)
>  			*ptr = '_';
> -		pf->tvar->name = strdup(buf);
> +		pf->tvar->name = buf;
>  	}
>  	if (pf->tvar->name == NULL)
>  		return -ENOMEM;
> @@ -1318,8 +1318,8 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
>  			if (ret2 == 0) {
>  				strlist__add(vl->vars,
>  					strbuf_detach(&buf, NULL));
> -			}
> -			strbuf_release(&buf);
> +			} else
> +				strbuf_release(&buf);
>  		}
>  	}
>  

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

* Re: [RFC PATCH perf/core v3 02/17] perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid
  2015-08-15 11:42 ` [RFC PATCH perf/core v3 02/17] perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid Masami Hiramatsu
@ 2015-08-28 16:07   ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 25+ messages in thread
From: Arnaldo Carvalho de Melo @ 2015-08-28 16:07 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Peter Zijlstra, linux-kernel, Adrian Hunter, Ingo Molnar,
	Paul Mackerras, Jiri Olsa, Namhyung Kim, Borislav Petkov,
	Hemant Kumar

Em Sat, Aug 15, 2015 at 08:42:57PM +0900, Masami Hiramatsu escreveu:
> Use path/to/bin/buildid/elf instead of path/to/bin/buildid
> to store corresponding elf binary.
> This also stores vdso in buildid/vdso, kallsyms in buildid/kallsyms.

Please break this patch into multiple ones to ease review, for instance,
the very first one should be:

"This patch makes path/to/bin/buildid become a directory, and the first
 content it'll have is the current ELF file, that will be named
 path/to/bin/build/ELF, the following patches will add more entries in
 the path/to/bin/buildid/ directory with other buildid specific content,
 such as kallsyms, SDT metadata, etc"

And this would even fix a problem that we have now that is if we
have a kallsyms in the build-id cache and then, later, install the
matching vmlinux, we keep caching just the kallsyms based metadata for
that buildid (the kernel in this example).

Can you please do that?

Thanks,

- Arnaldo

> Note that the build-id based symlink changes to point to the
> path/to/bin/buildid, not path/to/bin/buildid/elf.
> 
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> ---
>  Changes in v3:
>   - Update for the latest perf/core
>   - Use sbuild_id for stringified build_id buffer.
> ---
>  tools/perf/util/build-id.c |   65 +++++++++++++++++++++++++++++++-------------
>  tools/perf/util/dso.h      |    5 +++
>  tools/perf/util/symbol.c   |    2 +
>  3 files changed, 52 insertions(+), 20 deletions(-)
> 
> diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
> index 4a2c2f0..f65d7c2 100644
> --- a/tools/perf/util/build-id.c
> +++ b/tools/perf/util/build-id.c
> @@ -112,7 +112,8 @@ static int asnprintf(char **strp, size_t size, const char *fmt, ...)
>  	return ret;
>  }
>  
> -static char *build_id__filename(const char *sbuild_id, char *bf, size_t size)
> +static char *build_id_cache__linkname(const char *sbuild_id, char *bf,
> +				      size_t size)
>  {
>  	char *tmp = bf;
>  	int ret = asnprintf(&bf, size, "%s/.build-id/%.2s/%s", buildid_dir,
> @@ -122,15 +123,35 @@ static char *build_id__filename(const char *sbuild_id, char *bf, size_t size)
>  	return bf;
>  }
>  
> +static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso)
> +{
> +	return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf");
> +}
> +
>  char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
>  {
> -	char build_id_hex[SBUILD_ID_SIZE];
> +	bool is_kallsyms = dso__is_kallsyms((struct dso *)dso);
> +	bool is_vdso = dso__is_vdso((struct dso *)dso);
> +	char sbuild_id[SBUILD_ID_SIZE];
> +	char *linkname;
> +	bool alloc = (bf == NULL);
> +	int ret;
>  
>  	if (!dso->has_build_id)
>  		return NULL;
>  
> -	build_id__sprintf(dso->build_id, sizeof(dso->build_id), build_id_hex);
> -	return build_id__filename(build_id_hex, bf, size);
> +	build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
> +	linkname = build_id_cache__linkname(sbuild_id, NULL, 0);
> +	if (!linkname)
> +		return NULL;
> +
> +	ret = asnprintf(&bf, size, "%s/%s", linkname,
> +			 build_id_cache__basename(is_kallsyms, is_vdso));
> +	if (ret < 0 || (!alloc && size < (unsigned int)ret))
> +		bf = NULL;
> +	free(linkname);
> +
> +	return bf;
>  }
>  
>  #define dsos__for_each_with_build_id(pos, head)	\
> @@ -261,7 +282,8 @@ void disable_buildid_cache(void)
>  }
>  
>  static char *build_id_cache__dirname_from_path(const char *name,
> -					       bool is_kallsyms, bool is_vdso)
> +					       bool is_kallsyms, bool is_vdso,
> +					       const char *sbuild_id)
>  {
>  	char *realname = (char *)name, *filename;
>  	bool slash = is_kallsyms || is_vdso;
> @@ -272,8 +294,9 @@ static char *build_id_cache__dirname_from_path(const char *name,
>  			return NULL;
>  	}
>  
> -	if (asprintf(&filename, "%s%s%s", buildid_dir, slash ? "/" : "",
> -		     is_vdso ? DSO__NAME_VDSO : realname) < 0)
> +	if (asprintf(&filename, "%s%s%s%s%s", buildid_dir, slash ? "/" : "",
> +		     is_vdso ? DSO__NAME_VDSO : realname,
> +		     sbuild_id ? "/" : "", sbuild_id ?: "") < 0)
>  		filename = NULL;
>  
>  	if (!slash)
> @@ -292,7 +315,8 @@ int build_id_cache__list_build_ids(const char *pathname,
>  	int ret = 0;
>  
>  	list = strlist__new(NULL, NULL);
> -	dir_name = build_id_cache__dirname_from_path(pathname, false, false);
> +	dir_name = build_id_cache__dirname_from_path(pathname, false, false,
> +						     NULL);
>  	if (!list || !dir_name) {
>  		ret = -ENOMEM;
>  		goto out;
> @@ -327,7 +351,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
>  {
>  	const size_t size = PATH_MAX;
>  	char *realname = NULL, *filename = NULL, *dir_name = NULL,
> -	     *linkname = zalloc(size), *targetname, *tmp;
> +	     *linkname = zalloc(size), *tmp;
>  	int err = -1;
>  
>  	if (!is_kallsyms) {
> @@ -336,14 +360,17 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
>  			goto out_free;
>  	}
>  
> -	dir_name = build_id_cache__dirname_from_path(name, is_kallsyms, is_vdso);
> +	dir_name = build_id_cache__dirname_from_path(name, is_kallsyms,
> +						     is_vdso, sbuild_id);
>  	if (!dir_name)
>  		goto out_free;
>  
>  	if (mkdir_p(dir_name, 0755))
>  		goto out_free;
>  
> -	if (asprintf(&filename, "%s/%s", dir_name, sbuild_id) < 0) {
> +	/* Save the allocated buildid dirname */
> +	if (asprintf(&filename, "%s/%s", dir_name,
> +		     build_id_cache__basename(is_kallsyms, is_vdso)) < 0) {
>  		filename = NULL;
>  		goto out_free;
>  	}
> @@ -357,7 +384,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
>  			goto out_free;
>  	}
>  
> -	if (!build_id__filename(sbuild_id, linkname, size))
> +	if (!build_id_cache__linkname(sbuild_id, linkname, size))
>  		goto out_free;
>  	tmp = strrchr(linkname, '/');
>  	*tmp = '\0';
> @@ -366,10 +393,10 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
>  		goto out_free;
>  
>  	*tmp = '/';
> -	targetname = filename + strlen(buildid_dir) - 5;
> -	memcpy(targetname, "../..", 5);
> +	tmp = dir_name + strlen(buildid_dir) - 5;
> +	memcpy(tmp, "../..", 5);
>  
> -	if (symlink(targetname, linkname) == 0)
> +	if (symlink(tmp, linkname) == 0)
>  		err = 0;
>  out_free:
>  	if (!is_kallsyms)
> @@ -394,7 +421,7 @@ static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
>  bool build_id_cache__cached(const char *sbuild_id)
>  {
>  	bool ret = false;
> -	char *filename = build_id__filename(sbuild_id, NULL, 0);
> +	char *filename = build_id_cache__linkname(sbuild_id, NULL, 0);
>  
>  	if (filename && !access(filename, F_OK))
>  		ret = true;
> @@ -413,7 +440,7 @@ int build_id_cache__remove_s(const char *sbuild_id)
>  	if (filename == NULL || linkname == NULL)
>  		goto out_free;
>  
> -	if (!build_id__filename(sbuild_id, linkname, size))
> +	if (!build_id_cache__linkname(sbuild_id, linkname, size))
>  		goto out_free;
>  
>  	if (access(linkname, F_OK))
> @@ -431,7 +458,7 @@ int build_id_cache__remove_s(const char *sbuild_id)
>  	tmp = strrchr(linkname, '/') + 1;
>  	snprintf(tmp, size - (tmp - linkname), "%s", filename);
>  
> -	if (unlink(linkname))
> +	if (rm_rf(linkname))
>  		goto out_free;
>  
>  	err = 0;
> @@ -443,7 +470,7 @@ out_free:
>  
>  static int dso__cache_build_id(struct dso *dso, struct machine *machine)
>  {
> -	bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
> +	bool is_kallsyms = dso__is_kallsyms(dso);
>  	bool is_vdso = dso__is_vdso(dso);
>  	const char *name = dso->long_name;
>  	char nm[PATH_MAX];
> diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
> index c73276d..07f37c2 100644
> --- a/tools/perf/util/dso.h
> +++ b/tools/perf/util/dso.h
> @@ -345,6 +345,11 @@ static inline bool dso__is_kcore(struct dso *dso)
>  	       dso->binary_type == DSO_BINARY_TYPE__GUEST_KCORE;
>  }
>  
> +static inline bool dso__is_kallsyms(struct dso *dso)
> +{
> +	return dso->kernel && dso->long_name[0] != '/';
> +}
> +
>  void dso__free_a2l(struct dso *dso);
>  
>  enum dso_type dso__type(struct dso *dso, struct machine *machine);
> diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
> index 725640f..9ed826c 100644
> --- a/tools/perf/util/symbol.c
> +++ b/tools/perf/util/symbol.c
> @@ -1707,7 +1707,7 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)
>  	if (!find_matching_kcore(map, path, sizeof(path)))
>  		return strdup(path);
>  
> -	scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s",
> +	scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s/kallsyms",
>  		  buildid_dir, sbuild_id);
>  
>  	if (access(path, F_OK)) {

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

* Re: [RFC PATCH perf/core v3 03/17] perf buildid: Introduce sysfs/filename__sprintf_build_id
  2015-08-15 11:42 ` [RFC PATCH perf/core v3 03/17] perf buildid: Introduce sysfs/filename__sprintf_build_id Masami Hiramatsu
@ 2015-08-28 16:14   ` Arnaldo Carvalho de Melo
  2015-08-31  8:32   ` [tip:perf/core] perf buildid: Introduce sysfs/ filename__sprintf_build_id tip-bot for Masami Hiramatsu
  1 sibling, 0 replies; 25+ messages in thread
From: Arnaldo Carvalho de Melo @ 2015-08-28 16:14 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Peter Zijlstra, linux-kernel, Adrian Hunter, Ingo Molnar,
	Paul Mackerras, Jiri Olsa, Namhyung Kim, Borislav Petkov,
	Hemant Kumar

Em Sat, Aug 15, 2015 at 08:42:59PM +0900, Masami Hiramatsu escreveu:
> Introduce sysfs/filename__sprintf_build_id for consolidating
> similar code.

Applied.

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

* Re: [RFC PATCH perf/core v3 05/17] perf-buildid-cache: Use lsdir for looking up buildid caches
  2015-08-15 11:43 ` [RFC PATCH perf/core v3 05/17] perf-buildid-cache: Use lsdir for looking up buildid caches Masami Hiramatsu
@ 2015-08-28 16:17   ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 25+ messages in thread
From: Arnaldo Carvalho de Melo @ 2015-08-28 16:17 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Peter Zijlstra, linux-kernel, Adrian Hunter, Ingo Molnar,
	Paul Mackerras, Jiri Olsa, Namhyung Kim, Borislav Petkov,
	Hemant Kumar

Em Sat, Aug 15, 2015 at 08:43:04PM +0900, Masami Hiramatsu escreveu:
> Use new lsdir() for looking up buildid caches. This changes
> logic a bit to ignore all dot files, since the build-id
> cache must not start with dot.

It is not applying to my perf/core branch, please check.

This is after I applied that list_dir() helper.

- Arnaldo
 
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> ---
>  tools/perf/util/build-id.c |   30 +++++-------------------------
>  1 file changed, 5 insertions(+), 25 deletions(-)
> 
> diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
> index b639cad..e9ef98e 100644
> --- a/tools/perf/util/build-id.c
> +++ b/tools/perf/util/build-id.c
> @@ -342,38 +342,18 @@ int build_id_cache__list_build_ids(const char *pathname,
>  {
>  	struct strlist *list;
>  	char *dir_name;
> -	DIR *dir;
> -	struct dirent *d;
>  	int ret = 0;
>  
> -	list = strlist__new(NULL, NULL);
>  	dir_name = build_id_cache__dirname_from_path(pathname, false, false,
>  						     NULL);
> -	if (!list || !dir_name) {
> -		ret = -ENOMEM;
> -		goto out;
> -	}
> +	if (!dir_name)
> +		return -ENOMEM;
>  
> -	/* List up all dirents */
> -	dir = opendir(dir_name);
> -	if (!dir) {
> +	list = lsdir(dir_name, lsdir_no_dot_filter);
> +	if (!list)
>  		ret = -errno;
> -		goto out;
> -	}
> -
> -	while ((d = readdir(dir)) != NULL) {
> -		if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
> -			continue;
> -		strlist__add(list, d->d_name);
> -	}
> -	closedir(dir);
> -
> -out:
> +	*result = list;
>  	free(dir_name);
> -	if (ret)
> -		strlist__delete(list);
> -	else
> -		*result = list;
>  
>  	return ret;
>  }

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

* [tip:perf/core] perf buildid: Introduce sysfs/ filename__sprintf_build_id
  2015-08-15 11:42 ` [RFC PATCH perf/core v3 03/17] perf buildid: Introduce sysfs/filename__sprintf_build_id Masami Hiramatsu
  2015-08-28 16:14   ` Arnaldo Carvalho de Melo
@ 2015-08-31  8:32   ` tip-bot for Masami Hiramatsu
  1 sibling, 0 replies; 25+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2015-08-31  8:32 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: jolsa, acme, tglx, hpa, masami.hiramatsu.pt, paulus, bp,
	adrian.hunter, a.p.zijlstra, hemant, namhyung, linux-kernel,
	mingo

Commit-ID:  0b5a7935f3b5b7d40293b02c3e552f3d67af208b
Gitweb:     http://git.kernel.org/tip/0b5a7935f3b5b7d40293b02c3e552f3d67af208b
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Sat, 15 Aug 2015 20:42:59 +0900
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Fri, 28 Aug 2015 14:53:50 -0300

perf buildid: Introduce sysfs/filename__sprintf_build_id

Introduce sysfs/filename__sprintf_build_id for consolidating similar
code.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Hemant Kumar <hemant@linux.vnet.ibm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/20150815114259.13642.34685.stgit@localhost.localdomain
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/builtin-buildid-cache.c | 14 ++------------
 tools/perf/builtin-buildid-list.c  | 24 ++++++++++--------------
 tools/perf/util/build-id.c         | 32 ++++++++++++++++++++++++++++++++
 tools/perf/util/build-id.h         |  3 +++
 4 files changed, 47 insertions(+), 26 deletions(-)

diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index 65b4835..7b8450c 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -25,8 +25,6 @@
 static int build_id_cache__kcore_buildid(const char *proc_dir, char *sbuildid)
 {
 	char root_dir[PATH_MAX];
-	char notes[PATH_MAX];
-	u8 build_id[BUILD_ID_SIZE];
 	char *p;
 
 	strlcpy(root_dir, proc_dir, sizeof(root_dir));
@@ -35,15 +33,7 @@ static int build_id_cache__kcore_buildid(const char *proc_dir, char *sbuildid)
 	if (!p)
 		return -1;
 	*p = '\0';
-
-	scnprintf(notes, sizeof(notes), "%s/sys/kernel/notes", root_dir);
-
-	if (sysfs__read_build_id(notes, build_id, sizeof(build_id)))
-		return -1;
-
-	build_id__sprintf(build_id, sizeof(build_id), sbuildid);
-
-	return 0;
+	return sysfs__sprintf_build_id(root_dir, sbuildid);
 }
 
 static int build_id_cache__kcore_dir(char *dir, size_t sz)
@@ -138,7 +128,7 @@ static int build_id_cache__add_kcore(const char *filename, bool force)
 		return -1;
 	*p = '\0';
 
-	if (build_id_cache__kcore_buildid(from_dir, sbuildid))
+	if (build_id_cache__kcore_buildid(from_dir, sbuildid) < 0)
 		return -1;
 
 	scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s",
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index b5ca988..918b4de 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -19,29 +19,25 @@
 
 static int sysfs__fprintf_build_id(FILE *fp)
 {
-	u8 kallsyms_build_id[BUILD_ID_SIZE];
 	char sbuild_id[SBUILD_ID_SIZE];
+	int ret;
 
-	if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
-				 sizeof(kallsyms_build_id)) != 0)
-		return -1;
+	ret = sysfs__sprintf_build_id("/", sbuild_id);
+	if (ret != sizeof(sbuild_id))
+		return ret < 0 ? ret : -EINVAL;
 
-	build_id__sprintf(kallsyms_build_id, sizeof(kallsyms_build_id),
-			  sbuild_id);
-	fprintf(fp, "%s\n", sbuild_id);
-	return 0;
+	return fprintf(fp, "%s\n", sbuild_id);
 }
 
 static int filename__fprintf_build_id(const char *name, FILE *fp)
 {
-	u8 build_id[BUILD_ID_SIZE];
 	char sbuild_id[SBUILD_ID_SIZE];
+	int ret;
 
-	if (filename__read_build_id(name, build_id,
-				    sizeof(build_id)) != sizeof(build_id))
-		return 0;
+	ret = filename__sprintf_build_id(name, sbuild_id);
+	if (ret != sizeof(sbuild_id))
+		return ret < 0 ? ret : -EINVAL;
 
-	build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
 	return fprintf(fp, "%s\n", sbuild_id);
 }
 
@@ -63,7 +59,7 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
 	/*
 	 * See if this is an ELF file first:
 	 */
-	if (filename__fprintf_build_id(input_name, stdout))
+	if (filename__fprintf_build_id(input_name, stdout) > 0)
 		goto out;
 
 	session = perf_session__new(&file, false, &build_id__mark_dso_hit_ops);
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 4a2c2f0..d909459 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -93,6 +93,38 @@ int build_id__sprintf(const u8 *build_id, int len, char *bf)
 	return raw - build_id;
 }
 
+int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id)
+{
+	char notes[PATH_MAX];
+	u8 build_id[BUILD_ID_SIZE];
+	int ret;
+
+	if (!root_dir)
+		root_dir = "";
+
+	scnprintf(notes, sizeof(notes), "%s/sys/kernel/notes", root_dir);
+
+	ret = sysfs__read_build_id(notes, build_id, sizeof(build_id));
+	if (ret < 0)
+		return ret;
+
+	return build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
+}
+
+int filename__sprintf_build_id(const char *pathname, char *sbuild_id)
+{
+	u8 build_id[BUILD_ID_SIZE];
+	int ret;
+
+	ret = filename__read_build_id(pathname, build_id, sizeof(build_id));
+	if (ret < 0)
+		return ret;
+	else if (ret != sizeof(build_id))
+		return -EINVAL;
+
+	return build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
+}
+
 /* asnprintf consolidates asprintf and snprintf */
 static int asnprintf(char **strp, size_t size, const char *fmt, ...)
 {
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index ce2f493..27a14a8 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -12,6 +12,9 @@ extern struct perf_tool build_id__mark_dso_hit_ops;
 struct dso;
 
 int build_id__sprintf(const u8 *build_id, int len, char *bf);
+int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id);
+int filename__sprintf_build_id(const char *pathname, char *sbuild_id);
+
 char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size);
 
 int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,

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

end of thread, other threads:[~2015-08-31  8:32 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-08-15 11:42 [RFC PATCH perf/core v3 00/17] perf-probe --cache and SDT support Masami Hiramatsu
2015-08-15 11:42 ` [RFC PATCH perf/core v3 01/17] perf probe: Use strbuf for making strings in probe-event.c Masami Hiramatsu
2015-08-28 15:56   ` Arnaldo Carvalho de Melo
2015-08-15 11:42 ` [RFC PATCH perf/core v3 02/17] perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid Masami Hiramatsu
2015-08-28 16:07   ` Arnaldo Carvalho de Melo
2015-08-15 11:42 ` [RFC PATCH perf/core v3 03/17] perf buildid: Introduce sysfs/filename__sprintf_build_id Masami Hiramatsu
2015-08-28 16:14   ` Arnaldo Carvalho de Melo
2015-08-31  8:32   ` [tip:perf/core] perf buildid: Introduce sysfs/ filename__sprintf_build_id tip-bot for Masami Hiramatsu
2015-08-15 11:43 ` [RFC PATCH perf/core v3 04/17] perf: Add lsdir to read a directory Masami Hiramatsu
2015-08-15 11:43 ` [RFC PATCH perf/core v3 05/17] perf-buildid-cache: Use lsdir for looking up buildid caches Masami Hiramatsu
2015-08-28 16:17   ` Arnaldo Carvalho de Melo
2015-08-15 11:43 ` [RFC PATCH perf/core v3 06/17] perf probe: Add --cache option to cache the probe definitions Masami Hiramatsu
2015-08-15 11:43 ` [RFC PATCH perf/core v3 07/17] perf probe: Use cache entry if possible Masami Hiramatsu
2015-08-15 11:43 ` [RFC PATCH perf/core v3 08/17] perf probe: Show all cached probes Masami Hiramatsu
2015-08-15 11:43 ` [RFC PATCH perf/core v3 09/17] perf probe: Remove caches when --cache is given Masami Hiramatsu
2015-08-15 11:43 ` [RFC PATCH perf/core v3 10/17] perf/sdt: ELF support for SDT Masami Hiramatsu
2015-08-15 11:43 ` [RFC PATCH perf/core v3 11/17] perf probe: Add group name support Masami Hiramatsu
2015-08-15 11:43 ` [RFC PATCH perf/core v3 12/17] perf-probe: Set default kprobe group name if it is not given Masami Hiramatsu
2015-08-15 11:43 ` [RFC PATCH perf/core v3 13/17] perf buildid-cache: Scan and import user SDT events to probe cache Masami Hiramatsu
2015-08-15 11:43 ` [RFC PATCH perf/core v3 14/17] perf probe: Accept %sdt and %cached event name Masami Hiramatsu
2015-08-15 11:43 ` [RFC PATCH perf/core v3 15/17] perf-list: Show SDT events Masami Hiramatsu
2015-08-15 11:43 ` [RFC PATCH perf/core v3 16/17] perf-list: Skip SDTs placed in invalid binaries Masami Hiramatsu
2015-08-15 11:43 ` [RFC PATCH perf/core v3 17/17] perf record: Support recording SDT events Masami Hiramatsu
2015-08-19  8:30 ` [RFC PATCH perf/core v3 00/17] perf-probe --cache and SDT support Namhyung Kim
2015-08-19 15:15   ` 平松雅巳 / HIRAMATU,MASAMI

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.