Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1435133 > unrolled thread
| Started by | Masami Hiramatsu <mhiramat@kernel.org> |
|---|---|
| First post | 2016-07-01 10:20 +0200 |
| Last post | 2016-07-01 15:20 +0200 |
| Articles | 18 — 4 participants |
Back to article view | Back to linux.kernel
[PATCH perf/core v13 00/15] perf-probe --cache and SDT support Masami Hiramatsu <mhiramat@kernel.org> - 2016-07-01 10:20 +0200
[PATCH perf/core v13 05/15] perf probe: Add group name support Masami Hiramatsu <mhiramat@kernel.org> - 2016-07-01 10:30 +0200
[tip:perf/core] perf probe: Add group name support tip-bot for Masami Hiramatsu <tipbot@zytor.com> - 2016-07-05 12:30 +0200
[PATCH perf/core v13 04/15] perf/sdt: ELF support for SDT Masami Hiramatsu <mhiramat@kernel.org> - 2016-07-01 10:30 +0200
Re: [PATCH perf/core v13 04/15] perf/sdt: ELF support for SDT Arnaldo Carvalho de Melo <acme@kernel.org> - 2016-07-01 21:00 +0200
Re: [PATCH perf/core v13 04/15] perf/sdt: ELF support for SDT Masami Hiramatsu <mhiramat@kernel.org> - 2016-07-04 07:30 +0200
[tip:perf/core] perf sdt: ELF support for SDT tip-bot for Hemant Kumar <tipbot@zytor.com> - 2016-07-05 12:20 +0200
[PATCH perf/core v13 02/15] perf probe: Show all cached probes Masami Hiramatsu <mhiramat@kernel.org> - 2016-07-01 10:30 +0200
Re: [PATCH perf/core v13 02/15] perf probe: Show all cached probes Arnaldo Carvalho de Melo <acme@kernel.org> - 2016-07-01 16:00 +0200
Re: [PATCH perf/core v13 02/15] perf probe: Show all cached probes Masami Hiramatsu <mhiramat@kernel.org> - 2016-07-04 04:10 +0200
[tip:perf/core] perf probe: Show all cached probes tip-bot for Masami Hiramatsu <tipbot@zytor.com> - 2016-07-05 12:20 +0200
[PATCH perf/core v13 06/15] perf buildid-cache: Scan and import user SDT events to probe cache Masami Hiramatsu <mhiramat@kernel.org> - 2016-07-01 10:30 +0200
Re: [PATCH perf/core v13 06/15] perf buildid-cache: Scan and import user SDT events to probe cache Arnaldo Carvalho de Melo <acme@kernel.org> - 2016-07-01 20:30 +0200
Re: [PATCH perf/core v13 06/15] perf buildid-cache: Scan and import user SDT events to probe cache Masami Hiramatsu <mhiramat@kernel.org> - 2016-07-04 04:20 +0200
Re: [PATCH perf/core v13 06/15] perf buildid-cache: Scan and import user SDT events to probe cache Masami Hiramatsu <mhiramat@kernel.org> - 2016-07-05 04:10 +0200
[tip:perf/core] perf buildid-cache: Scan and import user SDT events to probe cache tip-bot for Masami Hiramatsu <tipbot@zytor.com> - 2016-07-05 12:30 +0200
[PATCH perf/core v13 07/15] perf probe: Accept %sdt and %cached event name Masami Hiramatsu <mhiramat@kernel.org> - 2016-07-01 10:30 +0200
Re: [PATCH perf/core v13 00/15] perf-probe --cache and SDT support Arnaldo Carvalho de Melo <acme@kernel.org> - 2016-07-01 15:20 +0200
| From | Masami Hiramatsu <mhiramat@kernel.org> |
|---|---|
| Date | 2016-07-01 10:20 +0200 |
| Subject | [PATCH perf/core v13 00/15] perf-probe --cache and SDT support |
| Message-ID | <rQ1Gp-4bf-3@gated-at.bofh.it> |
Hi,
Here is the 13th version of the patchset for probe-cache and
initial SDT support.
Here is the previous v12: https://lkml.org/lkml/2016/6/24/147
In this version, I've removed the patch for perf-list to show
SDT events, since at this point we don't support SDT from
perf record. I also change perf-probe --cache --list to show
cached events on only valid (existing) binaries.
Thank you,
---
Hemant Kumar (1):
perf/sdt: ELF support for SDT
Masami Hiramatsu (14):
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 buildid-cache: Scan and import user SDT events to probe cache
perf probe: Accept %sdt and %cached event name
perf-probe: Make --list shows only available cached events
perf: probe-cache: Add for_each_probe_cache_entry() wrapper
perf probe: Allow wildcard for cached events
perf probe: Search SDT/cached event from all probe caches
perf probe: Support @BUILDID or @FILE suffix for SDT events
perf probe: Support a special SDT probe format
perf build: Add sdt feature detection
perf-test: Add a test case for SDT event
tools/perf/Documentation/perf-buildid-cache.txt | 3
tools/perf/Documentation/perf-probe.txt | 30 +-
tools/perf/Makefile.perf | 3
tools/perf/builtin-probe.c | 31 ++
tools/perf/config/Makefile | 10 +
tools/perf/tests/Build | 1
tools/perf/tests/builtin-test.c | 4
tools/perf/tests/make | 3
tools/perf/tests/sdt.c | 115 +++++++
tools/perf/tests/tests.h | 1
tools/perf/util/build-id.c | 212 +++++++++++++
tools/perf/util/build-id.h | 4
tools/perf/util/probe-event.c | 366 +++++++++++++++++++++--
tools/perf/util/probe-event.h | 1
tools/perf/util/probe-file.c | 226 +++++++++++++-
tools/perf/util/probe-file.h | 15 +
tools/perf/util/symbol-elf.c | 252 ++++++++++++++++
tools/perf/util/symbol.h | 22 +
18 files changed, 1235 insertions(+), 64 deletions(-)
create mode 100644 tools/perf/tests/sdt.c
--
Masami Hiramatsu
[toc] | [next] | [standalone]
| From | Masami Hiramatsu <mhiramat@kernel.org> |
|---|---|
| Date | 2016-07-01 10:30 +0200 |
| Subject | [PATCH perf/core v13 05/15] perf probe: Add group name support |
| Message-ID | <rQ1ZL-4iE-7@gated-at.bofh.it> |
| In reply to | #1435133 |
From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Allow user to set group name for adding new event.
Note that user must ensure that the group name doesn't
conflict with existing group name carefully.
E.g. Existing group name can conflict with other events.
Especially, using the group name reserved for kernel
modules can hide kernel embedded events when loading
modules.
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
Changes in v4:
- Update Documentation/perf-probe.txt too.
---
tools/perf/Documentation/perf-probe.txt | 10 ++++++----
tools/perf/util/probe-event.c | 23 ++++++++++++++---------
2 files changed, 20 insertions(+), 13 deletions(-)
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 8d09173..7a258e9 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -143,16 +143,18 @@ PROBE SYNTAX
Probe points are defined by following syntax.
1) Define event based on function name
- [EVENT=]FUNC[@SRC][:RLN|+OFFS|%return|;PTN] [ARG ...]
+ [[GROUP:]EVENT=]FUNC[@SRC][:RLN|+OFFS|%return|;PTN] [ARG ...]
2) Define event based on source file with line number
- [EVENT=]SRC:ALN [ARG ...]
+ [[GROUP:]EVENT=]SRC:ALN [ARG ...]
3) Define event based on source file with lazy pattern
- [EVENT=]SRC;PTN [ARG ...]
+ [[GROUP:]EVENT=]SRC;PTN [ARG ...]
-'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'.
+'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. You can also specify a group name by 'GROUP', if omitted, set 'probe' is used for kprobe and 'probe_<bin>' is used for uprobe.
+Note that using existing group name can conflict with other events. Especially, using the group name reserved for kernel modules can hide embedded events in the
+modules.
'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).
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index f81b5dd..0201f66 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1206,10 +1206,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;
@@ -1218,11 +1216,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;
@@ -1230,7 +1236,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;
}
[toc] | [prev] | [next] | [standalone]
| From | tip-bot for Masami Hiramatsu <tipbot@zytor.com> |
|---|---|
| Date | 2016-07-05 12:30 +0200 |
| Subject | [tip:perf/core] perf probe: Add group name support |
| Message-ID | <rRvM6-1wX-27@gated-at.bofh.it> |
| In reply to | #1435137 |
Commit-ID: 8d993d96901f55d26e083390aae80fd02cbff7aa
Gitweb: http://git.kernel.org/tip/8d993d96901f55d26e083390aae80fd02cbff7aa
Author: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Fri, 1 Jul 2016 17:04:01 +0900
Committer: Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Mon, 4 Jul 2016 19:39:00 -0300
perf probe: Add group name support
Allow user to set group name for adding new event. Note that user must
ensure that the group name doesn't conflict with existing group name
carefully.
E.g. Existing group name can conflict with other events. Especially,
using the group name reserved for kernel modules can hide kernel
embedded events when loading modules.
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Hemant Kumar <hemant@linux.vnet.ibm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/146736024091.27797.9471545190066268995.stgit@devbox
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/Documentation/perf-probe.txt | 10 ++++++----
tools/perf/util/probe-event.c | 23 ++++++++++++++---------
2 files changed, 20 insertions(+), 13 deletions(-)
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 8d09173..7a258e9 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -143,16 +143,18 @@ PROBE SYNTAX
Probe points are defined by following syntax.
1) Define event based on function name
- [EVENT=]FUNC[@SRC][:RLN|+OFFS|%return|;PTN] [ARG ...]
+ [[GROUP:]EVENT=]FUNC[@SRC][:RLN|+OFFS|%return|;PTN] [ARG ...]
2) Define event based on source file with line number
- [EVENT=]SRC:ALN [ARG ...]
+ [[GROUP:]EVENT=]SRC:ALN [ARG ...]
3) Define event based on source file with lazy pattern
- [EVENT=]SRC;PTN [ARG ...]
+ [[GROUP:]EVENT=]SRC;PTN [ARG ...]
-'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'.
+'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. You can also specify a group name by 'GROUP', if omitted, set 'probe' is used for kprobe and 'probe_<bin>' is used for uprobe.
+Note that using existing group name can conflict with other events. Especially, using the group name reserved for kernel modules can hide embedded events in the
+modules.
'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).
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index f81b5dd..0201f66 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1206,10 +1206,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;
@@ -1218,11 +1216,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;
@@ -1230,7 +1236,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;
}
[toc] | [prev] | [next] | [standalone]
| From | Masami Hiramatsu <mhiramat@kernel.org> |
|---|---|
| Date | 2016-07-01 10:30 +0200 |
| Subject | [PATCH perf/core v13 04/15] perf/sdt: ELF support for SDT |
| Message-ID | <rQ1ZM-4iE-13@gated-at.bofh.it> |
| In reply to | #1435133 |
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>
Reviewed-by: Masami Hiramatsu <mhiramat@kernel.org>
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 87a297d..e74ce17 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -1781,6 +1781,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 b10d558..699f7cb 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -342,4 +342,26 @@ void arch__sym_update(struct symbol *s, 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 */
[toc] | [prev] | [next] | [standalone]
| From | Arnaldo Carvalho de Melo <acme@kernel.org> |
|---|---|
| Date | 2016-07-01 21:00 +0200 |
| Subject | Re: [PATCH perf/core v13 04/15] perf/sdt: ELF support for SDT |
| Message-ID | <rQbPs-1IB-3@gated-at.bofh.it> |
| In reply to | #1435138 |
Em Fri, Jul 01, 2016 at 05:03:46PM +0900, Masami Hiramatsu escreveu:
> 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.
Breaks the build on older systems:
[root@jouet perf]# dm
centos:5: FAIL
CC /tmp/build/perf/util/symbol-elf.o
cc1: warnings being treated as errors
util/symbol-elf.c: In function 'construct_sdt_notes_list':
util/symbol-elf.c:1927: warning: implicit declaration of function 'elf_getshdrstrndx'
util/symbol-elf.c:1927: warning: nested extern declaration of 'elf_getshdrstrndx'
mv: cannot stat `/tmp/build/perf/util/.symbol-elf.o.tmp': No such file or directory
make[3]: *** [/tmp/build/perf/util/symbol-elf.o] Error 1
make[3]: *** Waiting for unfinished jobs....
make[2]: *** [util] Error 2
make[1]: *** [/tmp/build/perf/libperf-in.o] Error 2
make: *** [install-bin] Error 2
make: Leaving directory `/git/linux/tools/perf'
centos:6: Ok
centos:7: Ok
debian:experimental: Ok
debian:7: Ok
debian:8: Ok
fedora:21: Ok
fedora:22: Ok
fedora:23: Ok
fedora:24: Ok
opensuse:13.2: Ok
opensuse:42.1: Ok
ubuntu:14.04.4: Ok
ubuntu:15.10: Ok
ubuntu:16.04: Ok
ubuntu:12.04.5: Ok
---------
Needs a feature detection test, I will try to contribute that.
- Arnaldo
> 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>
> Reviewed-by: Masami Hiramatsu <mhiramat@kernel.org>
> 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 87a297d..e74ce17 100644
> --- a/tools/perf/util/symbol-elf.c
> +++ b/tools/perf/util/symbol-elf.c
> @@ -1781,6 +1781,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 b10d558..699f7cb 100644
> --- a/tools/perf/util/symbol.h
> +++ b/tools/perf/util/symbol.h
> @@ -342,4 +342,26 @@ void arch__sym_update(struct symbol *s, 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 */
[toc] | [prev] | [next] | [standalone]
| From | Masami Hiramatsu <mhiramat@kernel.org> |
|---|---|
| Date | 2016-07-04 07:30 +0200 |
| Subject | Re: [PATCH perf/core v13 04/15] perf/sdt: ELF support for SDT |
| Message-ID | <rR4Cd-1Br-5@gated-at.bofh.it> |
| In reply to | #1435553 |
On Fri, 1 Jul 2016 15:56:49 -0300
Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
> Em Fri, Jul 01, 2016 at 05:03:46PM +0900, Masami Hiramatsu escreveu:
> > 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.
>
> Breaks the build on older systems:
>
>
> [root@jouet perf]# dm
> centos:5: FAIL
> CC /tmp/build/perf/util/symbol-elf.o
> cc1: warnings being treated as errors
> util/symbol-elf.c: In function 'construct_sdt_notes_list':
> util/symbol-elf.c:1927: warning: implicit declaration of function 'elf_getshdrstrndx'
> util/symbol-elf.c:1927: warning: nested extern declaration of 'elf_getshdrstrndx'
> mv: cannot stat `/tmp/build/perf/util/.symbol-elf.o.tmp': No such file or directory
> make[3]: *** [/tmp/build/perf/util/symbol-elf.o] Error 1
> make[3]: *** Waiting for unfinished jobs....
> make[2]: *** [util] Error 2
> make[1]: *** [/tmp/build/perf/libperf-in.o] Error 2
> make: *** [install-bin] Error 2
> make: Leaving directory `/git/linux/tools/perf'
> centos:6: Ok
> centos:7: Ok
> debian:experimental: Ok
> debian:7: Ok
> debian:8: Ok
> fedora:21: Ok
> fedora:22: Ok
> fedora:23: Ok
> fedora:24: Ok
> opensuse:13.2: Ok
> opensuse:42.1: Ok
> ubuntu:14.04.4: Ok
> ubuntu:15.10: Ok
> ubuntu:16.04: Ok
> ubuntu:12.04.5: Ok
>
> ---------
OK, that API is newer one. We have to check wheter it is supported by libelf.
>
> Needs a feature detection test, I will try to contribute that.
Thanks!
>
> - Arnaldo
>
>
> > 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>
> > Reviewed-by: Masami Hiramatsu <mhiramat@kernel.org>
> > 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 87a297d..e74ce17 100644
> > --- a/tools/perf/util/symbol-elf.c
> > +++ b/tools/perf/util/symbol-elf.c
> > @@ -1781,6 +1781,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 b10d558..699f7cb 100644
> > --- a/tools/perf/util/symbol.h
> > +++ b/tools/perf/util/symbol.h
> > @@ -342,4 +342,26 @@ void arch__sym_update(struct symbol *s, 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 */
--
Masami Hiramatsu <mhiramat@kernel.org>
[toc] | [prev] | [next] | [standalone]
| From | tip-bot for Hemant Kumar <tipbot@zytor.com> |
|---|---|
| Date | 2016-07-05 12:20 +0200 |
| Subject | [tip:perf/core] perf sdt: ELF support for SDT |
| Message-ID | <rRvCq-1tJ-29@gated-at.bofh.it> |
| In reply to | #1435138 |
Commit-ID: 060fa0c7a3e0bb4f1426ee79dfd38e2a4c80067a
Gitweb: http://git.kernel.org/tip/060fa0c7a3e0bb4f1426ee79dfd38e2a4c80067a
Author: Hemant Kumar <hemant@linux.vnet.ibm.com>
AuthorDate: Fri, 1 Jul 2016 17:03:46 +0900
Committer: Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Mon, 4 Jul 2016 19:38:59 -0300
perf sdt: ELF support for SDT
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>
Reviewed-by: Masami Hiramatsu <mhiramat@kernel.org>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/146736022628.27797.1201368329092908163.stgit@devbox
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
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 b222552c..6f15b92 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -1789,6 +1789,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 b10d558..699f7cb 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -342,4 +342,26 @@ void arch__sym_update(struct symbol *s, 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 */
[toc] | [prev] | [next] | [standalone]
| From | Masami Hiramatsu <mhiramat@kernel.org> |
|---|---|
| Date | 2016-07-01 10:30 +0200 |
| Subject | [PATCH perf/core v13 02/15] perf probe: Show all cached probes |
| Message-ID | <rQ1ZM-4iE-11@gated-at.bofh.it> |
| In reply to | #1435133 |
From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
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>
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
Changes in v12:
- Rename strlist__for_each to strlist__for_each_entry.
Changes in v11:
- Make build_id_cache__list_all() returns strlist directly. (no error code)
- Harden build_id_cache__list_all() to check directory entries.
Changes in v7:
- Remove the top '/' from binary name if it is not a regular file.
---
tools/perf/Documentation/perf-probe.txt | 8 ++
tools/perf/builtin-probe.c | 2 -
tools/perf/util/build-id.c | 108 ++++++++++++++++++++++++++++++-
tools/perf/util/build-id.h | 3 +
tools/perf/util/probe-event.c | 3 +
tools/perf/util/probe-file.c | 66 ++++++++++++++++++-
tools/perf/util/probe-file.h | 1
7 files changed, 184 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 3426232..0bb9084 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 62b1473..1c49620 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -165,8 +165,7 @@ retry:
return NULL;
}
-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,
@@ -176,6 +175,36 @@ 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;
+ size_t offs = 5; /* == strlen("../..") */
+
+ 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 > buf + offs)) {
+ *p = '\0';
+ if (buf[offs + 1] == '[')
+ offs++; /*
+ * This is a DSO name, like [kernel.kallsyms].
+ * Skip the first '/', since this is not the
+ * cache of a regular file.
+ */
+ ret = strdup(buf + offs); /* 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");
@@ -387,6 +416,81 @@ void disable_buildid_cache(void)
no_buildid_cache = true;
}
+static bool lsdir_bid_head_filter(const char *name __maybe_unused,
+ struct dirent *d __maybe_unused)
+{
+ return (strlen(d->d_name) == 2) &&
+ isxdigit(d->d_name[0]) && isxdigit(d->d_name[1]);
+}
+
+static bool lsdir_bid_tail_filter(const char *name __maybe_unused,
+ struct dirent *d __maybe_unused)
+{
+ int i = 0;
+ while (isxdigit(d->d_name[i]) && i < SBUILD_ID_SIZE - 3)
+ i++;
+ return (i == SBUILD_ID_SIZE - 3) && (d->d_name[i] == '\0');
+}
+
+struct strlist *build_id_cache__list_all(void)
+{
+ struct strlist *toplist, *linklist = NULL, *bidlist;
+ struct str_node *nd, *nd2;
+ char *topdir, *linkdir = NULL;
+ char sbuild_id[SBUILD_ID_SIZE];
+
+ /* Open the top-level directory */
+ if (asprintf(&topdir, "%s/.build-id/", buildid_dir) < 0)
+ return NULL;
+
+ bidlist = strlist__new(NULL, NULL);
+ if (!bidlist)
+ goto out;
+
+ toplist = lsdir(topdir, lsdir_bid_head_filter);
+ if (!toplist) {
+ pr_debug("Error in lsdir(%s): %d\n", topdir, errno);
+ /* If there is no buildid cache, return an empty list */
+ if (errno == ENOENT)
+ goto out;
+ goto err_out;
+ }
+
+ strlist__for_each_entry(nd, toplist) {
+ if (asprintf(&linkdir, "%s/%s", topdir, nd->s) < 0)
+ goto err_out;
+ /* Open the lower-level directory */
+ linklist = lsdir(linkdir, lsdir_bid_tail_filter);
+ if (!linklist) {
+ pr_debug("Error in lsdir(%s): %d\n", linkdir, errno);
+ goto err_out;
+ }
+ strlist__for_each_entry(nd2, linklist) {
+ if (snprintf(sbuild_id, SBUILD_ID_SIZE, "%s%s",
+ nd->s, nd2->s) != SBUILD_ID_SIZE - 1)
+ goto err_out;
+ if (strlist__add(bidlist, sbuild_id) < 0)
+ goto err_out;
+ }
+ strlist__delete(linklist);
+ zfree(&linkdir);
+ }
+
+out_free:
+ strlist__delete(toplist);
+out:
+ free(topdir);
+
+ return bidlist;
+
+err_out:
+ strlist__delete(linklist);
+ zfree(&linkdir);
+ strlist__delete(bidlist);
+ bidlist = NULL;
+ goto out_free;
+}
+
char *build_id_cache__cachedir(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 d8c7f2f..b742e27 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -30,8 +30,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__cachedir(const char *sbuild_id, const char *name,
bool is_kallsyms, bool is_vdso);
+struct strlist *build_id_cache__list_all(void);
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 47b6b8b..f81b5dd 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -2366,6 +2366,9 @@ int show_perf_probe_events(struct strfilter *filter)
setup_pager();
+ if (probe_conf.cache)
+ return probe_cache__show_all_caches(filter);
+
ret = init_probe_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 a94ee47..156e3d8 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -367,10 +367,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 {
@@ -394,8 +401,11 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target)
dir_name = build_id_cache__cachedir(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, 0644);
@@ -673,3 +683,55 @@ 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->entries, node) {
+ 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 = strfilter__string(filter);
+
+ pr_debug("list cache with filter: %s\n", buf);
+ free(buf);
+
+ bidlist = build_id_cache__list_all();
+ if (!bidlist) {
+ pr_debug("Failed to get buildids: %d\n", errno);
+ return -EINVAL;
+ }
+ strlist__for_each_entry(nd, bidlist) {
+ pcache = probe_cache__new(nd->s);
+ if (!pcache)
+ continue;
+ if (!list_empty(&pcache->entries)) {
+ 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 910aa74..0009b8a 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -42,4 +42,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
[toc] | [prev] | [next] | [standalone]
| From | Arnaldo Carvalho de Melo <acme@kernel.org> |
|---|---|
| Date | 2016-07-01 16:00 +0200 |
| Subject | Re: [PATCH perf/core v13 02/15] perf probe: Show all cached probes |
| Message-ID | <rQ798-7jz-21@gated-at.bofh.it> |
| In reply to | #1435147 |
Em Fri, Jul 01, 2016 at 05:03:26PM +0900, Masami Hiramatsu escreveu:
> From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
>
> 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
This one works:
# perf probe --cache vfs_read \$params
Added new event:
probe:vfs_read (on vfs_read with $params)
You can now use it in all perf tools, such as:
perf record -e probe:vfs_read -aR sleep 1
#
> # perf probe --cache -x /lib64/libc-2.17.so getaddrinfo \$params
But this one doesn't and provides a funny message:
[root@jouet perf]# perf probe --cache -x /lib64/libc-2.23.so getaddrinfo \$params
Failed to write event: Invalid argument
Please upgrade your kernel to at least 3.14 to have access to feature $params
Error: Failed to add events.
[root@jouet perf]#
[root@jouet perf]# uname -a
Linux jouet 4.5.7-300.fc24.x86_64 #1 SMP Wed Jun 8 18:12:45 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
[root@jouet perf]# cat /etc/fedora-release
Fedora release 24 (Twenty Four)
[root@jouet perf]#
- Arnaldo
> # 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>
> Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
> ---
> Changes in v12:
> - Rename strlist__for_each to strlist__for_each_entry.
> Changes in v11:
> - Make build_id_cache__list_all() returns strlist directly. (no error code)
> - Harden build_id_cache__list_all() to check directory entries.
> Changes in v7:
> - Remove the top '/' from binary name if it is not a regular file.
> ---
> tools/perf/Documentation/perf-probe.txt | 8 ++
> tools/perf/builtin-probe.c | 2 -
> tools/perf/util/build-id.c | 108 ++++++++++++++++++++++++++++++-
> tools/perf/util/build-id.h | 3 +
> tools/perf/util/probe-event.c | 3 +
> tools/perf/util/probe-file.c | 66 ++++++++++++++++++-
> tools/perf/util/probe-file.h | 1
> 7 files changed, 184 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 3426232..0bb9084 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 62b1473..1c49620 100644
> --- a/tools/perf/util/build-id.c
> +++ b/tools/perf/util/build-id.c
> @@ -165,8 +165,7 @@ retry:
> return NULL;
> }
>
> -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,
> @@ -176,6 +175,36 @@ 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;
> + size_t offs = 5; /* == strlen("../..") */
> +
> + 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 > buf + offs)) {
> + *p = '\0';
> + if (buf[offs + 1] == '[')
> + offs++; /*
> + * This is a DSO name, like [kernel.kallsyms].
> + * Skip the first '/', since this is not the
> + * cache of a regular file.
> + */
> + ret = strdup(buf + offs); /* 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");
> @@ -387,6 +416,81 @@ void disable_buildid_cache(void)
> no_buildid_cache = true;
> }
>
> +static bool lsdir_bid_head_filter(const char *name __maybe_unused,
> + struct dirent *d __maybe_unused)
> +{
> + return (strlen(d->d_name) == 2) &&
> + isxdigit(d->d_name[0]) && isxdigit(d->d_name[1]);
> +}
> +
> +static bool lsdir_bid_tail_filter(const char *name __maybe_unused,
> + struct dirent *d __maybe_unused)
> +{
> + int i = 0;
> + while (isxdigit(d->d_name[i]) && i < SBUILD_ID_SIZE - 3)
> + i++;
> + return (i == SBUILD_ID_SIZE - 3) && (d->d_name[i] == '\0');
> +}
> +
> +struct strlist *build_id_cache__list_all(void)
> +{
> + struct strlist *toplist, *linklist = NULL, *bidlist;
> + struct str_node *nd, *nd2;
> + char *topdir, *linkdir = NULL;
> + char sbuild_id[SBUILD_ID_SIZE];
> +
> + /* Open the top-level directory */
> + if (asprintf(&topdir, "%s/.build-id/", buildid_dir) < 0)
> + return NULL;
> +
> + bidlist = strlist__new(NULL, NULL);
> + if (!bidlist)
> + goto out;
> +
> + toplist = lsdir(topdir, lsdir_bid_head_filter);
> + if (!toplist) {
> + pr_debug("Error in lsdir(%s): %d\n", topdir, errno);
> + /* If there is no buildid cache, return an empty list */
> + if (errno == ENOENT)
> + goto out;
> + goto err_out;
> + }
> +
> + strlist__for_each_entry(nd, toplist) {
> + if (asprintf(&linkdir, "%s/%s", topdir, nd->s) < 0)
> + goto err_out;
> + /* Open the lower-level directory */
> + linklist = lsdir(linkdir, lsdir_bid_tail_filter);
> + if (!linklist) {
> + pr_debug("Error in lsdir(%s): %d\n", linkdir, errno);
> + goto err_out;
> + }
> + strlist__for_each_entry(nd2, linklist) {
> + if (snprintf(sbuild_id, SBUILD_ID_SIZE, "%s%s",
> + nd->s, nd2->s) != SBUILD_ID_SIZE - 1)
> + goto err_out;
> + if (strlist__add(bidlist, sbuild_id) < 0)
> + goto err_out;
> + }
> + strlist__delete(linklist);
> + zfree(&linkdir);
> + }
> +
> +out_free:
> + strlist__delete(toplist);
> +out:
> + free(topdir);
> +
> + return bidlist;
> +
> +err_out:
> + strlist__delete(linklist);
> + zfree(&linkdir);
> + strlist__delete(bidlist);
> + bidlist = NULL;
> + goto out_free;
> +}
> +
> char *build_id_cache__cachedir(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 d8c7f2f..b742e27 100644
> --- a/tools/perf/util/build-id.h
> +++ b/tools/perf/util/build-id.h
> @@ -30,8 +30,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__cachedir(const char *sbuild_id, const char *name,
> bool is_kallsyms, bool is_vdso);
> +struct strlist *build_id_cache__list_all(void);
> 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 47b6b8b..f81b5dd 100644
> --- a/tools/perf/util/probe-event.c
> +++ b/tools/perf/util/probe-event.c
> @@ -2366,6 +2366,9 @@ int show_perf_probe_events(struct strfilter *filter)
>
> setup_pager();
>
> + if (probe_conf.cache)
> + return probe_cache__show_all_caches(filter);
> +
> ret = init_probe_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 a94ee47..156e3d8 100644
> --- a/tools/perf/util/probe-file.c
> +++ b/tools/perf/util/probe-file.c
> @@ -367,10 +367,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 {
> @@ -394,8 +401,11 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target)
>
> dir_name = build_id_cache__cachedir(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, 0644);
> @@ -673,3 +683,55 @@ 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->entries, node) {
> + 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 = strfilter__string(filter);
> +
> + pr_debug("list cache with filter: %s\n", buf);
> + free(buf);
> +
> + bidlist = build_id_cache__list_all();
> + if (!bidlist) {
> + pr_debug("Failed to get buildids: %d\n", errno);
> + return -EINVAL;
> + }
> + strlist__for_each_entry(nd, bidlist) {
> + pcache = probe_cache__new(nd->s);
> + if (!pcache)
> + continue;
> + if (!list_empty(&pcache->entries)) {
> + 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 910aa74..0009b8a 100644
> --- a/tools/perf/util/probe-file.h
> +++ b/tools/perf/util/probe-file.h
> @@ -42,4 +42,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
[toc] | [prev] | [next] | [standalone]
| From | Masami Hiramatsu <mhiramat@kernel.org> |
|---|---|
| Date | 2016-07-04 04:10 +0200 |
| Subject | Re: [PATCH perf/core v13 02/15] perf probe: Show all cached probes |
| Message-ID | <rR1uF-86s-5@gated-at.bofh.it> |
| In reply to | #1435351 |
On Fri, 1 Jul 2016 10:51:04 -0300 Arnaldo Carvalho de Melo <acme@kernel.org> wrote: > Em Fri, Jul 01, 2016 at 05:03:26PM +0900, Masami Hiramatsu escreveu: > > From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> > > > > 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 > > This one works: > > # perf probe --cache vfs_read \$params > Added new event: > probe:vfs_read (on vfs_read with $params) > > You can now use it in all perf tools, such as: > > perf record -e probe:vfs_read -aR sleep 1 > > # > > > # perf probe --cache -x /lib64/libc-2.17.so getaddrinfo \$params > > But this one doesn't and provides a funny message: > > [root@jouet perf]# perf probe --cache -x /lib64/libc-2.23.so getaddrinfo \$params > Failed to write event: Invalid argument > Please upgrade your kernel to at least 3.14 to have access to feature $params > Error: Failed to add events. Ah, OK, $params requires debuginfo. It this error message is not correct. I'll send a fix soon. Thanks!! -- Masami Hiramatsu <mhiramat@kernel.org>
[toc] | [prev] | [next] | [standalone]
| From | tip-bot for Masami Hiramatsu <tipbot@zytor.com> |
|---|---|
| Date | 2016-07-05 12:20 +0200 |
| Subject | [tip:perf/core] perf probe: Show all cached probes |
| Message-ID | <rRvCq-1tJ-41@gated-at.bofh.it> |
| In reply to | #1435147 |
Commit-ID: 1f3736c9c833e40ac4d3a8dc6d661e341df8a259
Gitweb: http://git.kernel.org/tip/1f3736c9c833e40ac4d3a8dc6d661e341df8a259
Author: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Fri, 1 Jul 2016 17:03:26 +0900
Committer: Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Fri, 1 Jul 2016 11:34:57 -0300
perf probe: Show all cached probes
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 <mhiramat@kernel.org>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Hemant Kumar <hemant@linux.vnet.ibm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/146736020674.27797.13488316780383460180.stgit@devbox
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/Documentation/perf-probe.txt | 8 ++-
tools/perf/builtin-probe.c | 2 +-
tools/perf/util/build-id.c | 108 +++++++++++++++++++++++++++++++-
tools/perf/util/build-id.h | 3 +
tools/perf/util/probe-event.c | 3 +
tools/perf/util/probe-file.c | 66 ++++++++++++++++++-
tools/perf/util/probe-file.h | 1 +
7 files changed, 184 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 3426232..0bb9084 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 62b1473..1c49620 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -165,8 +165,7 @@ retry:
return NULL;
}
-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,
@@ -176,6 +175,36 @@ 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;
+ size_t offs = 5; /* == strlen("../..") */
+
+ 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 > buf + offs)) {
+ *p = '\0';
+ if (buf[offs + 1] == '[')
+ offs++; /*
+ * This is a DSO name, like [kernel.kallsyms].
+ * Skip the first '/', since this is not the
+ * cache of a regular file.
+ */
+ ret = strdup(buf + offs); /* 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");
@@ -387,6 +416,81 @@ void disable_buildid_cache(void)
no_buildid_cache = true;
}
+static bool lsdir_bid_head_filter(const char *name __maybe_unused,
+ struct dirent *d __maybe_unused)
+{
+ return (strlen(d->d_name) == 2) &&
+ isxdigit(d->d_name[0]) && isxdigit(d->d_name[1]);
+}
+
+static bool lsdir_bid_tail_filter(const char *name __maybe_unused,
+ struct dirent *d __maybe_unused)
+{
+ int i = 0;
+ while (isxdigit(d->d_name[i]) && i < SBUILD_ID_SIZE - 3)
+ i++;
+ return (i == SBUILD_ID_SIZE - 3) && (d->d_name[i] == '\0');
+}
+
+struct strlist *build_id_cache__list_all(void)
+{
+ struct strlist *toplist, *linklist = NULL, *bidlist;
+ struct str_node *nd, *nd2;
+ char *topdir, *linkdir = NULL;
+ char sbuild_id[SBUILD_ID_SIZE];
+
+ /* Open the top-level directory */
+ if (asprintf(&topdir, "%s/.build-id/", buildid_dir) < 0)
+ return NULL;
+
+ bidlist = strlist__new(NULL, NULL);
+ if (!bidlist)
+ goto out;
+
+ toplist = lsdir(topdir, lsdir_bid_head_filter);
+ if (!toplist) {
+ pr_debug("Error in lsdir(%s): %d\n", topdir, errno);
+ /* If there is no buildid cache, return an empty list */
+ if (errno == ENOENT)
+ goto out;
+ goto err_out;
+ }
+
+ strlist__for_each_entry(nd, toplist) {
+ if (asprintf(&linkdir, "%s/%s", topdir, nd->s) < 0)
+ goto err_out;
+ /* Open the lower-level directory */
+ linklist = lsdir(linkdir, lsdir_bid_tail_filter);
+ if (!linklist) {
+ pr_debug("Error in lsdir(%s): %d\n", linkdir, errno);
+ goto err_out;
+ }
+ strlist__for_each_entry(nd2, linklist) {
+ if (snprintf(sbuild_id, SBUILD_ID_SIZE, "%s%s",
+ nd->s, nd2->s) != SBUILD_ID_SIZE - 1)
+ goto err_out;
+ if (strlist__add(bidlist, sbuild_id) < 0)
+ goto err_out;
+ }
+ strlist__delete(linklist);
+ zfree(&linkdir);
+ }
+
+out_free:
+ strlist__delete(toplist);
+out:
+ free(topdir);
+
+ return bidlist;
+
+err_out:
+ strlist__delete(linklist);
+ zfree(&linkdir);
+ strlist__delete(bidlist);
+ bidlist = NULL;
+ goto out_free;
+}
+
char *build_id_cache__cachedir(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 d8c7f2f..b742e27 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -30,8 +30,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__cachedir(const char *sbuild_id, const char *name,
bool is_kallsyms, bool is_vdso);
+struct strlist *build_id_cache__list_all(void);
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 47b6b8b..f81b5dd 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -2366,6 +2366,9 @@ int show_perf_probe_events(struct strfilter *filter)
setup_pager();
+ if (probe_conf.cache)
+ return probe_cache__show_all_caches(filter);
+
ret = init_probe_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 a94ee47..156e3d8 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -367,10 +367,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 {
@@ -394,8 +401,11 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target)
dir_name = build_id_cache__cachedir(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, 0644);
@@ -673,3 +683,55 @@ 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->entries, node) {
+ 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 = strfilter__string(filter);
+
+ pr_debug("list cache with filter: %s\n", buf);
+ free(buf);
+
+ bidlist = build_id_cache__list_all();
+ if (!bidlist) {
+ pr_debug("Failed to get buildids: %d\n", errno);
+ return -EINVAL;
+ }
+ strlist__for_each_entry(nd, bidlist) {
+ pcache = probe_cache__new(nd->s);
+ if (!pcache)
+ continue;
+ if (!list_empty(&pcache->entries)) {
+ 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 910aa74..0009b8a 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -42,4 +42,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
[toc] | [prev] | [next] | [standalone]
| From | Masami Hiramatsu <mhiramat@kernel.org> |
|---|---|
| Date | 2016-07-01 10:30 +0200 |
| Subject | [PATCH perf/core v13 06/15] perf buildid-cache: Scan and import user SDT events to probe cache |
| Message-ID | <rQ1ZM-4iE-31@gated-at.bofh.it> |
| In reply to | #1435133 |
From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
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>
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
Changes in v11:
- Warn if SDT scanning/updating are failed.
Changes in v10:
- Update Documentation/perf-buildid-cache.txt too.
Changes in v4:
- Fix a bug to copy correct group name to entries.
- Fix to consolidate same-name entries.
---
tools/perf/Documentation/perf-buildid-cache.txt | 3 +
tools/perf/util/build-id.c | 30 ++++++++++
tools/perf/util/probe-file.c | 69 ++++++++++++++++++++++-
tools/perf/util/probe-file.h | 2 +
4 files changed, 101 insertions(+), 3 deletions(-)
diff --git a/tools/perf/Documentation/perf-buildid-cache.txt b/tools/perf/Documentation/perf-buildid-cache.txt
index dd07b55..058064d 100644
--- a/tools/perf/Documentation/perf-buildid-cache.txt
+++ b/tools/perf/Documentation/perf-buildid-cache.txt
@@ -15,6 +15,9 @@ DESCRIPTION
This command manages the build-id cache. It can add, remove, update and purge
files to/from the cache. In the future it should as well set upper limits for
the space used by the cache, etc.
+This also scans the target binary for SDT (Statically Defined Tracing) and
+record it along with the buildid-cache, which will be used by perf-probe.
+For more details, see linkperf:perf-probe[1].
OPTIONS
-------
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 1c49620..e1a1640 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;
@@ -532,6 +533,30 @@ int build_id_cache__list_build_ids(const char *pathname,
return ret;
}
+#ifdef HAVE_LIBELF_SUPPORT
+static int build_id_cache__add_sdt_cache(const char *sbuild_id,
+ const char *realname)
+{
+ struct probe_cache *cache;
+ int ret;
+
+ cache = probe_cache__new(sbuild_id);
+ if (!cache)
+ return -1;
+
+ ret = probe_cache__scan_sdt(cache, realname);
+ if (ret >= 0) {
+ pr_debug("Found %d SDTs in %s\n", ret, realname);
+ if (probe_cache__commit(cache) < 0)
+ ret = -1;
+ }
+ probe_cache__delete(cache);
+ return ret;
+}
+#else
+#define build_id_cache__add_sdt_cache(sbuild_id, realname) (0)
+#endif
+
int build_id_cache__add_s(const char *sbuild_id, const char *name,
bool is_kallsyms, bool is_vdso)
{
@@ -589,6 +614,11 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
if (symlink(tmp, linkname) == 0)
err = 0;
+
+ /* Update SDT cache : error is just warned */
+ if (build_id_cache__add_sdt_cache(sbuild_id, realname) < 0)
+ pr_debug("Failed to update/scan SDT cache for %s\n", 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 6cb6ec0..5b563b2 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -434,12 +434,15 @@ 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);
if (!entry) {
ret = -ENOMEM;
goto out;
}
+ if (buf[0] == '%')
+ entry->sdt = true;
entry->spev = strdup(buf + 1);
if (entry->spev)
ret = parse_perf_probe_command(buf + 1,
@@ -621,19 +624,79 @@ 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;
+ /* Try to find same-name entry */
+ entry = probe_cache__find_by_name(pcache, sdtgrp, note->name);
+ if (!entry) {
+ 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(sdtgrp);
+ list_add_tail(&entry->node, &pcache->entries);
+ }
+ 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);
+ entry = NULL;
+ }
+ if (entry) {
+ list_del_init(&entry->node);
+ 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 stat st;
struct iovec iov[3];
+ const char *prefix = entry->sdt ? "%" : "#";
int ret;
/* Save stat for rollback */
ret = fstat(fd, &st);
if (ret < 0)
return 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 0ed1fc5..ddf5ae2 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -8,6 +8,7 @@
/* Cache of probe definitions */
struct probe_cache_entry {
struct list_head node;
+ bool sdt;
struct perf_probe_event pev;
char *spev;
struct strlist *tevlist;
@@ -35,6 +36,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__purge(struct probe_cache *pcache);
void probe_cache__delete(struct probe_cache *pcache);
[toc] | [prev] | [next] | [standalone]
| From | Arnaldo Carvalho de Melo <acme@kernel.org> |
|---|---|
| Date | 2016-07-01 20:30 +0200 |
| Subject | Re: [PATCH perf/core v13 06/15] perf buildid-cache: Scan and import user SDT events to probe cache |
| Message-ID | <rQbmp-1yP-3@gated-at.bofh.it> |
| In reply to | #1435148 |
Em Fri, Jul 01, 2016 at 05:04:10PM +0900, Masami Hiramatsu escreveu:
> From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
>
> 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
Why not remove the need for that build-cache --add? I.e. go straight to:
perf probe -x /usr/lib/libc-2.17.so -a sdt_libc:memory_heap_new=memory_heap_new
And all the various steps above be done automagically?
It may well be interesting to have it available as separate steps, as above,
but requiring this cumbersome sequence to performed all the time when it seems
possible to do automatically seems user unfriendly.
I am tentatively applying this and testing.
- Arnaldo
> 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 "%".
Is this still the case?
[root@jouet perf]# perf probe --cache --list
/usr/lib64/libc-2.23.so (88686319c72f1a9d9cd514af519aa5602880bab2):
sdt_libc:setjmp=setjmp
sdt_libc:longjmp=longjmp
sdt_libc:longjmp_target=longjmp_target
sdt_libc:memory_arena_reuse_free_list=memory_arena_reuse_free_list
sdt_libc:memory_heap_new=memory_heap_new
sdt_libc:memory_sbrk_less=memory_sbrk_less
sdt_libc:memory_arena_reuse_wait=memory_arena_reuse_wait
sdt_libc:memory_arena_reuse=memory_arena_reuse
sdt_libc:memory_arena_new=memory_arena_new
sdt_libc:memory_arena_retry=memory_arena_retry
sdt_libc:memory_heap_free=memory_heap_free
sdt_libc:memory_heap_less=memory_heap_less
sdt_libc:memory_heap_more=memory_heap_more
sdt_libc:memory_sbrk_more=memory_sbrk_more
sdt_libc:memory_malloc_retry=memory_malloc_retry
sdt_libc:memory_mallopt_free_dyn_thresholds=memory_mallopt_free_dyn_thresholds
sdt_libc:memory_realloc_retry=memory_realloc_retry
sdt_libc:memory_memalign_retry=memory_memalign_retry
sdt_libc:memory_calloc_retry=memory_calloc_retry
sdt_libc:memory_mallopt=memory_mallopt
sdt_libc:memory_mallopt_mxfast=memory_mallopt_mxfast
sdt_libc:memory_mallopt_arena_max=memory_mallopt_arena_max
sdt_libc:memory_mallopt_arena_test=memory_mallopt_arena_test
sdt_libc:memory_mallopt_mmap_max=memory_mallopt_mmap_max
sdt_libc:memory_mallopt_mmap_threshold=memory_mallopt_mmap_threshold
sdt_libc:memory_mallopt_top_pad=memory_mallopt_top_pad
sdt_libc:memory_mallopt_trim_threshold=memory_mallopt_trim_threshold
sdt_libc:memory_mallopt_perturb=memory_mallopt_perturb
sdt_libc:memory_mallopt_check_action=memory_mallopt_check_action
sdt_libc:lll_lock_wait_private=lll_lock_wait_private
[root@jouet perf]#
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
> ---
> Changes in v11:
> - Warn if SDT scanning/updating are failed.
> Changes in v10:
> - Update Documentation/perf-buildid-cache.txt too.
> Changes in v4:
> - Fix a bug to copy correct group name to entries.
> - Fix to consolidate same-name entries.
> ---
> tools/perf/Documentation/perf-buildid-cache.txt | 3 +
> tools/perf/util/build-id.c | 30 ++++++++++
> tools/perf/util/probe-file.c | 69 ++++++++++++++++++++++-
> tools/perf/util/probe-file.h | 2 +
> 4 files changed, 101 insertions(+), 3 deletions(-)
>
> diff --git a/tools/perf/Documentation/perf-buildid-cache.txt b/tools/perf/Documentation/perf-buildid-cache.txt
> index dd07b55..058064d 100644
> --- a/tools/perf/Documentation/perf-buildid-cache.txt
> +++ b/tools/perf/Documentation/perf-buildid-cache.txt
> @@ -15,6 +15,9 @@ DESCRIPTION
> This command manages the build-id cache. It can add, remove, update and purge
> files to/from the cache. In the future it should as well set upper limits for
> the space used by the cache, etc.
> +This also scans the target binary for SDT (Statically Defined Tracing) and
> +record it along with the buildid-cache, which will be used by perf-probe.
> +For more details, see linkperf:perf-probe[1].
>
> OPTIONS
> -------
> diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
> index 1c49620..e1a1640 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;
> @@ -532,6 +533,30 @@ int build_id_cache__list_build_ids(const char *pathname,
> return ret;
> }
>
> +#ifdef HAVE_LIBELF_SUPPORT
> +static int build_id_cache__add_sdt_cache(const char *sbuild_id,
> + const char *realname)
> +{
> + struct probe_cache *cache;
> + int ret;
> +
> + cache = probe_cache__new(sbuild_id);
> + if (!cache)
> + return -1;
> +
> + ret = probe_cache__scan_sdt(cache, realname);
> + if (ret >= 0) {
> + pr_debug("Found %d SDTs in %s\n", ret, realname);
> + if (probe_cache__commit(cache) < 0)
> + ret = -1;
> + }
> + probe_cache__delete(cache);
> + return ret;
> +}
> +#else
> +#define build_id_cache__add_sdt_cache(sbuild_id, realname) (0)
> +#endif
> +
> int build_id_cache__add_s(const char *sbuild_id, const char *name,
> bool is_kallsyms, bool is_vdso)
> {
> @@ -589,6 +614,11 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
>
> if (symlink(tmp, linkname) == 0)
> err = 0;
> +
> + /* Update SDT cache : error is just warned */
> + if (build_id_cache__add_sdt_cache(sbuild_id, realname) < 0)
> + pr_debug("Failed to update/scan SDT cache for %s\n", 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 6cb6ec0..5b563b2 100644
> --- a/tools/perf/util/probe-file.c
> +++ b/tools/perf/util/probe-file.c
> @@ -434,12 +434,15 @@ 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);
> if (!entry) {
> ret = -ENOMEM;
> goto out;
> }
> + if (buf[0] == '%')
> + entry->sdt = true;
> entry->spev = strdup(buf + 1);
> if (entry->spev)
> ret = parse_perf_probe_command(buf + 1,
> @@ -621,19 +624,79 @@ 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;
> + /* Try to find same-name entry */
> + entry = probe_cache__find_by_name(pcache, sdtgrp, note->name);
> + if (!entry) {
> + 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(sdtgrp);
> + list_add_tail(&entry->node, &pcache->entries);
> + }
> + 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);
> + entry = NULL;
> + }
> + if (entry) {
> + list_del_init(&entry->node);
> + 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 stat st;
> struct iovec iov[3];
> + const char *prefix = entry->sdt ? "%" : "#";
> int ret;
> /* Save stat for rollback */
> ret = fstat(fd, &st);
> if (ret < 0)
> return 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 0ed1fc5..ddf5ae2 100644
> --- a/tools/perf/util/probe-file.h
> +++ b/tools/perf/util/probe-file.h
> @@ -8,6 +8,7 @@
> /* Cache of probe definitions */
> struct probe_cache_entry {
> struct list_head node;
> + bool sdt;
> struct perf_probe_event pev;
> char *spev;
> struct strlist *tevlist;
> @@ -35,6 +36,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__purge(struct probe_cache *pcache);
> void probe_cache__delete(struct probe_cache *pcache);
[toc] | [prev] | [next] | [standalone]
| From | Masami Hiramatsu <mhiramat@kernel.org> |
|---|---|
| Date | 2016-07-04 04:20 +0200 |
| Subject | Re: [PATCH perf/core v13 06/15] perf buildid-cache: Scan and import user SDT events to probe cache |
| Message-ID | <rR1El-8fP-1@gated-at.bofh.it> |
| In reply to | #1435540 |
On Fri, 1 Jul 2016 15:22:01 -0300
Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
> Em Fri, Jul 01, 2016 at 05:04:10PM +0900, Masami Hiramatsu escreveu:
> > From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> >
> > 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
>
> Why not remove the need for that build-cache --add? I.e. go straight to:
>
> perf probe -x /usr/lib/libc-2.17.so -a sdt_libc:memory_heap_new=memory_heap_new
>
> And all the various steps above be done automagically?
Yes, I can add that.
> It may well be interesting to have it available as separate steps, as above,
> but requiring this cumbersome sequence to performed all the time when it seems
> possible to do automatically seems user unfriendly.
Agreed. In 11/15 added a feature to search SDT without -x, but
usually uprobes requires -x, using -x is also natural.
>
> I am tentatively applying this and testing.
Thank you!
>
> - Arnaldo
>
> > 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 "%".
>
> Is this still the case?
>
> [root@jouet perf]# perf probe --cache --list
> /usr/lib64/libc-2.23.so (88686319c72f1a9d9cd514af519aa5602880bab2):
> sdt_libc:setjmp=setjmp
> sdt_libc:longjmp=longjmp
> sdt_libc:longjmp_target=longjmp_target
> sdt_libc:memory_arena_reuse_free_list=memory_arena_reuse_free_list
> sdt_libc:memory_heap_new=memory_heap_new
> sdt_libc:memory_sbrk_less=memory_sbrk_less
> sdt_libc:memory_arena_reuse_wait=memory_arena_reuse_wait
> sdt_libc:memory_arena_reuse=memory_arena_reuse
> sdt_libc:memory_arena_new=memory_arena_new
> sdt_libc:memory_arena_retry=memory_arena_retry
> sdt_libc:memory_heap_free=memory_heap_free
> sdt_libc:memory_heap_less=memory_heap_less
> sdt_libc:memory_heap_more=memory_heap_more
> sdt_libc:memory_sbrk_more=memory_sbrk_more
> sdt_libc:memory_malloc_retry=memory_malloc_retry
> sdt_libc:memory_mallopt_free_dyn_thresholds=memory_mallopt_free_dyn_thresholds
> sdt_libc:memory_realloc_retry=memory_realloc_retry
> sdt_libc:memory_memalign_retry=memory_memalign_retry
> sdt_libc:memory_calloc_retry=memory_calloc_retry
> sdt_libc:memory_mallopt=memory_mallopt
> sdt_libc:memory_mallopt_mxfast=memory_mallopt_mxfast
> sdt_libc:memory_mallopt_arena_max=memory_mallopt_arena_max
> sdt_libc:memory_mallopt_arena_test=memory_mallopt_arena_test
> sdt_libc:memory_mallopt_mmap_max=memory_mallopt_mmap_max
> sdt_libc:memory_mallopt_mmap_threshold=memory_mallopt_mmap_threshold
> sdt_libc:memory_mallopt_top_pad=memory_mallopt_top_pad
> sdt_libc:memory_mallopt_trim_threshold=memory_mallopt_trim_threshold
> sdt_libc:memory_mallopt_perturb=memory_mallopt_perturb
> sdt_libc:memory_mallopt_check_action=memory_mallopt_check_action
> sdt_libc:lll_lock_wait_private=lll_lock_wait_private
> [root@jouet perf]#
>
>
>
> > Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> > Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
> > ---
> > Changes in v11:
> > - Warn if SDT scanning/updating are failed.
> > Changes in v10:
> > - Update Documentation/perf-buildid-cache.txt too.
> > Changes in v4:
> > - Fix a bug to copy correct group name to entries.
> > - Fix to consolidate same-name entries.
> > ---
> > tools/perf/Documentation/perf-buildid-cache.txt | 3 +
> > tools/perf/util/build-id.c | 30 ++++++++++
> > tools/perf/util/probe-file.c | 69 ++++++++++++++++++++++-
> > tools/perf/util/probe-file.h | 2 +
> > 4 files changed, 101 insertions(+), 3 deletions(-)
> >
> > diff --git a/tools/perf/Documentation/perf-buildid-cache.txt b/tools/perf/Documentation/perf-buildid-cache.txt
> > index dd07b55..058064d 100644
> > --- a/tools/perf/Documentation/perf-buildid-cache.txt
> > +++ b/tools/perf/Documentation/perf-buildid-cache.txt
> > @@ -15,6 +15,9 @@ DESCRIPTION
> > This command manages the build-id cache. It can add, remove, update and purge
> > files to/from the cache. In the future it should as well set upper limits for
> > the space used by the cache, etc.
> > +This also scans the target binary for SDT (Statically Defined Tracing) and
> > +record it along with the buildid-cache, which will be used by perf-probe.
> > +For more details, see linkperf:perf-probe[1].
> >
> > OPTIONS
> > -------
> > diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
> > index 1c49620..e1a1640 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;
> > @@ -532,6 +533,30 @@ int build_id_cache__list_build_ids(const char *pathname,
> > return ret;
> > }
> >
> > +#ifdef HAVE_LIBELF_SUPPORT
> > +static int build_id_cache__add_sdt_cache(const char *sbuild_id,
> > + const char *realname)
> > +{
> > + struct probe_cache *cache;
> > + int ret;
> > +
> > + cache = probe_cache__new(sbuild_id);
> > + if (!cache)
> > + return -1;
> > +
> > + ret = probe_cache__scan_sdt(cache, realname);
> > + if (ret >= 0) {
> > + pr_debug("Found %d SDTs in %s\n", ret, realname);
> > + if (probe_cache__commit(cache) < 0)
> > + ret = -1;
> > + }
> > + probe_cache__delete(cache);
> > + return ret;
> > +}
> > +#else
> > +#define build_id_cache__add_sdt_cache(sbuild_id, realname) (0)
> > +#endif
> > +
> > int build_id_cache__add_s(const char *sbuild_id, const char *name,
> > bool is_kallsyms, bool is_vdso)
> > {
> > @@ -589,6 +614,11 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
> >
> > if (symlink(tmp, linkname) == 0)
> > err = 0;
> > +
> > + /* Update SDT cache : error is just warned */
> > + if (build_id_cache__add_sdt_cache(sbuild_id, realname) < 0)
> > + pr_debug("Failed to update/scan SDT cache for %s\n", 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 6cb6ec0..5b563b2 100644
> > --- a/tools/perf/util/probe-file.c
> > +++ b/tools/perf/util/probe-file.c
> > @@ -434,12 +434,15 @@ 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);
> > if (!entry) {
> > ret = -ENOMEM;
> > goto out;
> > }
> > + if (buf[0] == '%')
> > + entry->sdt = true;
> > entry->spev = strdup(buf + 1);
> > if (entry->spev)
> > ret = parse_perf_probe_command(buf + 1,
> > @@ -621,19 +624,79 @@ 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;
> > + /* Try to find same-name entry */
> > + entry = probe_cache__find_by_name(pcache, sdtgrp, note->name);
> > + if (!entry) {
> > + 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(sdtgrp);
> > + list_add_tail(&entry->node, &pcache->entries);
> > + }
> > + 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);
> > + entry = NULL;
> > + }
> > + if (entry) {
> > + list_del_init(&entry->node);
> > + 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 stat st;
> > struct iovec iov[3];
> > + const char *prefix = entry->sdt ? "%" : "#";
> > int ret;
> > /* Save stat for rollback */
> > ret = fstat(fd, &st);
> > if (ret < 0)
> > return 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 0ed1fc5..ddf5ae2 100644
> > --- a/tools/perf/util/probe-file.h
> > +++ b/tools/perf/util/probe-file.h
> > @@ -8,6 +8,7 @@
> > /* Cache of probe definitions */
> > struct probe_cache_entry {
> > struct list_head node;
> > + bool sdt;
> > struct perf_probe_event pev;
> > char *spev;
> > struct strlist *tevlist;
> > @@ -35,6 +36,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__purge(struct probe_cache *pcache);
> > void probe_cache__delete(struct probe_cache *pcache);
--
Masami Hiramatsu <mhiramat@kernel.org>
[toc] | [prev] | [next] | [standalone]
| From | Masami Hiramatsu <mhiramat@kernel.org> |
|---|---|
| Date | 2016-07-05 04:10 +0200 |
| Subject | Re: [PATCH perf/core v13 06/15] perf buildid-cache: Scan and import user SDT events to probe cache |
| Message-ID | <rRnYd-52z-3@gated-at.bofh.it> |
| In reply to | #1435540 |
On Fri, 1 Jul 2016 15:22:01 -0300
Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
> Em Fri, Jul 01, 2016 at 05:04:10PM +0900, Masami Hiramatsu escreveu:
> > From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> >
> > 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
>
> Why not remove the need for that build-cache --add? I.e. go straight to:
>
> perf probe -x /usr/lib/libc-2.17.so -a sdt_libc:memory_heap_new=memory_heap_new
>
> And all the various steps above be done automagically?
Ah, this has been done :) Yes, you can do that already.
See commit dd975497ad ("perf probe: Introduce perf_cache interfaces")
which introduces probe cache and it automatically add the target
binary to the buildid-cache.
Thank you,
--
Masami Hiramatsu <mhiramat@kernel.org>
[toc] | [prev] | [next] | [standalone]
| From | tip-bot for Masami Hiramatsu <tipbot@zytor.com> |
|---|---|
| Date | 2016-07-05 12:30 +0200 |
| Subject | [tip:perf/core] perf buildid-cache: Scan and import user SDT events to probe cache |
| Message-ID | <rRvM6-1wX-25@gated-at.bofh.it> |
| In reply to | #1435148 |
Commit-ID: 6430a94ead2a4c8f350441351a735303eb6d1c8a
Gitweb: http://git.kernel.org/tip/6430a94ead2a4c8f350441351a735303eb6d1c8a
Author: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Fri, 1 Jul 2016 17:04:10 +0900
Committer: Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Mon, 4 Jul 2016 19:39:00 -0300
perf buildid-cache: Scan and import user SDT events to probe cache
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 <mhiramat@kernel.org>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Hemant Kumar <hemant@linux.vnet.ibm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/146736025058.27797.13043265488541434502.stgit@devbox
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/Documentation/perf-buildid-cache.txt | 3 ++
tools/perf/util/build-id.c | 30 +++++++++++
tools/perf/util/probe-file.c | 69 +++++++++++++++++++++++--
tools/perf/util/probe-file.h | 2 +
4 files changed, 101 insertions(+), 3 deletions(-)
diff --git a/tools/perf/Documentation/perf-buildid-cache.txt b/tools/perf/Documentation/perf-buildid-cache.txt
index dd07b55..058064d 100644
--- a/tools/perf/Documentation/perf-buildid-cache.txt
+++ b/tools/perf/Documentation/perf-buildid-cache.txt
@@ -15,6 +15,9 @@ DESCRIPTION
This command manages the build-id cache. It can add, remove, update and purge
files to/from the cache. In the future it should as well set upper limits for
the space used by the cache, etc.
+This also scans the target binary for SDT (Statically Defined Tracing) and
+record it along with the buildid-cache, which will be used by perf-probe.
+For more details, see linkperf:perf-probe[1].
OPTIONS
-------
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 1c49620..e1a1640 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;
@@ -532,6 +533,30 @@ int build_id_cache__list_build_ids(const char *pathname,
return ret;
}
+#ifdef HAVE_LIBELF_SUPPORT
+static int build_id_cache__add_sdt_cache(const char *sbuild_id,
+ const char *realname)
+{
+ struct probe_cache *cache;
+ int ret;
+
+ cache = probe_cache__new(sbuild_id);
+ if (!cache)
+ return -1;
+
+ ret = probe_cache__scan_sdt(cache, realname);
+ if (ret >= 0) {
+ pr_debug("Found %d SDTs in %s\n", ret, realname);
+ if (probe_cache__commit(cache) < 0)
+ ret = -1;
+ }
+ probe_cache__delete(cache);
+ return ret;
+}
+#else
+#define build_id_cache__add_sdt_cache(sbuild_id, realname) (0)
+#endif
+
int build_id_cache__add_s(const char *sbuild_id, const char *name,
bool is_kallsyms, bool is_vdso)
{
@@ -589,6 +614,11 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
if (symlink(tmp, linkname) == 0)
err = 0;
+
+ /* Update SDT cache : error is just warned */
+ if (build_id_cache__add_sdt_cache(sbuild_id, realname) < 0)
+ pr_debug("Failed to update/scan SDT cache for %s\n", 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 6cb6ec0..5b563b2 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -434,12 +434,15 @@ 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);
if (!entry) {
ret = -ENOMEM;
goto out;
}
+ if (buf[0] == '%')
+ entry->sdt = true;
entry->spev = strdup(buf + 1);
if (entry->spev)
ret = parse_perf_probe_command(buf + 1,
@@ -621,19 +624,79 @@ 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;
+ /* Try to find same-name entry */
+ entry = probe_cache__find_by_name(pcache, sdtgrp, note->name);
+ if (!entry) {
+ 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(sdtgrp);
+ list_add_tail(&entry->node, &pcache->entries);
+ }
+ 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);
+ entry = NULL;
+ }
+ if (entry) {
+ list_del_init(&entry->node);
+ 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 stat st;
struct iovec iov[3];
+ const char *prefix = entry->sdt ? "%" : "#";
int ret;
/* Save stat for rollback */
ret = fstat(fd, &st);
if (ret < 0)
return 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 0ed1fc5..ddf5ae2 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -8,6 +8,7 @@
/* Cache of probe definitions */
struct probe_cache_entry {
struct list_head node;
+ bool sdt;
struct perf_probe_event pev;
char *spev;
struct strlist *tevlist;
@@ -35,6 +36,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__purge(struct probe_cache *pcache);
void probe_cache__delete(struct probe_cache *pcache);
[toc] | [prev] | [next] | [standalone]
| From | Masami Hiramatsu <mhiramat@kernel.org> |
|---|---|
| Date | 2016-07-01 10:30 +0200 |
| Subject | [PATCH perf/core v13 07/15] perf probe: Accept %sdt and %cached event name |
| Message-ID | <rQ1ZM-4iE-35@gated-at.bofh.it> |
| In reply to | #1435133 |
From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
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
----
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
Changes in v10:
- Update Documentation/perf-probe.txt to add a link about SDT.
Changes in v7:
- Fix a bug to return an error if no SDT/cached events found in cache.
---
tools/perf/Documentation/perf-probe.txt | 9 +++
tools/perf/util/probe-event.c | 82 ++++++++++++++++++++++---------
tools/perf/util/probe-event.h | 1
tools/perf/util/probe-file.c | 9 +++
4 files changed, 76 insertions(+), 25 deletions(-)
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 7a258e9..39e3870 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -151,6 +151,8 @@ Probe points are defined by following syntax.
3) Define event based on source file with lazy pattern
[[GROUP:]EVENT=]SRC;PTN [ARG ...]
+ 4) Pre-defined SDT events or cached event with name
+ %[PROVIDER:]SDTEVENT
'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. You can also specify a group name by 'GROUP', if omitted, set 'probe' is used for kprobe and 'probe_<bin>' is used for uprobe.
Note that using existing group name can conflict with other events. Especially, using the group name reserved for kernel modules can hide embedded events in the
@@ -158,6 +160,11 @@ modules.
'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.
+Note that before using the SDT event, the target binary (on which SDT events are defined) must be scanned by linkperf:perf-buildid-cache[1] to make SDT events as cached events.
+
+For details of the SDT, see below.
+https://sourceware.org/gdb/onlinedocs/gdb/Static-Probe-Points.html
PROBE ARGUMENT
--------------
@@ -237,4 +244,4 @@ Add probes at malloc() function on libc
SEE ALSO
--------
-linkperf:perf-trace[1], linkperf:perf-record[1]
+linkperf:perf-trace[1], linkperf:perf-record[1], linkperf:perf-buildid-cache[1]
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 0201f66..7f79a83 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1197,6 +1197,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)
{
@@ -1204,38 +1232,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;
}
@@ -2874,7 +2907,8 @@ static int find_probe_trace_events_from_cache(struct perf_probe_event *pev,
entry = probe_cache__find(cache, pev);
if (!entry) {
- ret = 0;
+ /* SDT must be in the cache */
+ ret = pev->sdt ? -ENOENT : 0;
goto out;
}
@@ -2913,7 +2947,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);
@@ -2932,8 +2966,8 @@ 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 (ret > 0 || pev->sdt) /* SDT can be found only in the cache */
+ return ret == 0 ? -ENOENT : ret; /* Found in probe cache */
if (arch__prefers_symtab() && !perf_probe_event_need_dwarf(pev)) {
ret = find_probe_trace_events_from_map(pev, tevs);
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 432b690..e18ea9f 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -85,6 +85,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 5b563b2..b642d06 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -547,6 +547,15 @@ probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev)
return NULL;
list_for_each_entry(entry, &pcache->entries, node) {
+ 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) &&
[toc] | [prev] | [next] | [standalone]
| From | Arnaldo Carvalho de Melo <acme@kernel.org> |
|---|---|
| Date | 2016-07-01 15:20 +0200 |
| Message-ID | <rQ6wp-76i-21@gated-at.bofh.it> |
| In reply to | #1435133 |
Em Fri, Jul 01, 2016 at 05:03:01PM +0900, Masami Hiramatsu escreveu: > Hi, > > Here is the 13th version of the patchset for probe-cache and > initial SDT support. > > Here is the previous v12: https://lkml.org/lkml/2016/6/24/147 As a suggestion for next time, please keep the history here, inline, i.e. the text for v11, v10, etc. > In this version, I've removed the patch for perf-list to show > SDT events, since at this point we don't support SDT from > perf record. I also change perf-probe --cache --list to show > cached events on only valid (existing) binaries. > > Thank you, > > --- > > Hemant Kumar (1): > perf/sdt: ELF support for SDT > > Masami Hiramatsu (14): > 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 buildid-cache: Scan and import user SDT events to probe cache > perf probe: Accept %sdt and %cached event name > perf-probe: Make --list shows only available cached events > perf: probe-cache: Add for_each_probe_cache_entry() wrapper > perf probe: Allow wildcard for cached events > perf probe: Search SDT/cached event from all probe caches > perf probe: Support @BUILDID or @FILE suffix for SDT events > perf probe: Support a special SDT probe format > perf build: Add sdt feature detection > perf-test: Add a test case for SDT event > > > tools/perf/Documentation/perf-buildid-cache.txt | 3 > tools/perf/Documentation/perf-probe.txt | 30 +- > tools/perf/Makefile.perf | 3 > tools/perf/builtin-probe.c | 31 ++ > tools/perf/config/Makefile | 10 + > tools/perf/tests/Build | 1 > tools/perf/tests/builtin-test.c | 4 > tools/perf/tests/make | 3 > tools/perf/tests/sdt.c | 115 +++++++ > tools/perf/tests/tests.h | 1 > tools/perf/util/build-id.c | 212 +++++++++++++ > tools/perf/util/build-id.h | 4 > tools/perf/util/probe-event.c | 366 +++++++++++++++++++++-- > tools/perf/util/probe-event.h | 1 > tools/perf/util/probe-file.c | 226 +++++++++++++- > tools/perf/util/probe-file.h | 15 + > tools/perf/util/symbol-elf.c | 252 ++++++++++++++++ > tools/perf/util/symbol.h | 22 + > 18 files changed, 1235 insertions(+), 64 deletions(-) > create mode 100644 tools/perf/tests/sdt.c > > -- > Masami Hiramatsu
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web