summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Makefile40
-rw-r--r--tools/perf/arch/arm/Makefile4
-rw-r--r--tools/perf/arch/arm/util/dwarf-regs.c64
-rw-r--r--tools/perf/arch/sparc/Makefile4
-rw-r--r--tools/perf/arch/sparc/util/dwarf-regs.c43
-rw-r--r--tools/perf/builtin-record.c2
-rw-r--r--tools/perf/builtin-report.c2
-rwxr-xr-xtools/perf/util/PERF-VERSION-GEN17
-rw-r--r--tools/perf/util/callchain.c35
-rw-r--r--tools/perf/util/callchain.h5
-rw-r--r--tools/perf/util/event.c4
-rw-r--r--tools/perf/util/hist.c29
-rw-r--r--tools/perf/util/newt.c15
-rw-r--r--tools/perf/util/session.c11
-rw-r--r--tools/perf/util/session.h2
-rw-r--r--tools/perf/util/symbol.c17
-rw-r--r--tools/perf/util/thread.c11
-rw-r--r--tools/perf/util/thread.h5
18 files changed, 244 insertions, 66 deletions
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 3d8f31ed771..d75c28a825f 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -600,30 +600,32 @@ endif
ifdef NO_DEMANGLE
BASIC_CFLAGS += -DNO_DEMANGLE
-else ifdef HAVE_CPLUS_DEMANGLE
- EXTLIBS += -liberty
- BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
else
- has_bfd := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd "$(QUIET_STDERR)" && echo y")
-
- ifeq ($(has_bfd),y)
- EXTLIBS += -lbfd
+ ifdef HAVE_CPLUS_DEMANGLE
+ EXTLIBS += -liberty
+ BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
else
- has_bfd_iberty := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty "$(QUIET_STDERR)" && echo y")
- ifeq ($(has_bfd_iberty),y)
- EXTLIBS += -lbfd -liberty
+ has_bfd := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd "$(QUIET_STDERR)" && echo y")
+
+ ifeq ($(has_bfd),y)
+ EXTLIBS += -lbfd
else
- has_bfd_iberty_z := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty -lz "$(QUIET_STDERR)" && echo y")
- ifeq ($(has_bfd_iberty_z),y)
- EXTLIBS += -lbfd -liberty -lz
+ has_bfd_iberty := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty "$(QUIET_STDERR)" && echo y")
+ ifeq ($(has_bfd_iberty),y)
+ EXTLIBS += -lbfd -liberty
else
- has_cplus_demangle := $(shell sh -c "(echo 'extern char *cplus_demangle(const char *, int);'; echo 'int main(void) { cplus_demangle(0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -liberty "$(QUIET_STDERR)" && echo y")
- ifeq ($(has_cplus_demangle),y)
- EXTLIBS += -liberty
- BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
+ has_bfd_iberty_z := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty -lz "$(QUIET_STDERR)" && echo y")
+ ifeq ($(has_bfd_iberty_z),y)
+ EXTLIBS += -lbfd -liberty -lz
else
- msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling)
- BASIC_CFLAGS += -DNO_DEMANGLE
+ has_cplus_demangle := $(shell sh -c "(echo 'extern char *cplus_demangle(const char *, int);'; echo 'int main(void) { cplus_demangle(0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -liberty "$(QUIET_STDERR)" && echo y")
+ ifeq ($(has_cplus_demangle),y)
+ EXTLIBS += -liberty
+ BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
+ else
+ msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling)
+ BASIC_CFLAGS += -DNO_DEMANGLE
+ endif
endif
endif
endif
diff --git a/tools/perf/arch/arm/Makefile b/tools/perf/arch/arm/Makefile
new file mode 100644
index 00000000000..15130b50dfe
--- /dev/null
+++ b/tools/perf/arch/arm/Makefile
@@ -0,0 +1,4 @@
+ifndef NO_DWARF
+PERF_HAVE_DWARF_REGS := 1
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
+endif
diff --git a/tools/perf/arch/arm/util/dwarf-regs.c b/tools/perf/arch/arm/util/dwarf-regs.c
new file mode 100644
index 00000000000..fff6450c8c9
--- /dev/null
+++ b/tools/perf/arch/arm/util/dwarf-regs.c
@@ -0,0 +1,64 @@
+/*
+ * Mapping of DWARF debug register numbers into register names.
+ *
+ * Copyright (C) 2010 Will Deacon, ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <libio.h>
+#include <dwarf-regs.h>
+
+struct pt_regs_dwarfnum {
+ const char *name;
+ unsigned int dwarfnum;
+};
+
+#define STR(s) #s
+#define REG_DWARFNUM_NAME(r, num) {.name = r, .dwarfnum = num}
+#define GPR_DWARFNUM_NAME(num) \
+ {.name = STR(%r##num), .dwarfnum = num}
+#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0}
+
+/*
+ * Reference:
+ * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0040a/IHI0040A_aadwarf.pdf
+ */
+static const struct pt_regs_dwarfnum regdwarfnum_table[] = {
+ GPR_DWARFNUM_NAME(0),
+ GPR_DWARFNUM_NAME(1),
+ GPR_DWARFNUM_NAME(2),
+ GPR_DWARFNUM_NAME(3),
+ GPR_DWARFNUM_NAME(4),
+ GPR_DWARFNUM_NAME(5),
+ GPR_DWARFNUM_NAME(6),
+ GPR_DWARFNUM_NAME(7),
+ GPR_DWARFNUM_NAME(8),
+ GPR_DWARFNUM_NAME(9),
+ GPR_DWARFNUM_NAME(10),
+ REG_DWARFNUM_NAME("%fp", 11),
+ REG_DWARFNUM_NAME("%ip", 12),
+ REG_DWARFNUM_NAME("%sp", 13),
+ REG_DWARFNUM_NAME("%lr", 14),
+ REG_DWARFNUM_NAME("%pc", 15),
+ REG_DWARFNUM_END,
+};
+
+/**
+ * get_arch_regstr() - lookup register name from it's DWARF register number
+ * @n: the DWARF register number
+ *
+ * get_arch_regstr() returns the name of the register in struct
+ * regdwarfnum_table from it's DWARF register number. If the register is not
+ * found in the table, this returns NULL;
+ */
+const char *get_arch_regstr(unsigned int n)
+{
+ const struct pt_regs_dwarfnum *roff;
+ for (roff = regdwarfnum_table; roff->name != NULL; roff++)
+ if (roff->dwarfnum == n)
+ return roff->name;
+ return NULL;
+}
diff --git a/tools/perf/arch/sparc/Makefile b/tools/perf/arch/sparc/Makefile
new file mode 100644
index 00000000000..15130b50dfe
--- /dev/null
+++ b/tools/perf/arch/sparc/Makefile
@@ -0,0 +1,4 @@
+ifndef NO_DWARF
+PERF_HAVE_DWARF_REGS := 1
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
+endif
diff --git a/tools/perf/arch/sparc/util/dwarf-regs.c b/tools/perf/arch/sparc/util/dwarf-regs.c
new file mode 100644
index 00000000000..0ab88483720
--- /dev/null
+++ b/tools/perf/arch/sparc/util/dwarf-regs.c
@@ -0,0 +1,43 @@
+/*
+ * Mapping of DWARF debug register numbers into register names.
+ *
+ * Copyright (C) 2010 David S. Miller <davem@davemloft.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <libio.h>
+#include <dwarf-regs.h>
+
+#define SPARC_MAX_REGS 96
+
+const char *sparc_regs_table[SPARC_MAX_REGS] = {
+ "%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7",
+ "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%sp", "%o7",
+ "%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7",
+ "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%fp", "%i7",
+ "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7",
+ "%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15",
+ "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23",
+ "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31",
+ "%f32", "%f33", "%f34", "%f35", "%f36", "%f37", "%f38", "%f39",
+ "%f40", "%f41", "%f42", "%f43", "%f44", "%f45", "%f46", "%f47",
+ "%f48", "%f49", "%f50", "%f51", "%f52", "%f53", "%f54", "%f55",
+ "%f56", "%f57", "%f58", "%f59", "%f60", "%f61", "%f62", "%f63",
+};
+
+/**
+ * get_arch_regstr() - lookup register name from it's DWARF register number
+ * @n: the DWARF register number
+ *
+ * get_arch_regstr() returns the name of the register in struct
+ * regdwarfnum_table from it's DWARF register number. If the register is not
+ * found in the table, this returns NULL;
+ */
+const char *get_arch_regstr(unsigned int n)
+{
+ return (n <= SPARC_MAX_REGS) ? sparc_regs_table[n] : NULL;
+}
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index dc3435e18bd..711745f56bb 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -193,7 +193,7 @@ static void sig_handler(int sig)
static void sig_atexit(void)
{
- if (child_pid != -1)
+ if (child_pid > 0)
kill(child_pid, SIGTERM);
if (signr == -1)
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 35920578296..fd7407c7205 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -107,7 +107,7 @@ static int perf_session__add_hist_entry(struct perf_session *self,
goto out_free_syms;
err = 0;
if (symbol_conf.use_callchain) {
- err = append_chain(he->callchain, data->callchain, syms);
+ err = append_chain(he->callchain, data->callchain, syms, data->period);
if (err)
goto out_free_syms;
}
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN
index 49ece792191..97d76562a1a 100755
--- a/tools/perf/util/PERF-VERSION-GEN
+++ b/tools/perf/util/PERF-VERSION-GEN
@@ -5,17 +5,13 @@ if [ $# -eq 1 ] ; then
fi
GVF=${OUTPUT}PERF-VERSION-FILE
-DEF_VER=v0.0.2.PERF
LF='
'
-# First see if there is a version file (included in release tarballs),
-# then try git-describe, then default.
-if test -f version
-then
- VN=$(cat version) || VN="$DEF_VER"
-elif test -d .git -o -f .git &&
+# First check if there is a .git to get the version from git describe
+# otherwise try to get the version from the kernel makefile
+if test -d ../../.git -o -f ../../.git &&
VN=$(git describe --abbrev=4 HEAD 2>/dev/null) &&
case "$VN" in
*$LF*) (exit 1) ;;
@@ -27,7 +23,12 @@ elif test -d .git -o -f .git &&
then
VN=$(echo "$VN" | sed -e 's/-/./g');
else
- VN="$DEF_VER"
+ eval `grep '^VERSION\s*=' ../../Makefile|tr -d ' '`
+ eval `grep '^PATCHLEVEL\s*=' ../../Makefile|tr -d ' '`
+ eval `grep '^SUBLEVEL\s*=' ../../Makefile|tr -d ' '`
+ eval `grep '^EXTRAVERSION\s*=' ../../Makefile|tr -d ' '`
+
+ VN="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}${EXTRAVERSION}"
fi
VN=$(expr "$VN" : v*'\(.*\)')
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 62b69ad4aa7..52c777e451e 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -230,7 +230,7 @@ fill_node(struct callchain_node *node, struct resolved_chain *chain, int start)
static void
add_child(struct callchain_node *parent, struct resolved_chain *chain,
- int start)
+ int start, u64 period)
{
struct callchain_node *new;
@@ -238,7 +238,7 @@ add_child(struct callchain_node *parent, struct resolved_chain *chain,
fill_node(new, chain, start);
new->children_hit = 0;
- new->hit = 1;
+ new->hit = period;
}
/*
@@ -248,7 +248,8 @@ add_child(struct callchain_node *parent, struct resolved_chain *chain,
*/
static void
split_add_child(struct callchain_node *parent, struct resolved_chain *chain,
- struct callchain_list *to_split, int idx_parents, int idx_local)
+ struct callchain_list *to_split, int idx_parents, int idx_local,
+ u64 period)
{
struct callchain_node *new;
struct list_head *old_tail;
@@ -275,41 +276,41 @@ split_add_child(struct callchain_node *parent, struct resolved_chain *chain,
/* create a new child for the new branch if any */
if (idx_total < chain->nr) {
parent->hit = 0;
- add_child(parent, chain, idx_total);
- parent->children_hit++;
+ add_child(parent, chain, idx_total, period);
+ parent->children_hit += period;
} else {
- parent->hit = 1;
+ parent->hit = period;
}
}
static int
__append_chain(struct callchain_node *root, struct resolved_chain *chain,
- unsigned int start);
+ unsigned int start, u64 period);
static void
__append_chain_children(struct callchain_node *root,
struct resolved_chain *chain,
- unsigned int start)
+ unsigned int start, u64 period)
{
struct callchain_node *rnode;
/* lookup in childrens */
chain_for_each_child(rnode, root) {
- unsigned int ret = __append_chain(rnode, chain, start);
+ unsigned int ret = __append_chain(rnode, chain, start, period);
if (!ret)
goto inc_children_hit;
}
/* nothing in children, add to the current node */
- add_child(root, chain, start);
+ add_child(root, chain, start, period);
inc_children_hit:
- root->children_hit++;
+ root->children_hit += period;
}
static int
__append_chain(struct callchain_node *root, struct resolved_chain *chain,
- unsigned int start)
+ unsigned int start, u64 period)
{
struct callchain_list *cnode;
unsigned int i = start;
@@ -345,18 +346,18 @@ __append_chain(struct callchain_node *root, struct resolved_chain *chain,
/* we match only a part of the node. Split it and add the new chain */
if (i - start < root->val_nr) {
- split_add_child(root, chain, cnode, start, i - start);
+ split_add_child(root, chain, cnode, start, i - start, period);
return 0;
}
/* we match 100% of the path, increment the hit */
if (i - start == root->val_nr && i == chain->nr) {
- root->hit++;
+ root->hit += period;
return 0;
}
/* We match the node and still have a part remaining */
- __append_chain_children(root, chain, i);
+ __append_chain_children(root, chain, i, period);
return 0;
}
@@ -380,7 +381,7 @@ static void filter_context(struct ip_callchain *old, struct resolved_chain *new,
int append_chain(struct callchain_node *root, struct ip_callchain *chain,
- struct map_symbol *syms)
+ struct map_symbol *syms, u64 period)
{
struct resolved_chain *filtered;
@@ -397,7 +398,7 @@ int append_chain(struct callchain_node *root, struct ip_callchain *chain,
if (!filtered->nr)
goto end;
- __append_chain_children(root, filtered, 0);
+ __append_chain_children(root, filtered, 0, period);
end:
free(filtered);
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 1ca73e4a272..f2e9ee164bd 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -49,6 +49,9 @@ static inline void callchain_init(struct callchain_node *node)
INIT_LIST_HEAD(&node->brothers);
INIT_LIST_HEAD(&node->children);
INIT_LIST_HEAD(&node->val);
+
+ node->parent = NULL;
+ node->hit = 0;
}
static inline u64 cumul_hits(struct callchain_node *node)
@@ -58,7 +61,7 @@ static inline u64 cumul_hits(struct callchain_node *node)
int register_callchain_param(struct callchain_param *param);
int append_chain(struct callchain_node *root, struct ip_callchain *chain,
- struct map_symbol *syms);
+ struct map_symbol *syms, u64 period);
bool ip_callchain__valid(struct ip_callchain *chain, event_t *event);
#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 1f08f008d28..2fbf6a463c8 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -538,8 +538,10 @@ int event__process_task(event_t *self, struct perf_session *session)
dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
self->fork.ppid, self->fork.ptid);
- if (self->header.type == PERF_RECORD_EXIT)
+ if (self->header.type == PERF_RECORD_EXIT) {
+ perf_session__remove_thread(session, thread);
return 0;
+ }
if (thread == NULL || parent == NULL ||
thread__fork(thread, parent) < 0) {
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 07f89b66b31..784ee0bdda7 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -631,9 +631,14 @@ int hist_entry__fprintf(struct hist_entry *self, struct hists *pair_hists,
u64 session_total)
{
char bf[512];
- hist_entry__snprintf(self, bf, sizeof(bf), pair_hists,
- show_displacement, displacement,
- true, session_total);
+ int ret;
+
+ ret = hist_entry__snprintf(self, bf, sizeof(bf), pair_hists,
+ show_displacement, displacement,
+ true, session_total);
+ if (!ret)
+ return 0;
+
return fprintf(fp, "%s\n", bf);
}
@@ -762,6 +767,7 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
print_entries:
for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+ int cnt;
if (show_displacement) {
if (h->pair != NULL)
@@ -771,8 +777,13 @@ print_entries:
displacement = 0;
++position;
}
- ret += hist_entry__fprintf(h, pair, show_displacement,
- displacement, fp, self->stats.total_period);
+ cnt = hist_entry__fprintf(h, pair, show_displacement,
+ displacement, fp, self->stats.total_period);
+ /* Ignore those that didn't match the parent filter */
+ if (!cnt)
+ continue;
+
+ ret += cnt;
if (symbol_conf.use_callchain)
ret += hist_entry__fprintf_callchain(h, fp, self->stats.total_period);
@@ -965,13 +976,17 @@ static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file,
* Parse hexa addresses followed by ':'
*/
line_ip = strtoull(tmp, &tmp2, 16);
- if (*tmp2 != ':' || tmp == tmp2)
+ if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
line_ip = -1;
}
if (line_ip != -1) {
- u64 start = map__rip_2objdump(self->ms.map, sym->start);
+ u64 start = map__rip_2objdump(self->ms.map, sym->start),
+ end = map__rip_2objdump(self->ms.map, sym->end);
+
offset = line_ip - start;
+ if (offset < 0 || (u64)line_ip > end)
+ offset = -1;
}
objdump_line = objdump_line__new(offset, line);
diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c
index cf182ca132f..7537ca15900 100644
--- a/tools/perf/util/newt.c
+++ b/tools/perf/util/newt.c
@@ -43,6 +43,9 @@ struct ui_progress *ui_progress__new(const char *title, u64 total)
if (self != NULL) {
int cols;
+
+ if (use_browser <= 0)
+ return self;
newtGetScreenSize(&cols, NULL);
cols -= 4;
newtCenteredWindow(cols, 1, title);
@@ -67,14 +70,22 @@ out_free_self:
void ui_progress__update(struct ui_progress *self, u64 curr)
{
+ /*
+ * FIXME: We should have a per UI backend way of showing progress,
+ * stdio will just show a percentage as NN%, etc.
+ */
+ if (use_browser <= 0)
+ return;
newtScaleSet(self->scale, curr);
newtRefresh();
}
void ui_progress__delete(struct ui_progress *self)
{
- newtFormDestroy(self->form);
- newtPopWindow();
+ if (use_browser > 0) {
+ newtFormDestroy(self->form);
+ newtPopWindow();
+ }
free(self);
}
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 8f83a183576..c422cd67631 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -90,6 +90,7 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc
memcpy(self->filename, filename, len);
self->threads = RB_ROOT;
+ INIT_LIST_HEAD(&self->dead_threads);
self->hists_tree = RB_ROOT;
self->last_match = NULL;
self->mmap_window = 32;
@@ -131,6 +132,16 @@ void perf_session__delete(struct perf_session *self)
free(self);
}
+void perf_session__remove_thread(struct perf_session *self, struct thread *th)
+{
+ rb_erase(&th->rb_node, &self->threads);
+ /*
+ * We may have references to this thread, for instance in some hist_entry
+ * instances, so just move them to a separate list.
+ */
+ list_add_tail(&th->node, &self->dead_threads);
+}
+
static bool symbol__match_parent_regex(struct symbol *sym)
{
if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 55c6881b218..9fa0fc2a863 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -26,6 +26,7 @@ struct perf_session {
unsigned long size;
unsigned long mmap_window;
struct rb_root threads;
+ struct list_head dead_threads;
struct thread *last_match;
struct machine host_machine;
struct rb_root machines;
@@ -99,6 +100,7 @@ int perf_session__create_kernel_maps(struct perf_session *self);
int do_read(int fd, void *buf, size_t size);
void perf_session__update_sample_type(struct perf_session *self);
+void perf_session__remove_thread(struct perf_session *self, struct thread *th);
static inline
struct machine *perf_session__find_host_machine(struct perf_session *self)
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index b63e5713849..5b276833e2b 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1443,6 +1443,7 @@ static int map_groups__set_modules_path_dir(struct map_groups *self,
{
struct dirent *dent;
DIR *dir = opendir(dir_name);
+ int ret = 0;
if (!dir) {
pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
@@ -1465,8 +1466,9 @@ static int map_groups__set_modules_path_dir(struct map_groups *self,
snprintf(path, sizeof(path), "%s/%s",
dir_name, dent->d_name);
- if (map_groups__set_modules_path_dir(self, path) < 0)
- goto failure;
+ ret = map_groups__set_modules_path_dir(self, path);
+ if (ret < 0)
+ goto out;
} else {
char *dot = strrchr(dent->d_name, '.'),
dso_name[PATH_MAX];
@@ -1487,17 +1489,18 @@ static int map_groups__set_modules_path_dir(struct map_groups *self,
dir_name, dent->d_name);
long_name = strdup(path);
- if (long_name == NULL)
- goto failure;
+ if (long_name == NULL) {
+ ret = -1;
+ goto out;
+ }
dso__set_long_name(map->dso, long_name);
dso__kernel_module_get_build_id(map->dso, "");
}
}
- return 0;
-failure:
+out:
closedir(dir);
- return -1;
+ return ret;
}
static char *get_kernel_version(const char *root_dir)
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 1f7ecd47f49..9a448b47400 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -7,6 +7,15 @@
#include "util.h"
#include "debug.h"
+/* Skip "." and ".." directories */
+static int filter(const struct dirent *dir)
+{
+ if (dir->d_name[0] == '.')
+ return 0;
+ else
+ return 1;
+}
+
int find_all_tid(int pid, pid_t ** all_tid)
{
char name[256];
@@ -16,7 +25,7 @@ int find_all_tid(int pid, pid_t ** all_tid)
int i;
sprintf(name, "/proc/%d/task", pid);
- items = scandir(name, &namelist, NULL, NULL);
+ items = scandir(name, &namelist, filter, NULL);
if (items <= 0)
return -ENOENT;
*all_tid = malloc(sizeof(pid_t) * items);
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 1dfd9ff8bdc..ee6bbcf277c 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -6,7 +6,10 @@
#include "symbol.h"
struct thread {
- struct rb_node rb_node;
+ union {
+ struct rb_node rb_node;
+ struct list_head node;
+ };
struct map_groups mg;
pid_t pid;
char shortname[3];