2014-02-24 09:14:56

by Hemant Kumar

[permalink] [raw]
Subject: [RFC PATCH v1 0/2] perf: Support for SDT markers

This patchset helps in listing dtrace style markers(SDT) present in user space
applications through perf.
Notes/markers are placed at important places by the
developers. They have a negligible overhead when not enabled.
We can enable them and probe at these places and find some important information
like the arguments' values, etc.

We have lots of applications which use SDT markers today, like:
Postgresql, MySql, Mozilla, Perl, Python, Java, Ruby, libvirt, QEMU, glib

To add SDT markers into user applications:
We need to have this header sys/sdt.h present.
sys/sdt.h used is version 3.
If not present, install systemtap-sdt-devel package (for fedora-18).

Please refer to the Documentation patch to see how the SDT markers are added into
a program.

With this patchset,
- Use perf to list the markers in the app:
# perf list sdt ./user_app

./user_app :
%user_app:foo_start
%user_app:fun_start

- Also, we can see the SDT markers present in our system in the usual binaries.
These usual binaries are libraries (dsos) listed by ldconfig --print-cache and some
binaries present in PATH environment variable.

First, scan the binaries using :
# perf list sdt --scan

Creating a cache of SDT markers...
perf sdt cache created!
Use : "perf list sdt"
to see the SDT markers

After the sdt cache file is created, use perf list to view the markers :
# perf list sdt

%rtld : init_start
%rtld : init_complete
%rtld : map_failed
%rtld : map_start
%rtld : lll_futex_wake
...
...
%libgcc : unwind
%libvirt : rpc_server_client_auth_allow
%libvirt : rpc_server_client_auth_fail
%libvirt : rpc_server_client_auth_deny

Alternatively, one can view the /var/cache/perf/perf-sdt.cache directly.

This link shows an example of marker probing with Systemtap:
https://sourceware.org/systemtap/wiki/AddingUserSpaceProbingToApps

Also, this link provides important info regarding SDT notes:
http://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation

- Markers in binaries :
These SDT markers are present in the ELF in the section named
".note.stapsdt".
Here, the name of the marker, its provider, type, location, base
address, semaphore address.
We can retrieve these values using the members name_off and desc_off in
Nhdr structure. If these are not enabled, they are present in the ELF as nop.

Changes since last series :
- Made the SDT markers present in a system more visible through perf list
as suggested by Pekka Enberg.
- Less complex command line interface to access the SDT markers.
- Added a cache file to store most of the SDT markers of a system.

TODO:
- Add support to probe these SDT markers and integrate with a previous patch
(support to perf to probe SDT markers) posted in lkml.
https://lkml.org/lkml/2013/10/23/10

- Recognizing arguments and support to probe on them.

---

Hemant Kumar (2):
perf/sdt : Listing of SDT markers by perf
perf/sdt : Documentation


tools/perf/Documentation/SDT-markers.txt | 122 +++++++
tools/perf/Documentation/perf-list.txt | 8
tools/perf/Makefile.perf | 1
tools/perf/builtin-list.c | 4
tools/perf/util/parse-events.h | 2
tools/perf/util/sdt.c | 489 ++++++++++++++++++++++++++++++
tools/perf/util/symbol-elf.c | 227 ++++++++++++++
tools/perf/util/symbol.h | 19 +
8 files changed, 869 insertions(+), 3 deletions(-)
create mode 100644 tools/perf/Documentation/SDT-markers.txt
create mode 100644 tools/perf/util/sdt.c

--


2014-02-24 09:15:59

by Hemant Kumar

[permalink] [raw]
Subject: [RFC PATCH v1 1/2] perf/sdt : Listing of SDT markers by perf

This patch enables perf to list the SDT markers present in a system. It looks
in dsos given by ldconfig --print-cache and for other binaries, it looks into
the PATH environment variable. After preparing a list of the binaries, then
it starts searching for SDT markers in them.
To find the SDT markers, first an elf section named .note.stapsdt is searched
for. And then the SDT notes are retreived one by one from that section.
To counter the effect of prelinking, the section ".stapsdt.base" is searched.
If its found, then the location of the SDT marker is adjusted.

All these markers' info is written into a cache file
"/var/cache/perf/perf-sdt.cache".
Since, the presence of SDT markers is quite common these days, hence, its better
to make them visible to a user easily. Also, creating a cache file will help a user
to probe (to be implemented) these markers without much hussle. This cache file will
hold most of the SDT markers.
The format of each entry is -

%provider : marker : file_path : build_id : location : semaphore_loc

% - marks the beginning of each entry.
provider - The provider name of the SDT marker.
marker - The marker name of the SDT marker.
file_path - Full/absolute path of the file in which this marker is present.
location : Adjusted location of the SDT marker inside the program.
semaphore_loc : The semaphore address if present otherwise 0x0.

This format should help when probing will be implemented. The adjusted address
from the required entry can be directly used in probing if the build_id matches.

To use this feature, invoke :
# perf list sdt --scan

"--scan" should be used for the first time and whenever there is any change in
the files containing the SDT markers.

And then use :
# perf list sdt

This displays a list of SDT markers (read from the cache file) present in most of
the dsos and other binaries.

However, not all the SDT markers are present in the cache file. Only the ELFs
present in the directories in PATH variable are looked into.
An individual file argument can be given to "perf list" to find out the SDT markers
present in that file. Usage is as below :

# perf list sdt /home/hemant/tmp

/home/hemant/tmp:
%user : foo
%user : bar

Signed-off-by : [email protected]
---
tools/perf/Makefile.perf | 1
tools/perf/builtin-list.c | 4
tools/perf/util/parse-events.h | 2
tools/perf/util/sdt.c | 489 ++++++++++++++++++++++++++++++++++++++++
tools/perf/util/symbol-elf.c | 227 +++++++++++++++++++
tools/perf/util/symbol.h | 19 ++
6 files changed, 741 insertions(+), 1 deletion(-)
create mode 100644 tools/perf/util/sdt.c

diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 77b153f..25a6a21 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -369,6 +369,7 @@ LIB_OBJS += $(OUTPUT)util/stat.o
LIB_OBJS += $(OUTPUT)util/record.o
LIB_OBJS += $(OUTPUT)util/srcline.o
LIB_OBJS += $(OUTPUT)util/data.o
+LIB_OBJS += $(OUTPUT)util/sdt.o

LIB_OBJS += $(OUTPUT)ui/setup.o
LIB_OBJS += $(OUTPUT)ui/helpline.o
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index 011195e..da6e68c 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -23,7 +23,7 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_END()
};
const char * const list_usage[] = {
- "perf list [hw|sw|cache|tracepoint|pmu|event_glob]",
+ "perf list [hw|sw|cache|tracepoint|pmu|event_glob|sdt]",
NULL
};

@@ -55,6 +55,8 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
print_pmu_events(NULL, false);
else if (strcmp(argv[i], "--raw-dump") == 0)
print_events(NULL, true);
+ else if (strcmp(argv[i], "sdt") == 0)
+ print_sdt_events(argv[++i]);
else {
char *sep = strchr(argv[i], ':'), *s;
int sep_idx;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index f1cb4c4..33abbd0 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -110,4 +110,6 @@ extern int is_valid_tracepoint(const char *event_string);

extern int valid_debugfs_mount(const char *debugfs);

+void print_sdt_events(const char *arg);
+
#endif /* __PERF_PARSE_EVENTS_H */
diff --git a/tools/perf/util/sdt.c b/tools/perf/util/sdt.c
new file mode 100644
index 0000000..6b252cf
--- /dev/null
+++ b/tools/perf/util/sdt.c
@@ -0,0 +1,489 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <linux/limits.h>
+#include <dirent.h>
+#include <errno.h>
+
+#include "linux/list.h"
+#include "symbol.h"
+#include "build-id.h"
+#include "include/linux/kernel.h"
+#include "parse-events.h"
+
+#define LIB_COMM "ldconfig --print-cache"
+
+#define SDT_CACHE_DIR "/var/cache/perf/"
+#define SDT_CACHE "perf-sdt.cache"
+#define SDT_CACHE_TMP "perf-sdt.cache.tmp"
+
+#define DELIM ':'
+
+struct path_list {
+ char path[PATH_MAX];
+ struct list_head list;
+} execs;
+
+/* Write operation for cache */
+static void write_cache(FILE *cache, char *buffer)
+{
+ fprintf(cache, "%s", buffer);
+}
+
+/*
+ * get_sdt_note_info() is the function actually responsible for
+ * flushing the SDT notes info into the "cache" file or to the
+ * stdout if "cache" points to NULL. Also, this function finds out
+ * the build-id of an ELF to be written into "cache".
+ */
+static void get_sdt_note_info(struct list_head *start, const char *target,
+ FILE *cache)
+{
+ struct sdt_note *pos;
+ u8 build_id[BUILD_ID_SIZE];
+ char sbuild_id[BUILD_ID_SIZE * 2 + 1];
+ char buffer[2 * PATH_MAX];
+ if (list_empty(start))
+ return;
+
+ if (cache) {
+ /* Read the build id of the file */
+ if (filename__read_build_id(target, &build_id,
+ sizeof(build_id)) < 0) {
+ pr_debug("Couldn't read build-id in %s\n", target);
+ return;
+ }
+ /* Convert the build id into a string */
+ build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
+ } else {
+ printf("%s :\n", target);
+ }
+
+ list_for_each_entry(pos, start, note_list) {
+ if (cache) {
+ sprintf(buffer, "%%%s : %s : %s : %s : 0x%lx : 0x%lx\n",
+ pos->provider, pos->name, target, sbuild_id,
+ pos->bit32 ? pos->addr.a32[0] :
+ pos->addr.a64[0],
+ pos->bit32 ? pos->addr.a32[2] :
+ pos->addr.a64[2]);
+
+ /*
+ * Format of any line of this sdt-cache :
+ * provider:marker:filename:build-id:location:semaphore
+ */
+ write_cache(cache, buffer);
+ } else {
+ printf("%%%s : %s\n", pos->provider, pos->name);
+ }
+ }
+}
+
+/* Free the sdt note list */
+static void cleanup_sdt_note_list(struct list_head *sdt_notes)
+{
+ struct sdt_note *tmp, *pos;
+
+ if (list_empty(sdt_notes))
+ return;
+
+ list_for_each_entry_safe(pos, tmp, sdt_notes, note_list) {
+ list_del(&pos->note_list);
+ free(pos->name);
+ free(pos->provider);
+ free(pos);
+ }
+}
+
+/*
+ * Error displayed in case of query of a
+ * single file for SDT markers
+ */
+static int sdt_err(int val, const char *target)
+{
+ switch (-val) {
+ case 0:
+ break;
+ case ENOENT:
+ /* Absence of SDT markers */
+ printf("%s : No SDT markers found\n", target);
+ break;
+ case EBADF:
+ printf("%s : Bad file name\n", target);
+ break;
+ default:
+ printf("%s\n", strerror(val));
+ }
+
+ return val;
+}
+
+/*
+ * filename__find_sdt() looks for sdt markers and the list is stored
+ * in sdt_notes. The fd passed here is the file in which the info
+ * about the SDT markers is filled up.
+ */
+static int filename__find_sdt(const char *target, FILE *cache)
+{
+ int ret;
+
+ LIST_HEAD(sdt_notes);
+
+ ret = get_sdt_note_list(&sdt_notes, target);
+ if (!ret)
+ get_sdt_note_info(&sdt_notes, target, cache);
+ else if (!cache) /* using cache as flag */
+ sdt_err(ret, target);
+
+ cleanup_sdt_note_list(&sdt_notes);
+ return ret;
+}
+
+/*
+ * Finds out the libraries present in a system as shown by the command
+ * "ldconfig --print-cache". Uses "=>" and '/' to find out the start of a
+ * dso path.
+ */
+static void parse_lib_name(char *str, char *path)
+{
+ char *ptr, *q, *r;
+ char c = '=';
+
+ while (str != NULL) {
+ /* look for "=>" and then '/' */
+ ptr = strchr(str, c);
+ if (ptr && (*(ptr + 1) == '>')) {
+ ptr++;
+ q = strchr(ptr, '/');
+ if (!q)
+ return;
+ r = strchr(ptr, '\n');
+ *r = '\0';
+ strcpy(path, q);
+ return;
+ } else if (ptr == NULL) {
+ return;
+ } else {
+ str = ptr + 1;
+ continue;
+ }
+ }
+}
+
+/*
+ * Checks if a path is already present in the list.
+ * Returns 'true' if present and 'false' otherwise.
+ */
+static bool is_present_in_list(struct list_head *path_list, char *path)
+{
+ struct path_list *tmp;
+
+ list_for_each_entry(tmp, path_list, list) {
+ if (!strcmp(path, tmp->path))
+ return true;
+ }
+
+ return false;
+}
+
+static inline void append_path(char *path, struct list_head *list)
+{
+ char *res_path = NULL;
+ struct path_list *tmp = NULL;
+
+ res_path = (char *)malloc(sizeof(char) * PATH_MAX);
+
+ if (!res_path)
+ return;
+
+ memset(res_path, '\0', PATH_MAX);
+
+ if (realpath(path, res_path) && !is_present_in_list(list, res_path)) {
+ tmp = (struct path_list *) malloc(sizeof(struct path_list));
+ if (!tmp) {
+ free(res_path);
+ return;
+ }
+ strcpy(tmp->path, res_path);
+ list_add(&(tmp->list), list);
+ if (res_path)
+ free(res_path);
+ }
+}
+
+static void flush_sdt_list(struct list_head *head, FILE *cache)
+{
+ struct path_list *tmp;
+
+ list_for_each_entry(tmp, head, list)
+ filename__find_sdt(tmp->path, cache);
+}
+
+static void cleanup_path_list(struct list_head *head)
+{
+ struct path_list *tmp, *pos;
+
+ list_for_each_entry_safe(tmp, pos, head, list) {
+ list_del(&tmp->list);
+ free(tmp);
+ }
+}
+
+/*
+ * Finds SDT markers in the dsos which are present in a system.
+ * "cache" is the stream which is filled up with all these SDT info.
+ */
+static void find_sdt_in_dsos(FILE *cache)
+{
+ FILE *fp;
+ size_t len = 0;
+ char *line;
+ char path[PATH_MAX];
+ struct path_list lib_list;
+
+ INIT_LIST_HEAD(&lib_list.list);
+
+ /*
+ * Run the command ldconfig to find out the libraries in
+ * a system from the file ld.so.cache
+ */
+ fp = popen(LIB_COMM, "r");
+ if (fp == NULL) {
+ printf("Error in running %s\n", LIB_COMM);
+ return;
+ }
+
+ /*
+ * Take a line from the o/p of ldconfig and
+ * parse it to find a library path
+ */
+ while (getline(&line, &len, fp) != -1) {
+ memset(path, '\0', PATH_MAX);
+ parse_lib_name(line, path);
+ if (strcmp(path, ""))
+ append_path(path, &lib_list.list);
+ }
+ /* line and fp no more required */
+ free(line);
+ pclose(fp);
+
+ /* Find and write the SDT markers in the perf-sdt cache*/
+ flush_sdt_list(&lib_list.list, cache);
+
+ cleanup_path_list(&lib_list.list);
+ return;
+}
+
+/*
+ * Go through all the files inside "path".
+ * But don't go into sub-directories.
+ */
+static void walk_through_dir(char *path)
+{
+ struct dirent *entry;
+ DIR *dir;
+ struct stat sb;
+ int ret = 0;
+ char *swd;
+
+ dir = opendir(path);
+ if (!dir)
+ return;
+
+ /* save the current working directory */
+ swd = getcwd(NULL, 0);
+ if (!swd) {
+ pr_err("getcwd : error");
+ return;
+ }
+
+ ret = chdir(path);
+ if (ret) {
+ pr_err("chdir : error in %s", path);
+ return;
+ }
+ while ((entry = readdir(dir)) != NULL) {
+
+ ret = stat(entry->d_name, &sb);
+ if (ret == -1) {
+ pr_debug("%s : error in stat!\n", entry->d_name);
+ continue;
+ }
+
+ /* Not pursuing sub-directories */
+ if ((sb.st_mode & S_IFMT) != S_IFDIR)
+ if (sb.st_mode & S_IXUSR)
+ append_path(entry->d_name, &execs.list);
+ }
+
+ closedir(dir);
+
+ /* return to the saved working directory */
+ ret = chdir(swd);
+ if (ret) {
+ pr_err("chdir : error");
+ return;
+ }
+}
+
+/*
+ * parse_list() parses the list obtained from PATH and for each
+ * path, we call walk_through_dir() to traverse through the this
+ * path's subtree and obtain the list of all Elfs.
+ */
+static void parse_list(char *exe_list)
+{
+ struct path_list dir_exe_list, *tmp;
+ char *path = exe_list;
+ char *next_path;
+
+ INIT_LIST_HEAD(&dir_exe_list.list);
+
+ if (!exe_list)
+ return;
+
+ while (path) {
+ /* Parse the string based on ':' */
+ next_path = strchr(path, DELIM);
+ if (next_path) {
+ *next_path = '\0';
+ next_path++;
+ }
+
+ append_path(path, &(dir_exe_list.list));
+ path = next_path;
+ }
+
+ /* Traversing the directory paths */
+ list_for_each_entry(tmp, &dir_exe_list.list, list)
+ walk_through_dir(tmp->path);
+
+ cleanup_path_list(&dir_exe_list.list);
+}
+
+/*
+ * Obtain the list of paths from the PATH env variable
+ */
+static int find_sdt_in_execs(FILE *cache)
+{
+ char *list = NULL;
+ const char *env = "PATH";
+
+ INIT_LIST_HEAD(&execs.list);
+
+ list = getenv(env);
+ if (list)
+ parse_list(list);
+
+ flush_sdt_list(&execs.list, cache);
+ cleanup_path_list(&execs.list);
+
+ return 0;
+}
+
+/*
+ * find_sdt_in_bins() : this function calls diff functions to find
+ * out the SDT markers in different binaries and writes it to a
+ * temporary file.
+ * If everything goes smooth, this temporary file is renamed to the
+ * original cache file name.
+ */
+static int find_sdt_in_bins(void)
+{
+ FILE *cache;
+ struct stat buf;
+ int ret;
+
+ ret = stat(SDT_CACHE_DIR, &buf);
+ if (ret) {
+ ret = mkdir(SDT_CACHE_DIR, buf.st_mode);
+ if (ret) {
+ pr_err("%s : %s\n", SDT_CACHE_DIR, strerror(errno));
+ return -errno;
+ }
+ }
+
+ cache = fopen(SDT_CACHE_DIR SDT_CACHE_TMP, "w");
+ if (!cache) {
+ printf("Error in creating/opening the %s file!\n",
+ SDT_CACHE_DIR SDT_CACHE_TMP);
+ return -errno;
+ }
+
+ find_sdt_in_dsos(cache);
+ find_sdt_in_execs(cache);
+
+ if (!fclose(cache)) {
+ ret = rename(SDT_CACHE_DIR SDT_CACHE_TMP,
+ SDT_CACHE_DIR SDT_CACHE);
+ if (ret)
+ pr_err("%s : %s\n", SDT_CACHE_TMP, strerror(errno));
+
+ } else {
+ pr_err("%s : %s\n", SDT_CACHE_TMP, strerror(errno));
+ ret = -errno;
+ }
+
+ return ret;
+}
+
+static void display_sdt_cache(void)
+{
+ FILE *sdt_cache;
+ size_t len = 0;
+ char *line, *provider, *ptr;
+ int count = 0;
+
+ sdt_cache = fopen(SDT_CACHE_DIR SDT_CACHE, "r");
+ if (!sdt_cache) {
+ printf("Please run :\n perf list sdt --scan\n");
+ return;
+ }
+ while (getline(&line, &len, sdt_cache) != -1) {
+ /*
+ * Parse the line to get the SDT marker name and provider.
+ * '%' marks the beginning of a provider name.
+ * Thereafter, ':' can be used as a delimiter
+ */
+ provider = strchr(line, '%');
+ ptr = provider;
+ while (ptr && (count != 2)) {
+ ptr = strchr(ptr + 1, DELIM);
+ count++;
+ }
+ *ptr = '\0';
+ count = 0;
+ if (provider)
+ printf("%s\n", provider);
+ }
+ free(line);
+}
+
+void print_sdt_events(const char *arg)
+{
+ int ret;
+
+ if (arg) {
+ if (!strcmp(arg, "--scan")) {
+ ret = find_sdt_in_bins();
+ if (!ret) {
+ printf("perf sdt cache created!\n Use : ");
+ printf("\"perf list sdt\""
+ "\n to see the SDT markers\n");
+ } else {
+ pr_err("Error in creating the cache"
+ " for sdt markers\n");
+ }
+ } else {
+ filename__find_sdt(arg, NULL);
+ return;
+ }
+ } else {
+ display_sdt_cache();
+ }
+ return;
+}
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 3e9f336..632589d 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -1615,6 +1615,233 @@ void kcore_extract__delete(struct kcore_extract *kce)
unlink(kce->extract_filename);
}

+static int populate_sdt_note(Elf **elf, const char *data, size_t len, int type,
+ struct sdt_note **note)
+{
+ const char *provider, *name;
+ struct sdt_note *tmp = NULL;
+ GElf_Ehdr ehdr;
+ GElf_Addr base_off = 0;
+ GElf_Shdr shdr;
+ int ret = -1;
+ int i;
+
+ union {
+ Elf64_Addr a64[3];
+ Elf32_Addr a32[3];
+ } buf;
+
+ Elf_Data dst = {
+ .d_buf = &buf, .d_type = ELF_T_ADDR, .d_version = EV_CURRENT,
+ .d_size = gelf_fsize((*elf), ELF_T_ADDR, 3, 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
+ };
+
+ /* Check the type of each of the notes */
+ if (type != SDT_NOTE_TYPE)
+ goto out_err;
+
+ 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)
+ printf("gelf_xlatetom : %s\n", elf_errmsg(-1));
+
+ /* 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;
+ }
+
+ /* Obtain the addresses */
+ if (gelf_getclass(*elf) == ELFCLASS32) {
+ for (i = 0; i < 3; i++)
+ tmp->addr.a32[i] = buf.a32[i];
+ tmp->bit32 = true;
+ } else {
+ for (i = 0; i < 3; i++)
+ tmp->addr.a64[i] = buf.a64[i];
+ tmp->bit32 = false;
+ }
+
+ /* Now Adjust the prelink effect */
+ if (!gelf_getehdr(*elf, &ehdr)) {
+ pr_debug("%s : cannot get elf header.\n", __func__);
+ ret = -EBADF;
+ goto out_free_name;
+ }
+
+ /*
+ * 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];
+ }
+
+ *note = tmp;
+ return 0;
+
+out_free_name:
+ free(tmp->name);
+out_free_prov:
+ free(tmp->provider);
+out_free_note:
+ free(tmp);
+out_err:
+ return ret;
+}
+
+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;
+ struct sdt_note *tmp = NULL;
+ int ret = 0, val = 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))) {
+ val = populate_sdt_note(&elf, ((data->d_buf) + desc_off),
+ nhdr.n_descsz, nhdr.n_type,
+ &tmp);
+ if (!val)
+ list_add_tail(&tmp->note_list, sdt_notes);
+ if (val == -ENOMEM) {
+ ret = val;
+ goto out_ret;
+ }
+ }
+ }
+ if (!sdt_notes)
+ ret = -ENOENT;
+
+out_ret:
+ return ret;
+}
+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 -errno;
+
+ symbol__elf_init();
+ elf = elf_begin(fd, ELF_C_READ, NULL);
+ if (!elf) {
+ ret = -EBADF;
+ goto out_close;
+ }
+ ret = construct_sdt_notes_list(elf, head);
+ elf_end(elf);
+
+out_close:
+ close(fd);
+ return ret;
+}
+
+/*
+ * Returns 'true' if the file is an elf and 'false' otherwise
+ */
+bool is_an_elf(char *file)
+{
+ int fd;
+ Elf *elf;
+ bool ret = true;
+
+ fd = open(file, O_RDONLY);
+ if (fd < 0) {
+ ret = false;
+ goto out_ret;
+ }
+
+ symbol__elf_init();
+ elf = elf_begin(fd, ELF_C_READ, NULL);
+ if (!elf) {
+ ret = false;
+ goto out_close;
+ }
+ if (elf_kind(elf) != ELF_K_ELF)
+ ret = false;
+
+ elf_end(elf);
+
+out_close:
+ close(fd);
+out_ret:
+ return ret;
+}
+
void symbol__elf_init(void)
{
elf_version(EV_CURRENT);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 2553ae0..a919776 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -291,4 +291,23 @@ int compare_proc_modules(const char *from, const char *to);
int setup_list(struct strlist **list, const char *list_str,
const char *list_name);

+struct sdt_note {
+ char *name;
+ char *provider;
+ bool bit32;
+ union {
+ Elf64_Addr a64[3];
+ Elf32_Addr a32[3];
+ } addr;
+ struct list_head note_list;
+};
+
+int get_sdt_note_list(struct list_head *head, const char *target);
+bool is_an_elf(char *file);
+
+#define SDT_BASE_SCN ".stapsdt.base"
+#define SDT_NOTE_SCN ".note.stapsdt"
+#define SDT_NOTE_TYPE 3
+#define SDT_NOTE_NAME "stapsdt"
+
#endif /* __PERF_SYMBOL */

2014-02-24 09:16:28

by Hemant Kumar

[permalink] [raw]
Subject: [RFC PATCH v1 2/2] perf/sdt : Documentation

Documentation for perf listing of SDT markers.
---
tools/perf/Documentation/SDT-markers.txt | 122 ++++++++++++++++++++++++++++++
tools/perf/Documentation/perf-list.txt | 8 +-
2 files changed, 128 insertions(+), 2 deletions(-)
create mode 100644 tools/perf/Documentation/SDT-markers.txt

diff --git a/tools/perf/Documentation/SDT-markers.txt b/tools/perf/Documentation/SDT-markers.txt
new file mode 100644
index 0000000..9d12c224
--- /dev/null
+++ b/tools/perf/Documentation/SDT-markers.txt
@@ -0,0 +1,122 @@
+Support to perf for listing the SDT markers :
+
+This helps in listing dtrace style markers(SDT) present in user space
+applications through perf. Notes/markers are placed at important places by the
+developers. They have a negligible overhead when not enabled.
+We can enable them and probe at these places and find some important information
+like the arguments' values, etc.
+
+How to add SDT markers into user applications:
+We need to have this header sys/sdt.h present.
+sys/sdt.h used is version 3.
+If not present, install systemtap-sdt-devel package (for fedora-18).
+
+A very simple example:
+
+$ cat user_app.c
+
+#include <sys/sdt.h>
+
+void main () {
+ /* ... */
+ /*
+ * user_app is the provider name
+ * test_probe is the marker name
+ */
+ STAP_PROBE(user_app, test_mark);
+ /* ... */
+}
+
+$ gcc user_app.c
+$ perf list sdt ./a.out
+./a.out:
+%user_app:test_mark
+
+A different example to show the same:
+- Create a file with .d extension and mention the probe names in it with
+provider name and marker name.
+
+$ cat probes.d
+provider user_app {
+ probe foo_start();
+ probe fun_start();
+};
+
+- Now create the probes.h and probes.o file :
+$ dtrace -C -h -s probes.d -o probes.h
+$ dtrace -C -G -s probes.d -o probes.o
+
+- A program using the markers:
+
+$ cat user_app.c
+
+#include <stdio.h>
+#include "probes.h"
+
+void foo(void)
+{
+ USER_APP_FOO_START();
+ printf("This is foo\n");
+}
+
+void fun(void)
+{
+ USER_APP_FUN_START();
+ printf("Inside fun\n");
+}
+int main(void)
+{
+ printf("In main\n");
+ foo();
+ fun();
+ return 0;
+}
+- Compile it and also provide probes.o file to linker:
+$ gcc user_app.c probes.o -o user_app
+
+- Now use perf to list the markers in the app:
+# perf list sdt ./user_app
+
+./user_app :
+%user_app:foo_start
+%user_app:fun_start
+
+Also, we can see the SDT markers present in our system in the usual binaries.
+First, scan the binaries using :
+# perf list sdt --scan
+
+Creating a cache of SDT markers...
+perf sdt cache created!
+ Use : "perf list sdt"
+ to see the SDT markers
+
+After the sdt cache file is created, use perf list to view the markers :
+# perf list sdt
+
+%rtld : init_start
+%rtld : init_complete
+%rtld : map_failed
+%rtld : map_start
+%rtld : lll_futex_wake
+...
+...
+%libgcc : unwind
+%libvirt : rpc_server_client_auth_allow
+%libvirt : rpc_server_client_auth_fail
+%libvirt : rpc_server_client_auth_deny
+
+Alternatively, one can view the /var/cache/perf-sdt.cache directly.
+
+Also, this link provides important info regarding SDT notes:
+http://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation
+
+This link shows an example of marker probing with Systemtap:
+https://sourceware.org/systemtap/wiki/AddingUserSpaceProbingToApps
+
+- Markers in binaries :
+These SDT markers are present in the ELF in the section named
+".note.stapsdt".
+Here, the name of the marker, its provider, type, location, base
+address, semaphore address.
+We can retrieve these values using the members name_off and desc_off in
+Nhdr structure. If these are not enabled, they are present in the ELF as nop.
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt
index 6fce6a6..7a5552c 100644
--- a/tools/perf/Documentation/perf-list.txt
+++ b/tools/perf/Documentation/perf-list.txt
@@ -8,7 +8,7 @@ perf-list - List all symbolic event types
SYNOPSIS
--------
[verse]
-'perf list' [hw|sw|cache|tracepoint|pmu|event_glob]
+'perf list' [hw|sw|cache|tracepoint|pmu|event_glob|sdt]

DESCRIPTION
-----------
@@ -92,7 +92,7 @@ details. Some of them are referenced in the SEE ALSO section below.
OPTIONS
-------

-Without options all known events will be listed.
+Without options all known events will be listed except the SDT markers.

To limit the list use:

@@ -108,6 +108,10 @@ To limit the list use:

. 'pmu' to print the kernel supplied PMU events.

+. 'sdt' to print the SDT markers present in dsos and binaries. An additional
+ argument of filename will instruct perf to look for SDT markers only in that
+ file.
+
. If none of the above is matched, it will apply the supplied glob to all
events, printing the ones that match.

2014-02-25 06:56:13

by Namhyung Kim

[permalink] [raw]
Subject: Re: [RFC PATCH v1 1/2] perf/sdt : Listing of SDT markers by perf

Hi Hemant,

On Mon, 24 Feb 2014 14:45:43 +0530, Hemant Kumar wrote:
> This patch enables perf to list the SDT markers present in a system. It looks
> in dsos given by ldconfig --print-cache and for other binaries, it looks into
> the PATH environment variable. After preparing a list of the binaries, then
> it starts searching for SDT markers in them.
> To find the SDT markers, first an elf section named .note.stapsdt is searched
> for. And then the SDT notes are retreived one by one from that section.
> To counter the effect of prelinking, the section ".stapsdt.base" is searched.
> If its found, then the location of the SDT marker is adjusted.
>
> All these markers' info is written into a cache file
> "/var/cache/perf/perf-sdt.cache".
> Since, the presence of SDT markers is quite common these days, hence, its better
> to make them visible to a user easily. Also, creating a cache file will help a user
> to probe (to be implemented) these markers without much hussle. This cache file will
> hold most of the SDT markers.
> The format of each entry is -
>
> %provider : marker : file_path : build_id : location : semaphore_loc
>
> % - marks the beginning of each entry.
> provider - The provider name of the SDT marker.
> marker - The marker name of the SDT marker.
> file_path - Full/absolute path of the file in which this marker is present.
> location : Adjusted location of the SDT marker inside the program.
> semaphore_loc : The semaphore address if present otherwise 0x0.
>
> This format should help when probing will be implemented. The adjusted address
> from the required entry can be directly used in probing if the build_id matches.
>
> To use this feature, invoke :
> # perf list sdt --scan
>
> "--scan" should be used for the first time and whenever there is any change in
> the files containing the SDT markers.
>
> And then use :
> # perf list sdt
>
> This displays a list of SDT markers (read from the cache file) present in most of
> the dsos and other binaries.

The default action of perf list (with no argument) prints all available
events on the system - so it should also print SDT markers IMHO.

>
> However, not all the SDT markers are present in the cache file. Only the ELFs
> present in the directories in PATH variable are looked into.
> An individual file argument can be given to "perf list" to find out the SDT markers
> present in that file. Usage is as below :
>
> # perf list sdt /home/hemant/tmp
>
> /home/hemant/tmp:
> %user : foo
> %user : bar
>
> Signed-off-by : [email protected]
> ---

[SNIP]
> +/*
> + * Finds out the libraries present in a system as shown by the command
> + * "ldconfig --print-cache". Uses "=>" and '/' to find out the start of a
> + * dso path.
> + */
> +static void parse_lib_name(char *str, char *path)
> +{
> + char *ptr, *q, *r;
> + char c = '=';
> +
> + while (str != NULL) {
> + /* look for "=>" and then '/' */
> + ptr = strchr(str, c);
> + if (ptr && (*(ptr + 1) == '>')) {

Hmm.. why not searching "=>" by strstr() then?


> + ptr++;
> + q = strchr(ptr, '/');
> + if (!q)
> + return;
> + r = strchr(ptr, '\n');
> + *r = '\0';
> + strcpy(path, q);
> + return;
> + } else if (ptr == NULL) {
> + return;
> + } else {
> + str = ptr + 1;
> + continue;
> + }
> + }
> +}

[SNIP]
> + /*
> + * Take a line from the o/p of ldconfig and
> + * parse it to find a library path
> + */
> + while (getline(&line, &len, fp) != -1) {
> + memset(path, '\0', PATH_MAX);
> + parse_lib_name(line, path);
> + if (strcmp(path, ""))

I think it'd better changing the parse_lib_name to return a value
instead of checking whether the path is an empty string.


> + append_path(path, &lib_list.list);
> + }
> + /* line and fp no more required */
> + free(line);
> + pclose(fp);
> +
> + /* Find and write the SDT markers in the perf-sdt cache*/
> + flush_sdt_list(&lib_list.list, cache);
> +
> + cleanup_path_list(&lib_list.list);
> + return;
> +}

[SNIP]
> +static int populate_sdt_note(Elf **elf, const char *data, size_t len, int type,
> + struct sdt_note **note)
> +{
> + const char *provider, *name;
> + struct sdt_note *tmp = NULL;
> + GElf_Ehdr ehdr;
> + GElf_Addr base_off = 0;
> + GElf_Shdr shdr;
> + int ret = -1;
> + int i;
> +
> + union {
> + Elf64_Addr a64[3];
> + Elf32_Addr a32[3];
> + } buf;
> +
> + Elf_Data dst = {
> + .d_buf = &buf, .d_type = ELF_T_ADDR, .d_version = EV_CURRENT,
> + .d_size = gelf_fsize((*elf), ELF_T_ADDR, 3, 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
> + };
> +
> + /* Check the type of each of the notes */
> + if (type != SDT_NOTE_TYPE)
> + goto out_err;
> +
> + 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)

Do we really need this xlate function? It seems elf_getdata() already
did necessary conversions so only thing we need to do is checking its
class and read out the addresses in a proper length, no?


> + printf("gelf_xlatetom : %s\n", elf_errmsg(-1));
> +
> + /* 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;
> + }
> +
> + /* Obtain the addresses */
> + if (gelf_getclass(*elf) == ELFCLASS32) {
> + for (i = 0; i < 3; i++)
> + tmp->addr.a32[i] = buf.a32[i];
> + tmp->bit32 = true;
> + } else {
> + for (i = 0; i < 3; i++)
> + tmp->addr.a64[i] = buf.a64[i];
> + tmp->bit32 = false;
> + }
> +
> + /* Now Adjust the prelink effect */
> + if (!gelf_getehdr(*elf, &ehdr)) {
> + pr_debug("%s : cannot get elf header.\n", __func__);
> + ret = -EBADF;
> + goto out_free_name;
> + }
> +
> + /*
> + * 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) {

Why not moving this block under the above if block?


> + 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];
> + }
> +
> + *note = tmp;
> + return 0;
> +
> +out_free_name:
> + free(tmp->name);
> +out_free_prov:
> + free(tmp->provider);
> +out_free_note:
> + free(tmp);
> +out_err:
> + return ret;
> +}
> +
> +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;
> + struct sdt_note *tmp = NULL;
> + int ret = 0, val = 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))) {
> + val = populate_sdt_note(&elf, ((data->d_buf) + desc_off),
> + nhdr.n_descsz, nhdr.n_type,
> + &tmp);
> + if (!val)
> + list_add_tail(&tmp->note_list, sdt_notes);
> + if (val == -ENOMEM) {
> + ret = val;
> + goto out_ret;
> + }
> + }
> + }
> + if (!sdt_notes)

Did you mean list_empty(sdt_notes) ? :)

Thanks,
Namhyung


> + Ret = -ENOENT;
> +
> +out_ret:
> + return ret;
> +}

2014-02-25 09:04:04

by Hemant Kumar

[permalink] [raw]
Subject: Re: [RFC PATCH v1 1/2] perf/sdt : Listing of SDT markers by perf

On 02/25/2014 12:26 PM, Namhyung Kim wrote:
> Hi Hemant,
>
> On Mon, 24 Feb 2014 14:45:43 +0530, Hemant Kumar wrote:
>> This patch enables perf to list the SDT markers present in a system. It looks
>> in dsos given by ldconfig --print-cache and for other binaries, it looks into
>> the PATH environment variable. After preparing a list of the binaries, then
>> it starts searching for SDT markers in them.
>> To find the SDT markers, first an elf section named .note.stapsdt is searched
>> for. And then the SDT notes are retreived one by one from that section.
>> To counter the effect of prelinking, the section ".stapsdt.base" is searched.
>> If its found, then the location of the SDT marker is adjusted.
>>
>> All these markers' info is written into a cache file
>> "/var/cache/perf/perf-sdt.cache".
>> Since, the presence of SDT markers is quite common these days, hence, its better
>> to make them visible to a user easily. Also, creating a cache file will help a user
>> to probe (to be implemented) these markers without much hussle. This cache file will
>> hold most of the SDT markers.
>> The format of each entry is -
>>
>> %provider : marker : file_path : build_id : location : semaphore_loc
>>
>> % - marks the beginning of each entry.
>> provider - The provider name of the SDT marker.
>> marker - The marker name of the SDT marker.
>> file_path - Full/absolute path of the file in which this marker is present.
>> location : Adjusted location of the SDT marker inside the program.
>> semaphore_loc : The semaphore address if present otherwise 0x0.
>>
>> This format should help when probing will be implemented. The adjusted address
>> from the required entry can be directly used in probing if the build_id matches.
>>
>> To use this feature, invoke :
>> # perf list sdt --scan
>>
>> "--scan" should be used for the first time and whenever there is any change in
>> the files containing the SDT markers.
>>
>> And then use :
>> # perf list sdt
>>
>> This displays a list of SDT markers (read from the cache file) present in most of
>> the dsos and other binaries.
> The default action of perf list (with no argument) prints all available
> events on the system - so it should also print SDT markers IMHO.

Right, but won't that list be huge?

>> However, not all the SDT markers are present in the cache file. Only the ELFs
>> present in the directories in PATH variable are looked into.
>> An individual file argument can be given to "perf list" to find out the SDT markers
>> present in that file. Usage is as below :
>>
>> # perf list sdt /home/hemant/tmp
>>
>> /home/hemant/tmp:
>> %user : foo
>> %user : bar
>>
>> Signed-off-by : [email protected]
>> ---
> [SNIP]
>> +/*
>> + * Finds out the libraries present in a system as shown by the command
>> + * "ldconfig --print-cache". Uses "=>" and '/' to find out the start of a
>> + * dso path.
>> + */
>> +static void parse_lib_name(char *str, char *path)
>> +{
>> + char *ptr, *q, *r;
>> + char c = '=';
>> +
>> + while (str != NULL) {
>> + /* look for "=>" and then '/' */
>> + ptr = strchr(str, c);
>> + if (ptr && (*(ptr + 1) == '>')) {
> Hmm.. why not searching "=>" by strstr() then?

Right! will change it to strstr.

>
>> + ptr++;
>> + q = strchr(ptr, '/');
>> + if (!q)
>> + return;
>> + r = strchr(ptr, '\n');
>> + *r = '\0';
>> + strcpy(path, q);
>> + return;
>> + } else if (ptr == NULL) {
>> + return;
>> + } else {
>> + str = ptr + 1;
>> + continue;
>> + }
>> + }
>> +}
> [SNIP]
>> + /*
>> + * Take a line from the o/p of ldconfig and
>> + * parse it to find a library path
>> + */
>> + while (getline(&line, &len, fp) != -1) {
>> + memset(path, '\0', PATH_MAX);
>> + parse_lib_name(line, path);
>> + if (strcmp(path, ""))
> I think it'd better changing the parse_lib_name to return a value
> instead of checking whether the path is an empty string.

Ok. Seems better!

>
>
>> + append_path(path, &lib_list.list);
>> + }
>> + /* line and fp no more required */
>> + free(line);
>> + pclose(fp);
>> +
>> + /* Find and write the SDT markers in the perf-sdt cache*/
>> + flush_sdt_list(&lib_list.list, cache);
>> +
>> + cleanup_path_list(&lib_list.list);
>> + return;
>> +}
> [SNIP]
>> +static int populate_sdt_note(Elf **elf, const char *data, size_t len, int type,
>> + struct sdt_note **note)
>> +{
>> + const char *provider, *name;
>> + struct sdt_note *tmp = NULL;
>> + GElf_Ehdr ehdr;
>> + GElf_Addr base_off = 0;
>> + GElf_Shdr shdr;
>> + int ret = -1;
>> + int i;
>> +
>> + union {
>> + Elf64_Addr a64[3];
>> + Elf32_Addr a32[3];
>> + } buf;
>> +
>> + Elf_Data dst = {
>> + .d_buf = &buf, .d_type = ELF_T_ADDR, .d_version = EV_CURRENT,
>> + .d_size = gelf_fsize((*elf), ELF_T_ADDR, 3, 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
>> + };
>> +
>> + /* Check the type of each of the notes */
>> + if (type != SDT_NOTE_TYPE)
>> + goto out_err;
>> +
>> + 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)
> Do we really need this xlate function? It seems elf_getdata() already
> did necessary conversions so only thing we need to do is checking its
> class and read out the addresses in a proper length, no?
>

Hmm, alright. I thought the conversion was necessary for cross developed
binaries.
But I guess elf_getdata() should do all these conversions. Will remove that.

>> + printf("gelf_xlatetom : %s\n", elf_errmsg(-1));
>> +
>> + /* 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;
>> + }
>> +
>> + /* Obtain the addresses */
>> + if (gelf_getclass(*elf) == ELFCLASS32) {
>> + for (i = 0; i < 3; i++)
>> + tmp->addr.a32[i] = buf.a32[i];
>> + tmp->bit32 = true;
>> + } else {
>> + for (i = 0; i < 3; i++)
>> + tmp->addr.a64[i] = buf.a64[i];
>> + tmp->bit32 = false;
>> + }
>> +
>> + /* Now Adjust the prelink effect */
>> + if (!gelf_getehdr(*elf, &ehdr)) {
>> + pr_debug("%s : cannot get elf header.\n", __func__);
>> + ret = -EBADF;
>> + goto out_free_name;
>> + }
>> +
>> + /*
>> + * 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) {
> Why not moving this block under the above if block?
>

Yeah, better! Will do it.

>> + 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];
>> + }
>> +
>> + *note = tmp;
>> + return 0;
>> +
>> +out_free_name:
>> + free(tmp->name);
>> +out_free_prov:
>> + free(tmp->provider);
>> +out_free_note:
>> + free(tmp);
>> +out_err:
>> + return ret;
>> +}
>> +
>> +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;
>> + struct sdt_note *tmp = NULL;
>> + int ret = 0, val = 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))) {
>> + val = populate_sdt_note(&elf, ((data->d_buf) + desc_off),
>> + nhdr.n_descsz, nhdr.n_type,
>> + &tmp);
>> + if (!val)
>> + list_add_tail(&tmp->note_list, sdt_notes);
>> + if (val == -ENOMEM) {
>> + ret = val;
>> + goto out_ret;
>> + }
>> + }
>> + }
>> + if (!sdt_notes)
> Did you mean list_empty(sdt_notes) ? :)

Oops! Yes, will fix it.

[SNIP]

Thanks a lot for reviewing the patch.

--
Thanks
Hemant Kumar

Subject: Re: [RFC PATCH v1 0/2] perf: Support for SDT markers

(2014/02/24 18:14), Hemant Kumar wrote:
> This patchset helps in listing dtrace style markers(SDT) present in user space
> applications through perf.
> Notes/markers are placed at important places by the
> developers. They have a negligible overhead when not enabled.
> We can enable them and probe at these places and find some important information
> like the arguments' values, etc.
>
> We have lots of applications which use SDT markers today, like:
> Postgresql, MySql, Mozilla, Perl, Python, Java, Ruby, libvirt, QEMU, glib
>
> To add SDT markers into user applications:
> We need to have this header sys/sdt.h present.
> sys/sdt.h used is version 3.
> If not present, install systemtap-sdt-devel package (for fedora-18).
>
> Please refer to the Documentation patch to see how the SDT markers are added into
> a program.
>
> With this patchset,
> - Use perf to list the markers in the app:
> # perf list sdt ./user_app
>
> ./user_app :
> %user_app:foo_start
> %user_app:fun_start
>
> - Also, we can see the SDT markers present in our system in the usual binaries.
> These usual binaries are libraries (dsos) listed by ldconfig --print-cache and some
> binaries present in PATH environment variable.
>
> First, scan the binaries using :
> # perf list sdt --scan
>
> Creating a cache of SDT markers...
> perf sdt cache created!
> Use : "perf list sdt"
> to see the SDT markers

Hmm, in that case, I think you'd better introduce perf-sdt for scanning.
e.g.

# perf sdt --scan app

then you can add app to sdt cache, without app,

# perf sdt --scan

will just scans all binaries on the PATH and the libraries which listed
by `ldconfig --print-caceh`

And perf-list shows only the SDTs in the cache.

If there is no SDTs in the cache, `perf-list sdt` will warn you to
run the `perf sdt --scan`.


>
> After the sdt cache file is created, use perf list to view the markers :
> # perf list sdt
>
> %rtld : init_start
> %rtld : init_complete
> %rtld : map_failed
> %rtld : map_start
> %rtld : lll_futex_wake
> ...
> ...
> %libgcc : unwind
> %libvirt : rpc_server_client_auth_allow
> %libvirt : rpc_server_client_auth_fail
> %libvirt : rpc_server_client_auth_deny
>
> Alternatively, one can view the /var/cache/perf/perf-sdt.cache directly.
>
> This link shows an example of marker probing with Systemtap:
> https://sourceware.org/systemtap/wiki/AddingUserSpaceProbingToApps
>
> Also, this link provides important info regarding SDT notes:
> http://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation
>
> - Markers in binaries :
> These SDT markers are present in the ELF in the section named
> ".note.stapsdt".
> Here, the name of the marker, its provider, type, location, base
> address, semaphore address.
> We can retrieve these values using the members name_off and desc_off in
> Nhdr structure. If these are not enabled, they are present in the ELF as nop.
>
> Changes since last series :
> - Made the SDT markers present in a system more visible through perf list
> as suggested by Pekka Enberg.
> - Less complex command line interface to access the SDT markers.
> - Added a cache file to store most of the SDT markers of a system.
>
> TODO:
> - Add support to probe these SDT markers and integrate with a previous patch
> (support to perf to probe SDT markers) posted in lkml.
> https://lkml.org/lkml/2013/10/23/10

Yeah, but I think we'd better choose another way to integrate it.
Since SDT is like markers(static events), setting each of them via perf-probe is
not intuitive. :) I'd like to use it as an event, e.g.

# perf top -e "%libgcc:unwind"

And perf top internally calls perf-probe to add new uprobe event, and
clean the new event at exit.


Thank you,

--
Masami HIRAMATSU
IT Management Research Dept. Linux Technology Center
Hitachi, Ltd., Yokohama Research Laboratory
E-mail: [email protected]

2014-02-25 15:57:17

by Hemant Kumar

[permalink] [raw]
Subject: Re: [RFC PATCH v1 0/2] perf: Support for SDT markers

On 02/25/2014 05:14 PM, Masami Hiramatsu wrote:
> (2014/02/24 18:14), Hemant Kumar wrote:
>> This patchset helps in listing dtrace style markers(SDT) present in user space
>> applications through perf.
>> Notes/markers are placed at important places by the
>> developers. They have a negligible overhead when not enabled.
>> We can enable them and probe at these places and find some important information
>> like the arguments' values, etc.
>>
>> We have lots of applications which use SDT markers today, like:
>> Postgresql, MySql, Mozilla, Perl, Python, Java, Ruby, libvirt, QEMU, glib
>>
>> To add SDT markers into user applications:
>> We need to have this header sys/sdt.h present.
>> sys/sdt.h used is version 3.
>> If not present, install systemtap-sdt-devel package (for fedora-18).
>>
>> Please refer to the Documentation patch to see how the SDT markers are added into
>> a program.
>>
>> With this patchset,
>> - Use perf to list the markers in the app:
>> # perf list sdt ./user_app
>>
>> ./user_app :
>> %user_app:foo_start
>> %user_app:fun_start
>>
>> - Also, we can see the SDT markers present in our system in the usual binaries.
>> These usual binaries are libraries (dsos) listed by ldconfig --print-cache and some
>> binaries present in PATH environment variable.
>>
>> First, scan the binaries using :
>> # perf list sdt --scan
>>
>> Creating a cache of SDT markers...
>> perf sdt cache created!
>> Use : "perf list sdt"
>> to see the SDT markers
> Hmm, in that case, I think you'd better introduce perf-sdt for scanning.
> e.g.
>
> # perf sdt --scan app

Hmm, this seems a better idea :)

> then you can add app to sdt cache, without app,
>
> # perf sdt --scan
>
> will just scans all binaries on the PATH and the libraries which listed
> by `ldconfig --print-caceh`
>
> And perf-list shows only the SDTs in the cache.

Well, what will be better? perf-list or perf-sdt or perf-list sdt??
If perf-list, then wouldn't it be a huge list!!

>
> If there is no SDTs in the cache, `perf-list sdt` will warn you to
> run the `perf sdt --scan`.

Right.

>
>> After the sdt cache file is created, use perf list to view the markers :
>> # perf list sdt
>>
>> %rtld : init_start
>> %rtld : init_complete
>> %rtld : map_failed
>> %rtld : map_start
>> %rtld : lll_futex_wake
>> ...
>> ...
>> %libgcc : unwind
>> %libvirt : rpc_server_client_auth_allow
>> %libvirt : rpc_server_client_auth_fail
>> %libvirt : rpc_server_client_auth_deny
>>
>> Alternatively, one can view the /var/cache/perf/perf-sdt.cache directly.
>>
>> This link shows an example of marker probing with Systemtap:
>> https://sourceware.org/systemtap/wiki/AddingUserSpaceProbingToApps
>>
>> Also, this link provides important info regarding SDT notes:
>> http://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation
>>
>> - Markers in binaries :
>> These SDT markers are present in the ELF in the section named
>> ".note.stapsdt".
>> Here, the name of the marker, its provider, type, location, base
>> address, semaphore address.
>> We can retrieve these values using the members name_off and desc_off in
>> Nhdr structure. If these are not enabled, they are present in the ELF as nop.
>>
>> Changes since last series :
>> - Made the SDT markers present in a system more visible through perf list
>> as suggested by Pekka Enberg.
>> - Less complex command line interface to access the SDT markers.
>> - Added a cache file to store most of the SDT markers of a system.
>>
>> TODO:
>> - Add support to probe these SDT markers and integrate with a previous patch
>> (support to perf to probe SDT markers) posted in lkml.
>> https://lkml.org/lkml/2013/10/23/10
> Yeah, but I think we'd better choose another way to integrate it.
> Since SDT is like markers(static events), setting each of them via perf-probe is
> not intuitive. :) I'd like to use it as an event, e.g.
>
> # perf top -e "%libgcc:unwind"
>
> And perf top internally calls perf-probe to add new uprobe event, and
> clean the new event at exit.
>
>
>

Yeah! Right :) Makes sense.

Will implement the suggestions in the next version asap!

--
Thanks
Hemant Kumar

2014-02-26 07:58:07

by Namhyung Kim

[permalink] [raw]
Subject: Re: [RFC PATCH v1 1/2] perf/sdt : Listing of SDT markers by perf

Hi Hemant,

On Tue, 25 Feb 2014 14:33:37 +0530, Hemant Kumar wrote:
> On 02/25/2014 12:26 PM, Namhyung Kim wrote:
>>> + /* Translation from file representation to memory representation */
>>> + if (gelf_xlatetom(*elf, &dst, &src,
>>> + elf_getident(*elf, NULL)[EI_DATA]) == NULL)
>> Do we really need this xlate function? It seems elf_getdata() already
>> did necessary conversions so only thing we need to do is checking its
>> class and read out the addresses in a proper length, no?
>>
>
> Hmm, alright. I thought the conversion was necessary for cross
> developed binaries.
> But I guess elf_getdata() should do all these conversions. Will remove that.

Looking at the source, it seems we still need to xlate() anyway. The
conversion function (elf_cvt_note) only handles the header part since it
cannot know what the content is.

But obviously we cannot enable/disable the marker as we cannot run the
cross-built binary - it only can be used to show the list of SDT markers
in the binary. Or else, we can simply deny to do it..

Thanks,
Namhyung

2014-02-26 08:18:35

by Namhyung Kim

[permalink] [raw]
Subject: Re: [RFC PATCH v1 0/2] perf: Support for SDT markers

Hi Masami and Hemant,

On Tue, 25 Feb 2014 21:27:07 +0530, Hemant Kumar wrote:
> On 02/25/2014 05:14 PM, Masami Hiramatsu wrote:
>> (2014/02/24 18:14), Hemant Kumar wrote:
>>> First, scan the binaries using :
>>> # perf list sdt --scan
>>>
>>> Creating a cache of SDT markers...
>>> perf sdt cache created!
>>> Use : "perf list sdt"
>>> to see the SDT markers
>> Hmm, in that case, I think you'd better introduce perf-sdt for scanning.
>> e.g.
>>
>> # perf sdt --scan app
>
> Hmm, this seems a better idea :)
>
>> then you can add app to sdt cache, without app,
>>
>> # perf sdt --scan
>>
>> will just scans all binaries on the PATH and the libraries which listed
>> by `ldconfig --print-caceh`

What should be done with the new perf sdt command? If it's only
intended to list the markers, I'd just suggest to add "perf list sdt" as
this patch did.

Plus I think it'd be better if event_glob pattern also looks for sdt
markers so that user can find out a specific markers easily, e.g.:

# perf list rtld:*

or

# perf list %rtld:*

>>
>> And perf-list shows only the SDTs in the cache.
>
> Well, what will be better? perf-list or perf-sdt or perf-list sdt??
> If perf-list, then wouldn't it be a huge list!!

The output of perf list is already a huge list and we paginate it. So I
don't think it's gonna be a problem. :)


>>> - Add support to probe these SDT markers and integrate with a previous patch
>>> (support to perf to probe SDT markers) posted in lkml.
>>> https://lkml.org/lkml/2013/10/23/10
>> Yeah, but I think we'd better choose another way to integrate it.
>> Since SDT is like markers(static events), setting each of them via perf-probe is
>> not intuitive. :) I'd like to use it as an event, e.g.
>>
>> # perf top -e "%libgcc:unwind"
>>
>> And perf top internally calls perf-probe to add new uprobe event, and
>> clean the new event at exit.
>
> Yeah! Right :) Makes sense.
>
> Will implement the suggestions in the next version asap!

That would be great!

Thanks,
Namhyung

2014-02-26 09:03:53

by Hemant Kumar

[permalink] [raw]
Subject: Re: [RFC PATCH v1 0/2] perf: Support for SDT markers

On 02/26/2014 01:48 PM, Namhyung Kim wrote:
> Hi Masami and Hemant,
>
> On Tue, 25 Feb 2014 21:27:07 +0530, Hemant Kumar wrote:
>> On 02/25/2014 05:14 PM, Masami Hiramatsu wrote:
>>> (2014/02/24 18:14), Hemant Kumar wrote:
>>>> First, scan the binaries using :
>>>> # perf list sdt --scan
>>>>
>>>> Creating a cache of SDT markers...
>>>> perf sdt cache created!
>>>> Use : "perf list sdt"
>>>> to see the SDT markers
>>> Hmm, in that case, I think you'd better introduce perf-sdt for scanning.
>>> e.g.
>>>
>>> # perf sdt --scan app
>> Hmm, this seems a better idea :)
>>
>>> then you can add app to sdt cache, without app,
>>>
>>> # perf sdt --scan
>>>
>>> will just scans all binaries on the PATH and the libraries which listed
>>> by `ldconfig --print-caceh`
> What should be done with the new perf sdt command? If it's only
> intended to list the markers, I'd just suggest to add "perf list sdt" as
> this patch did.

If we display the SDT markers along with the other events in perf list,
then I think we can go with
perf list sdt. I am not too sure though! :)

For me, the main issue was that the markers are not events. They become
events after
we place them in the uprobe_events file just like functions. But we use
`perf list` to
display all the "events" available on a system. Isn't it?

> Plus I think it'd be better if event_glob pattern also looks for sdt
> markers so that user can find out a specific markers easily, e.g.:
>
> # perf list rtld:*
>
> or
>
> # perf list %rtld:*

Good idea! Will surely include support for this in event_glob pattern.

>>> And perf-list shows only the SDTs in the cache.
>> Well, what will be better? perf-list or perf-sdt or perf-list sdt??
>> If perf-list, then wouldn't it be a huge list!!
> The output of perf list is already a huge list and we paginate it. So I
> don't think it's gonna be a problem. :)

Ok! Then we can use perf list. :)

>
>>>> - Add support to probe these SDT markers and integrate with a previous patch
>>>> (support to perf to probe SDT markers) posted in lkml.
>>>> https://lkml.org/lkml/2013/10/23/10
>>> Yeah, but I think we'd better choose another way to integrate it.
>>> Since SDT is like markers(static events), setting each of them via perf-probe is
>>> not intuitive. :) I'd like to use it as an event, e.g.
>>>
>>> # perf top -e "%libgcc:unwind"
>>>
>>> And perf top internally calls perf-probe to add new uprobe event, and
>>> clean the new event at exit.
>> Yeah! Right :) Makes sense.
>>
>> Will implement the suggestions in the next version asap!
> That would be great!

--
Thanks
Hemant Kumar

Subject: Re: Re: [RFC PATCH v1 0/2] perf: Support for SDT markers

(2014/02/26 17:18), Namhyung Kim wrote:
> Hi Masami and Hemant,
>
> On Tue, 25 Feb 2014 21:27:07 +0530, Hemant Kumar wrote:
>> On 02/25/2014 05:14 PM, Masami Hiramatsu wrote:
>>> (2014/02/24 18:14), Hemant Kumar wrote:
>>>> First, scan the binaries using :
>>>> # perf list sdt --scan
>>>>
>>>> Creating a cache of SDT markers...
>>>> perf sdt cache created!
>>>> Use : "perf list sdt"
>>>> to see the SDT markers
>>> Hmm, in that case, I think you'd better introduce perf-sdt for scanning.
>>> e.g.
>>>
>>> # perf sdt --scan app
>>
>> Hmm, this seems a better idea :)
>>
>>> then you can add app to sdt cache, without app,
>>>
>>> # perf sdt --scan
>>>
>>> will just scans all binaries on the PATH and the libraries which listed
>>> by `ldconfig --print-caceh`
>
> What should be done with the new perf sdt command? If it's only
> intended to list the markers, I'd just suggest to add "perf list sdt" as
> this patch did.
>
> Plus I think it'd be better if event_glob pattern also looks for sdt
> markers so that user can find out a specific markers easily, e.g.:
>
> # perf list rtld:*
>
> or
>
> # perf list %rtld:*

Ah, that's a good idea :)

>>>
>>> And perf-list shows only the SDTs in the cache.
>>
>> Well, what will be better? perf-list or perf-sdt or perf-list sdt??
>> If perf-list, then wouldn't it be a huge list!!
>
> The output of perf list is already a huge list and we paginate it. So I
> don't think it's gonna be a problem. :)

Agreed.

>>>> - Add support to probe these SDT markers and integrate with a previous patch
>>>> (support to perf to probe SDT markers) posted in lkml.
>>>> https://lkml.org/lkml/2013/10/23/10
>>> Yeah, but I think we'd better choose another way to integrate it.
>>> Since SDT is like markers(static events), setting each of them via perf-probe is
>>> not intuitive. :) I'd like to use it as an event, e.g.
>>>
>>> # perf top -e "%libgcc:unwind"
>>>
>>> And perf top internally calls perf-probe to add new uprobe event, and
>>> clean the new event at exit.
>>
>> Yeah! Right :) Makes sense.

Note that we will need an option to make it permanent (not clear the event on exit)
for people who want to use SDT event from ftrace. :)

>> Will implement the suggestions in the next version asap!
>
> That would be great!

Thank you!


--
Masami HIRAMATSU
IT Management Research Dept. Linux Technology Center
Hitachi, Ltd., Yokohama Research Laboratory
E-mail: [email protected]

Subject: Re: Re: [RFC PATCH v1 0/2] perf: Support for SDT markers

(2014/02/26 18:03), Hemant Kumar wrote:
> On 02/26/2014 01:48 PM, Namhyung Kim wrote:
>> Hi Masami and Hemant,
>>
>> On Tue, 25 Feb 2014 21:27:07 +0530, Hemant Kumar wrote:
>>> On 02/25/2014 05:14 PM, Masami Hiramatsu wrote:
>>>> (2014/02/24 18:14), Hemant Kumar wrote:
>>>>> First, scan the binaries using :
>>>>> # perf list sdt --scan
>>>>>
>>>>> Creating a cache of SDT markers...
>>>>> perf sdt cache created!
>>>>> Use : "perf list sdt"
>>>>> to see the SDT markers
>>>> Hmm, in that case, I think you'd better introduce perf-sdt for scanning.
>>>> e.g.
>>>>
>>>> # perf sdt --scan app
>>> Hmm, this seems a better idea :)
>>>
>>>> then you can add app to sdt cache, without app,
>>>>
>>>> # perf sdt --scan
>>>>
>>>> will just scans all binaries on the PATH and the libraries which listed
>>>> by `ldconfig --print-caceh`
>> What should be done with the new perf sdt command? If it's only
>> intended to list the markers, I'd just suggest to add "perf list sdt" as
>> this patch did.

No, here what I said is, the "perf sdt" is only for managing SDT cache
as like as "perf buildid-cache". Thus, "perf sdt-cache" might be better.

BTW, the SDT markers can be changed if the application is updated.
To ensure the correctness of SDT markers, we should store buildid in the
cache file and check it when listing and using them.

> If we display the SDT markers along with the other events in perf list,
> then I think we can go with
> perf list sdt. I am not too sure though! :)
>
> For me, the main issue was that the markers are not events. They become
> events after
> we place them in the uprobe_events file just like functions. But we use
> `perf list` to
> display all the "events" available on a system. Isn't it?

As I said, if perf accepts -e "%app:sdt" option, showing SDT events as
fixed events does not matter, since it is transparent to users. :)

Thank you,

--
Masami HIRAMATSU
IT Management Research Dept. Linux Technology Center
Hitachi, Ltd., Yokohama Research Laboratory
E-mail: [email protected]

2014-02-26 16:12:07

by Hemant Kumar

[permalink] [raw]
Subject: Re: [RFC PATCH v1 0/2] perf: Support for SDT markers

On 02/26/2014 03:12 PM, Masami Hiramatsu wrote:
> (2014/02/26 18:03), Hemant Kumar wrote:
>> On 02/26/2014 01:48 PM, Namhyung Kim wrote:
>>> Hi Masami and Hemant,
>>>
>>> On Tue, 25 Feb 2014 21:27:07 +0530, Hemant Kumar wrote:
>>>> On 02/25/2014 05:14 PM, Masami Hiramatsu wrote:
>>>>> (2014/02/24 18:14), Hemant Kumar wrote:
>>>>>> First, scan the binaries using :
>>>>>> # perf list sdt --scan
>>>>>>
>>>>>> Creating a cache of SDT markers...
>>>>>> perf sdt cache created!
>>>>>> Use : "perf list sdt"
>>>>>> to see the SDT markers
>>>>> Hmm, in that case, I think you'd better introduce perf-sdt for scanning.
>>>>> e.g.
>>>>>
>>>>> # perf sdt --scan app
>>>> Hmm, this seems a better idea :)
>>>>
>>>>> then you can add app to sdt cache, without app,
>>>>>
>>>>> # perf sdt --scan
>>>>>
>>>>> will just scans all binaries on the PATH and the libraries which listed
>>>>> by `ldconfig --print-caceh`
>>> What should be done with the new perf sdt command? If it's only
>>> intended to list the markers, I'd just suggest to add "perf list sdt" as
>>> this patch did.
> No, here what I said is, the "perf sdt" is only for managing SDT cache
> as like as "perf buildid-cache". Thus, "perf sdt-cache" might be better.

Ah! ok.

> BTW, the SDT markers can be changed if the application is updated.
> To ensure the correctness of SDT markers, we should store buildid in the
> cache file and check it when listing and using them.

Yeah! That's why perf list sdt --scan is storing the buildid too in the
cache file.

>> If we display the SDT markers along with the other events in perf list,
>> then I think we can go with
>> perf list sdt. I am not too sure though! :)
>>
>> For me, the main issue was that the markers are not events. They become
>> events after
>> we place them in the uprobe_events file just like functions. But we use
>> `perf list` to
>> display all the "events" available on a system. Isn't it?
> As I said, if perf accepts -e "%app:sdt" option, showing SDT events as
> fixed events does not matter, since it is transparent to users. :)
>
> Thank you,
>

Alright. Got it! :)

--
Thanks
Hemant Kumar