perf record: Introduce a symtab cache
[safe/jmp/linux-2.6] / tools / perf / util / symbol.c
index 17ce012..79ca6a0 100644 (file)
@@ -1,6 +1,7 @@
 #include "util.h"
 #include "../perf.h"
 #include "session.h"
+#include "sort.h"
 #include "string.h"
 #include "symbol.h"
 #include "thread.h"
@@ -21,6 +22,7 @@
 enum dso_origin {
        DSO__ORIG_KERNEL = 0,
        DSO__ORIG_JAVA_JIT,
+       DSO__ORIG_BUILD_ID_CACHE,
        DSO__ORIG_FEDORA,
        DSO__ORIG_UBUNTU,
        DSO__ORIG_BUILDID,
@@ -37,6 +39,7 @@ static int vmlinux_path__nr_entries;
 static char **vmlinux_path;
 
 struct symbol_conf symbol_conf = {
+       .exclude_other    = true,
        .use_modules      = true,
        .try_vmlinux_path = true,
 };
@@ -1189,6 +1192,7 @@ char dso__symtab_origin(const struct dso *self)
        static const char origin[] = {
                [DSO__ORIG_KERNEL] =   'k',
                [DSO__ORIG_JAVA_JIT] = 'j',
+               [DSO__ORIG_BUILD_ID_CACHE] = 'B',
                [DSO__ORIG_FEDORA] =   'f',
                [DSO__ORIG_UBUNTU] =   'u',
                [DSO__ORIG_BUILDID] =  'b',
@@ -1207,6 +1211,7 @@ int dso__load(struct dso *self, struct map *map, struct perf_session *session,
        int size = PATH_MAX;
        char *name;
        u8 build_id[BUILD_ID_SIZE];
+       char build_id_hex[BUILD_ID_SIZE * 2 + 1];
        int ret = -1;
        int fd;
 
@@ -1228,8 +1233,16 @@ int dso__load(struct dso *self, struct map *map, struct perf_session *session,
                return ret;
        }
 
-       self->origin = DSO__ORIG_FEDORA - 1;
+       self->origin = DSO__ORIG_BUILD_ID_CACHE;
 
+       if (self->has_build_id) {
+               build_id__sprintf(self->build_id, sizeof(self->build_id),
+                                 build_id_hex);
+               snprintf(name, size, "%s/%s/.build-id/%.2s/%s",
+                        getenv("HOME"), DEBUG_CACHE_DIR,
+                        build_id_hex, build_id_hex + 2);
+               goto open_file;
+       }
 more:
        do {
                self->origin++;
@@ -1245,8 +1258,6 @@ more:
                case DSO__ORIG_BUILDID:
                        if (filename__read_build_id(self->long_name, build_id,
                                                    sizeof(build_id))) {
-                               char build_id_hex[BUILD_ID_SIZE * 2 + 1];
-
                                build_id__sprintf(build_id, sizeof(build_id),
                                                  build_id_hex);
                                snprintf(name, size,
@@ -1274,7 +1285,7 @@ compare_build_id:
                        if (!dso__build_id_equal(self, build_id))
                                goto more;
                }
-
+open_file:
                fd = open(name, O_RDONLY);
        } while (fd < 0);
 
@@ -1739,6 +1750,20 @@ out_fail:
        return -1;
 }
 
+static int setup_list(struct strlist **list, const char *list_str,
+                     const char *list_name)
+{
+       if (list_str == NULL)
+               return 0;
+
+       *list = strlist__new(true, list_str);
+       if (!*list) {
+               pr_err("problems parsing %s list\n", list_name);
+               return -1;
+       }
+       return 0;
+}
+
 int symbol__init(void)
 {
        elf_version(EV_CURRENT);
@@ -1749,7 +1774,30 @@ int symbol__init(void)
        if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
                return -1;
 
+       if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
+               pr_err("'.' is the only non valid --field-separator argument\n");
+               return -1;
+       }
+
+       if (setup_list(&symbol_conf.dso_list,
+                      symbol_conf.dso_list_str, "dso") < 0)
+               return -1;
+
+       if (setup_list(&symbol_conf.comm_list,
+                      symbol_conf.comm_list_str, "comm") < 0)
+               goto out_free_dso_list;
+
+       if (setup_list(&symbol_conf.sym_list,
+                      symbol_conf.sym_list_str, "symbol") < 0)
+               goto out_free_comm_list;
+
        return 0;
+
+out_free_dso_list:
+       strlist__delete(symbol_conf.dso_list);
+out_free_comm_list:
+       strlist__delete(symbol_conf.comm_list);
+       return -1;
 }
 
 int perf_session__create_kernel_maps(struct perf_session *self)