summaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/annotate.c6
-rw-r--r--tools/perf/util/annotate.h2
-rw-r--r--tools/perf/util/event.c5
-rw-r--r--tools/perf/util/event.h2
-rw-r--r--tools/perf/util/evlist.c13
-rw-r--r--tools/perf/util/evlist.h1
-rw-r--r--tools/perf/util/evsel.c57
-rw-r--r--tools/perf/util/map.c98
-rw-r--r--tools/perf/util/map.h42
-rw-r--r--tools/perf/util/probe-finder.c2
-rw-r--r--tools/perf/util/python.c2
-rw-r--r--tools/perf/util/session.h3
-rw-r--r--tools/perf/util/sort.c10
-rw-r--r--tools/perf/util/symbol.c153
-rw-r--r--tools/perf/util/top.h3
-rw-r--r--tools/perf/util/ui/browsers/top.c28
16 files changed, 308 insertions, 119 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 01d36ba54053..bc8f4773d4d8 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -16,6 +16,8 @@
#include "annotate.h"
#include <pthread.h>
+const char *disassembler_style;
+
int symbol__annotate_init(struct map *map __used, struct symbol *sym)
{
struct annotation *notes = symbol__annotation(sym);
@@ -323,9 +325,11 @@ fallback:
dso, dso->long_name, sym, sym->name);
snprintf(command, sizeof(command),
- "objdump --start-address=0x%016" PRIx64
+ "objdump %s%s --start-address=0x%016" PRIx64
" --stop-address=0x%016" PRIx64
" -d %s %s -C %s|grep -v %s|expand",
+ disassembler_style ? "-M " : "",
+ disassembler_style ? disassembler_style : "",
map__rip_2objdump(map, sym->start),
map__rip_2objdump(map, sym->end),
symbol_conf.annotate_asm_raw ? "" : "--no-show-raw",
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index c2c286896801..6ede1286ee71 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -100,4 +100,6 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
int refresh);
#endif
+extern const char *disassembler_style;
+
#endif /* __PERF_ANNOTATE_H */
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 3c1b8a632101..437f8ca679a0 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -169,12 +169,17 @@ static int perf_event__synthesize_mmap_events(union perf_event *event,
continue;
pbf += n + 3;
if (*pbf == 'x') { /* vm_exec */
+ char anonstr[] = "//anon\n";
char *execname = strchr(bf, '/');
/* Catch VDSO */
if (execname == NULL)
execname = strstr(bf, "[vdso]");
+ /* Catch anonymous mmaps */
+ if ((execname == NULL) && !strstr(bf, "["))
+ execname = anonstr;
+
if (execname == NULL)
continue;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 1d7f66488a88..357a85b85248 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -186,6 +186,6 @@ const char *perf_event__name(unsigned int id);
int perf_event__parse_sample(const union perf_event *event, u64 type,
int sample_size, bool sample_id_all,
- struct perf_sample *sample);
+ struct perf_sample *sample, bool swapped);
#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index c12bd476c6f7..72e9f4886b6d 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -113,6 +113,19 @@ void perf_evlist__disable(struct perf_evlist *evlist)
}
}
+void perf_evlist__enable(struct perf_evlist *evlist)
+{
+ int cpu, thread;
+ struct perf_evsel *pos;
+
+ for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
+ list_for_each_entry(pos, &evlist->entries, node) {
+ for (thread = 0; thread < evlist->threads->nr; thread++)
+ ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_ENABLE);
+ }
+ }
+}
+
int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
{
int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries;
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index ce85ae9ae57a..f34915002745 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -54,6 +54,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite);
void perf_evlist__munmap(struct perf_evlist *evlist);
void perf_evlist__disable(struct perf_evlist *evlist);
+void perf_evlist__enable(struct perf_evlist *evlist);
static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
struct cpu_map *cpus,
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index a03a36b7908a..e389815078d3 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -7,6 +7,8 @@
* Released under the GPL v2. (and only v2, not any later version)
*/
+#include <byteswap.h>
+#include "asm/bug.h"
#include "evsel.h"
#include "evlist.h"
#include "util.h"
@@ -342,10 +344,20 @@ static bool sample_overlap(const union perf_event *event,
int perf_event__parse_sample(const union perf_event *event, u64 type,
int sample_size, bool sample_id_all,
- struct perf_sample *data)
+ struct perf_sample *data, bool swapped)
{
const u64 *array;
+ /*
+ * used for cross-endian analysis. See git commit 65014ab3
+ * for why this goofiness is needed.
+ */
+ union {
+ u64 val64;
+ u32 val32[2];
+ } u;
+
+
data->cpu = data->pid = data->tid = -1;
data->stream_id = data->id = data->time = -1ULL;
@@ -366,9 +378,16 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
}
if (type & PERF_SAMPLE_TID) {
- u32 *p = (u32 *)array;
- data->pid = p[0];
- data->tid = p[1];
+ u.val64 = *array;
+ if (swapped) {
+ /* undo swap of u64, then swap on individual u32s */
+ u.val64 = bswap_64(u.val64);
+ u.val32[0] = bswap_32(u.val32[0]);
+ u.val32[1] = bswap_32(u.val32[1]);
+ }
+
+ data->pid = u.val32[0];
+ data->tid = u.val32[1];
array++;
}
@@ -395,8 +414,15 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
}
if (type & PERF_SAMPLE_CPU) {
- u32 *p = (u32 *)array;
- data->cpu = *p;
+
+ u.val64 = *array;
+ if (swapped) {
+ /* undo swap of u64, then swap on individual u32s */
+ u.val64 = bswap_64(u.val64);
+ u.val32[0] = bswap_32(u.val32[0]);
+ }
+
+ data->cpu = u.val32[0];
array++;
}
@@ -423,18 +449,27 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
}
if (type & PERF_SAMPLE_RAW) {
- u32 *p = (u32 *)array;
+ const u64 *pdata;
+
+ u.val64 = *array;
+ if (WARN_ONCE(swapped,
+ "Endianness of raw data not corrected!\n")) {
+ /* undo swap of u64, then swap on individual u32s */
+ u.val64 = bswap_64(u.val64);
+ u.val32[0] = bswap_32(u.val32[0]);
+ u.val32[1] = bswap_32(u.val32[1]);
+ }
if (sample_overlap(event, array, sizeof(u32)))
return -EFAULT;
- data->raw_size = *p;
- p++;
+ data->raw_size = u.val32[0];
+ pdata = (void *) array + sizeof(u32);
- if (sample_overlap(event, p, data->raw_size))
+ if (sample_overlap(event, pdata, data->raw_size))
return -EFAULT;
- data->raw_data = p;
+ data->raw_data = (void *) pdata;
}
return 0;
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index a16ecab5229d..9cf0d4393c8d 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -18,6 +18,13 @@ static inline int is_anon_memory(const char *filename)
return strcmp(filename, "//anon") == 0;
}
+static inline int is_no_dso_memory(const char *filename)
+{
+ return !strcmp(filename, "[stack]") ||
+ !strcmp(filename, "[vdso]") ||
+ !strcmp(filename, "[heap]");
+}
+
void map__init(struct map *self, enum map_type type,
u64 start, u64 end, u64 pgoff, struct dso *dso)
{
@@ -42,9 +49,10 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
if (self != NULL) {
char newfilename[PATH_MAX];
struct dso *dso;
- int anon;
+ int anon, no_dso;
anon = is_anon_memory(filename);
+ no_dso = is_no_dso_memory(filename);
if (anon) {
snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
@@ -57,12 +65,16 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
map__init(self, type, start, start + len, pgoff, dso);
- if (anon) {
-set_identity:
+ if (anon || no_dso) {
self->map_ip = self->unmap_ip = identity__map_ip;
- } else if (strcmp(filename, "[vdso]") == 0) {
- dso__set_loaded(dso, self->type);
- goto set_identity;
+
+ /*
+ * Set memory without DSO as loaded. All map__find_*
+ * functions still return NULL, and we avoid the
+ * unnecessary map__load warning.
+ */
+ if (no_dso)
+ dso__set_loaded(dso, self->type);
}
}
return self;
@@ -220,55 +232,55 @@ u64 map__objdump_2ip(struct map *map, u64 addr)
return ip;
}
-void map_groups__init(struct map_groups *self)
+void map_groups__init(struct map_groups *mg)
{
int i;
for (i = 0; i < MAP__NR_TYPES; ++i) {
- self->maps[i] = RB_ROOT;
- INIT_LIST_HEAD(&self->removed_maps[i]);
+ mg->maps[i] = RB_ROOT;
+ INIT_LIST_HEAD(&mg->removed_maps[i]);
}
- self->machine = NULL;
+ mg->machine = NULL;
}
-static void maps__delete(struct rb_root *self)
+static void maps__delete(struct rb_root *maps)
{
- struct rb_node *next = rb_first(self);
+ struct rb_node *next = rb_first(maps);
while (next) {
struct map *pos = rb_entry(next, struct map, rb_node);
next = rb_next(&pos->rb_node);
- rb_erase(&pos->rb_node, self);
+ rb_erase(&pos->rb_node, maps);
map__delete(pos);
}
}
-static void maps__delete_removed(struct list_head *self)
+static void maps__delete_removed(struct list_head *maps)
{
struct map *pos, *n;
- list_for_each_entry_safe(pos, n, self, node) {
+ list_for_each_entry_safe(pos, n, maps, node) {
list_del(&pos->node);
map__delete(pos);
}
}
-void map_groups__exit(struct map_groups *self)
+void map_groups__exit(struct map_groups *mg)
{
int i;
for (i = 0; i < MAP__NR_TYPES; ++i) {
- maps__delete(&self->maps[i]);
- maps__delete_removed(&self->removed_maps[i]);
+ maps__delete(&mg->maps[i]);
+ maps__delete_removed(&mg->removed_maps[i]);
}
}
-void map_groups__flush(struct map_groups *self)
+void map_groups__flush(struct map_groups *mg)
{
int type;
for (type = 0; type < MAP__NR_TYPES; type++) {
- struct rb_root *root = &self->maps[type];
+ struct rb_root *root = &mg->maps[type];
struct rb_node *next = rb_first(root);
while (next) {
@@ -280,17 +292,17 @@ void map_groups__flush(struct map_groups *self)
* instance in some hist_entry instances, so
* just move them to a separate list.
*/
- list_add_tail(&pos->node, &self->removed_maps[pos->type]);
+ list_add_tail(&pos->node, &mg->removed_maps[pos->type]);
}
}
}
-struct symbol *map_groups__find_symbol(struct map_groups *self,
+struct symbol *map_groups__find_symbol(struct map_groups *mg,
enum map_type type, u64 addr,
struct map **mapp,
symbol_filter_t filter)
{
- struct map *map = map_groups__find(self, type, addr);
+ struct map *map = map_groups__find(mg, type, addr);
if (map != NULL) {
if (mapp != NULL)
@@ -301,7 +313,7 @@ struct symbol *map_groups__find_symbol(struct map_groups *self,
return NULL;
}
-struct symbol *map_groups__find_symbol_by_name(struct map_groups *self,
+struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
enum map_type type,
const char *name,
struct map **mapp,
@@ -309,7 +321,7 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *self,
{
struct rb_node *nd;
- for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
+ for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
struct map *pos = rb_entry(nd, struct map, rb_node);
struct symbol *sym = map__find_symbol_by_name(pos, name, filter);
@@ -323,13 +335,13 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *self,
return NULL;
}
-size_t __map_groups__fprintf_maps(struct map_groups *self,
+size_t __map_groups__fprintf_maps(struct map_groups *mg,
enum map_type type, int verbose, FILE *fp)
{
size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
struct rb_node *nd;
- for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
+ for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
struct map *pos = rb_entry(nd, struct map, rb_node);
printed += fprintf(fp, "Map:");
printed += map__fprintf(pos, fp);
@@ -342,22 +354,22 @@ size_t __map_groups__fprintf_maps(struct map_groups *self,
return printed;
}
-size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp)
+size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp)
{
size_t printed = 0, i;
for (i = 0; i < MAP__NR_TYPES; ++i)
- printed += __map_groups__fprintf_maps(self, i, verbose, fp);
+ printed += __map_groups__fprintf_maps(mg, i, verbose, fp);
return printed;
}
-static size_t __map_groups__fprintf_removed_maps(struct map_groups *self,
+static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg,
enum map_type type,
int verbose, FILE *fp)
{
struct map *pos;
size_t printed = 0;
- list_for_each_entry(pos, &self->removed_maps[type], node) {
+ list_for_each_entry(pos, &mg->removed_maps[type], node) {
printed += fprintf(fp, "Map:");
printed += map__fprintf(pos, fp);
if (verbose > 1) {
@@ -368,26 +380,26 @@ static size_t __map_groups__fprintf_removed_maps(struct map_groups *self,
return printed;
}
-static size_t map_groups__fprintf_removed_maps(struct map_groups *self,
+static size_t map_groups__fprintf_removed_maps(struct map_groups *mg,
int verbose, FILE *fp)
{
size_t printed = 0, i;
for (i = 0; i < MAP__NR_TYPES; ++i)
- printed += __map_groups__fprintf_removed_maps(self, i, verbose, fp);
+ printed += __map_groups__fprintf_removed_maps(mg, i, verbose, fp);
return printed;
}
-size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp)
+size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp)
{
- size_t printed = map_groups__fprintf_maps(self, verbose, fp);
+ size_t printed = map_groups__fprintf_maps(mg, verbose, fp);
printed += fprintf(fp, "Removed maps:\n");
- return printed + map_groups__fprintf_removed_maps(self, verbose, fp);
+ return printed + map_groups__fprintf_removed_maps(mg, verbose, fp);
}
-int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
+int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
int verbose, FILE *fp)
{
- struct rb_root *root = &self->maps[map->type];
+ struct rb_root *root = &mg->maps[map->type];
struct rb_node *next = rb_first(root);
int err = 0;
@@ -418,7 +430,7 @@ int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
}
before->end = map->start - 1;
- map_groups__insert(self, before);
+ map_groups__insert(mg, before);
if (verbose >= 2)
map__fprintf(before, fp);
}
@@ -432,7 +444,7 @@ int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
}
after->start = map->end + 1;
- map_groups__insert(self, after);
+ map_groups__insert(mg, after);
if (verbose >= 2)
map__fprintf(after, fp);
}
@@ -441,7 +453,7 @@ move_map:
* If we have references, just move them to a separate list.
*/
if (pos->referenced)
- list_add_tail(&pos->node, &self->removed_maps[map->type]);
+ list_add_tail(&pos->node, &mg->removed_maps[map->type]);
else
map__delete(pos);
@@ -455,7 +467,7 @@ move_map:
/*
* XXX This should not really _copy_ te maps, but refcount them.
*/
-int map_groups__clone(struct map_groups *self,
+int map_groups__clone(struct map_groups *mg,
struct map_groups *parent, enum map_type type)
{
struct rb_node *nd;
@@ -464,7 +476,7 @@ int map_groups__clone(struct map_groups *self,
struct map *new = map__clone(map);
if (new == NULL)
return -ENOMEM;
- map_groups__insert(self, new);
+ map_groups__insert(mg, new);
}
return 0;
}
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index b397c0383728..890d85545d0f 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -123,17 +123,17 @@ void map__fixup_end(struct map *self);
void map__reloc_vmlinux(struct map *self);
-size_t __map_groups__fprintf_maps(struct map_groups *self,
+size_t __map_groups__fprintf_maps(struct map_groups *mg,
enum map_type type, int verbose, FILE *fp);
void maps__insert(struct rb_root *maps, struct map *map);
-void maps__remove(struct rb_root *self, struct map *map);
+void maps__remove(struct rb_root *maps, struct map *map);
struct map *maps__find(struct rb_root *maps, u64 addr);
-void map_groups__init(struct map_groups *self);
-void map_groups__exit(struct map_groups *self);
-int map_groups__clone(struct map_groups *self,
+void map_groups__init(struct map_groups *mg);
+void map_groups__exit(struct map_groups *mg);
+int map_groups__clone(struct map_groups *mg,
struct map_groups *parent, enum map_type type);
-size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp);
-size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp);
+size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp);
+size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp);
typedef void (*machine__process_t)(struct machine *self, void *data);
@@ -162,29 +162,29 @@ static inline bool machine__is_host(struct machine *self)
return self ? self->pid == HOST_KERNEL_ID : false;
}
-static inline void map_groups__insert(struct map_groups *self, struct map *map)
+static inline void map_groups__insert(struct map_groups *mg, struct map *map)
{
- maps__insert(&self->maps[map->type], map);
- map->groups = self;
+ maps__insert(&mg->maps[map->type], map);
+ map->groups = mg;
}
-static inline void map_groups__remove(struct map_groups *self, struct map *map)
+static inline void map_groups__remove(struct map_groups *mg, struct map *map)
{
- maps__remove(&self->maps[map->type], map);
+ maps__remove(&mg->maps[map->type], map);
}
-static inline struct map *map_groups__find(struct map_groups *self,
+static inline struct map *map_groups__find(struct map_groups *mg,
enum map_type type, u64 addr)
{
- return maps__find(&self->maps[type], addr);
+ return maps__find(&mg->maps[type], addr);
}
-struct symbol *map_groups__find_symbol(struct map_groups *self,
+struct symbol *map_groups__find_symbol(struct map_groups *mg,
enum map_type type, u64 addr,
struct map **mapp,
symbol_filter_t filter);
-struct symbol *map_groups__find_symbol_by_name(struct map_groups *self,
+struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
enum map_type type,
const char *name,
struct map **mapp,
@@ -208,11 +208,11 @@ struct symbol *machine__find_kernel_function(struct machine *self, u64 addr,
}
static inline
-struct symbol *map_groups__find_function_by_name(struct map_groups *self,
+struct symbol *map_groups__find_function_by_name(struct map_groups *mg,
const char *name, struct map **mapp,
symbol_filter_t filter)
{
- return map_groups__find_symbol_by_name(self, MAP__FUNCTION, name, mapp, filter);
+ return map_groups__find_symbol_by_name(mg, MAP__FUNCTION, name, mapp, filter);
}
static inline
@@ -225,13 +225,13 @@ struct symbol *machine__find_kernel_function_by_name(struct machine *self,
filter);
}
-int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
+int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
int verbose, FILE *fp);
-struct map *map_groups__find_by_name(struct map_groups *self,
+struct map *map_groups__find_by_name(struct map_groups *mg,
enum map_type type, const char *name);
struct map *machine__new_module(struct machine *self, u64 start, const char *filename);
-void map_groups__flush(struct map_groups *self);
+void map_groups__flush(struct map_groups *mg);
#endif /* __PERF_MAP_H */
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 555fc3864b90..5d732621a462 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -659,7 +659,7 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die))
ret = -ENOENT;
}
- if (ret == 0)
+ if (ret >= 0)
ret = convert_variable(&vr_die, pf);
if (ret < 0)
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index cbc8f215d4b7..7624324efad4 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -803,7 +803,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
first = list_entry(evlist->entries.next, struct perf_evsel, node);
err = perf_event__parse_sample(event, first->attr.sample_type,
perf_evsel__sample_size(first),
- sample_id_all, &pevent->sample);
+ sample_id_all, &pevent->sample, false);
if (err)
return PyErr_Format(PyExc_OSError,
"perf: can't parse sample, err=%d", err);
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 170601e67d6b..974d0cbee5e9 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -162,7 +162,8 @@ static inline int perf_session__parse_sample(struct perf_session *session,
{
return perf_event__parse_sample(event, session->sample_type,
session->sample_size,
- session->sample_id_all, sample);
+ session->sample_id_all, sample,
+ session->header.needs_swap);
}
struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 401e220566fd..1ee8f1e40f18 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -151,11 +151,17 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
{
u64 ip_l, ip_r;
+ if (!left->ms.sym && !right->ms.sym)
+ return right->level - left->level;
+
+ if (!left->ms.sym || !right->ms.sym)
+ return cmp_null(left->ms.sym, right->ms.sym);
+
if (left->ms.sym == right->ms.sym)
return 0;
- ip_l = left->ms.sym ? left->ms.sym->start : left->ip;
- ip_r = right->ms.sym ? right->ms.sym->start : right->ip;
+ ip_l = left->ms.sym->start;
+ ip_r = right->ms.sym->start;
return (int64_t)(ip_r - ip_l);
}
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 245e60d6b4e7..077df15ee705 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -76,16 +76,104 @@ static void dso__set_sorted_by_name(struct dso *dso, enum map_type type)
bool symbol_type__is_a(char symbol_type, enum map_type map_type)
{
+ symbol_type = toupper(symbol_type);
+
switch (map_type) {
case MAP__FUNCTION:
return symbol_type == 'T' || symbol_type == 'W';
case MAP__VARIABLE:
- return symbol_type == 'D' || symbol_type == 'd';
+ return symbol_type == 'D';
default:
return false;
}
}
+static int prefix_underscores_count(const char *str)
+{
+ const char *tail = str;
+
+ while (*tail == '_')
+ tail++;
+
+ return tail - str;
+}
+
+#define SYMBOL_A 0
+#define SYMBOL_B 1
+
+static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
+{
+ s64 a;
+ s64 b;
+
+ /* Prefer a symbol with non zero length */
+ a = syma->end - syma->start;
+ b = symb->end - symb->start;
+ if ((b == 0) && (a > 0))
+ return SYMBOL_A;
+ else if ((a == 0) && (b > 0))
+ return SYMBOL_B;
+
+ /* Prefer a non weak symbol over a weak one */
+ a = syma->binding == STB_WEAK;
+ b = symb->binding == STB_WEAK;
+ if (b && !a)
+ return SYMBOL_A;
+ if (a && !b)
+ return SYMBOL_B;
+
+ /* Prefer a global symbol over a non global one */
+ a = syma->binding == STB_GLOBAL;
+ b = symb->binding == STB_GLOBAL;
+ if (a && !b)
+ return SYMBOL_A;
+ if (b && !a)
+ return SYMBOL_B;
+
+ /* Prefer a symbol with less underscores */
+ a = prefix_underscores_count(syma->name);
+ b = prefix_underscores_count(symb->name);
+ if (b > a)
+ return SYMBOL_A;
+ else if (a > b)
+ return SYMBOL_B;
+
+ /* If all else fails, choose the symbol with the longest name */
+ if (strlen(syma->name) >= strlen(symb->name))
+ return SYMBOL_A;
+ else
+ return SYMBOL_B;
+}
+
+static void symbols__fixup_duplicate(struct rb_root *symbols)
+{
+ struct rb_node *nd;
+ struct symbol *curr, *next;
+
+ nd = rb_first(symbols);
+
+ while (nd) {
+ curr = rb_entry(nd, struct symbol, rb_node);
+again:
+ nd = rb_next(&curr->rb_node);
+ next = rb_entry(nd, struct symbol, rb_node);
+
+ if (!nd)
+ break;
+
+ if (curr->start != next->start)
+ continue;
+
+ if (choose_best_symbol(curr, next) == SYMBOL_A) {
+ rb_erase(&next->rb_node, symbols);
+ goto again;
+ } else {
+ nd = rb_next(&curr->rb_node);
+ rb_erase(&curr->rb_node, symbols);
+ }
+ }
+}
+
static void symbols__fixup_end(struct rb_root *symbols)
{
struct rb_node *nd, *prevnd = rb_first(symbols);
@@ -440,18 +528,11 @@ int kallsyms__parse(const char *filename, void *arg,
char *line = NULL;
size_t n;
int err = -1;
- u64 prev_start = 0;
- char prev_symbol_type = 0;
- char *prev_symbol_name;
FILE *file = fopen(filename, "r");
if (file == NULL)
goto out_failure;
- prev_symbol_name = malloc(KSYM_NAME_LEN);
- if (prev_symbol_name == NULL)
- goto out_close;
-
err = 0;
while (!feof(file)) {
@@ -472,7 +553,7 @@ int kallsyms__parse(const char *filename, void *arg,
if (len + 2 >= line_len)
continue;
- symbol_type = toupper(line[len]);
+ symbol_type = line[len];
len += 2;
symbol_name = line + len;
len = line_len - len;
@@ -482,24 +563,18 @@ int kallsyms__parse(const char *filename, void *arg,
break;
}
- if (prev_symbol_type) {
- u64 end = start;
- if (end != prev_start)
- --end;
- err = process_symbol(arg, prev_symbol_name,
- prev_symbol_type, prev_start, end);
- if (err)
- break;
- }
-
- memcpy(prev_symbol_name, symbol_name, len + 1);
- prev_symbol_type = symbol_type;
- prev_start = start;
+ /*
+ * module symbols are not sorted so we add all
+ * symbols with zero length and rely on
+ * symbols__fixup_end() to fix it up.
+ */
+ err = process_symbol(arg, symbol_name,
+ symbol_type, start, start);
+ if (err)
+ break;
}
- free(prev_symbol_name);
free(line);
-out_close:
fclose(file);
return err;
@@ -705,6 +780,9 @@ int dso__load_kallsyms(struct dso *dso, const char *filename,
if (dso__load_all_kallsyms(dso, filename, map) < 0)
return -1;
+ symbols__fixup_duplicate(&dso->symbols[map->type]);
+ symbols__fixup_end(&dso->symbols[map->type]);
+
if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
dso->symtab_type = SYMTAB__GUEST_KALLSYMS;
else
@@ -1094,8 +1172,7 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
if (dso->has_build_id) {
u8 build_id[BUILD_ID_SIZE];
- if (elf_read_build_id(elf, build_id,
- BUILD_ID_SIZE) != BUILD_ID_SIZE)
+ if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0)
goto out_elf_end;
if (!dso__build_id_equal(dso, build_id))
@@ -1113,6 +1190,8 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
}
opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx);
+ if (opdshdr.sh_type != SHT_PROGBITS)
+ opdsec = NULL;
if (opdsec)
opddata = elf_rawdata(opdsec, NULL);
@@ -1278,6 +1357,7 @@ new_symbol:
* For misannotated, zeroed, ASM function sizes.
*/
if (nr > 0) {
+ symbols__fixup_duplicate(&dso->symbols[map->type]);
symbols__fixup_end(&dso->symbols[map->type]);
if (kmap) {
/*
@@ -1364,8 +1444,8 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size)
ptr = data->d_buf;
while (ptr < (data->d_buf + data->d_size)) {
GElf_Nhdr *nhdr = ptr;
- int namesz = NOTE_ALIGN(nhdr->n_namesz),
- descsz = NOTE_ALIGN(nhdr->n_descsz);
+ size_t namesz = NOTE_ALIGN(nhdr->n_namesz),
+ descsz = NOTE_ALIGN(nhdr->n_descsz);
const char *name;
ptr += sizeof(*nhdr);
@@ -1374,8 +1454,10 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size)
if (nhdr->n_type == NT_GNU_BUILD_ID &&
nhdr->n_namesz == sizeof("GNU")) {
if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
- memcpy(bf, ptr, BUILD_ID_SIZE);
- err = BUILD_ID_SIZE;
+ size_t sz = min(size, descsz);
+ memcpy(bf, ptr, sz);
+ memset(bf + sz, 0, size - sz);
+ err = descsz;
break;
}
}
@@ -1427,7 +1509,7 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
while (1) {
char bf[BUFSIZ];
GElf_Nhdr nhdr;
- int namesz, descsz;
+ size_t namesz, descsz;
if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
break;
@@ -1436,15 +1518,16 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
descsz = NOTE_ALIGN(nhdr.n_descsz);
if (nhdr.n_type == NT_GNU_BUILD_ID &&
nhdr.n_namesz == sizeof("GNU")) {
- if (read(fd, bf, namesz) != namesz)
+ if (read(fd, bf, namesz) != (ssize_t)namesz)
break;
if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
- if (read(fd, build_id,
- BUILD_ID_SIZE) == BUILD_ID_SIZE) {
+ size_t sz = min(descsz, size);
+ if (read(fd, build_id, sz) == (ssize_t)sz) {
+ memset(build_id + sz, 0, size - sz);
err = 0;
break;
}
- } else if (read(fd, bf, descsz) != descsz)
+ } else if (read(fd, bf, descsz) != (ssize_t)descsz)
break;
} else {
int n = namesz + descsz;
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index bfbf95bcc603..b07b0410463c 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -10,6 +10,7 @@
struct perf_evlist;
struct perf_evsel;
+struct perf_session;
struct sym_entry {
struct rb_node rb_node;
@@ -38,6 +39,7 @@ struct perf_top {
u64 kernel_samples, us_samples;
u64 exact_samples;
u64 guest_us_samples, guest_kernel_samples;
+ u64 total_lost_warned;
int print_entries, count_filter, delay_secs;
int display_weighted, freq, rb_entries;
pid_t target_pid, target_tid;
@@ -45,6 +47,7 @@ struct perf_top {
const char *cpu_list;
struct sym_entry *sym_filter_entry;
struct perf_evsel *sym_evsel;
+ struct perf_session *session;
};
size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
diff --git a/tools/perf/util/ui/browsers/top.c b/tools/perf/util/ui/browsers/top.c
index 88403cf8396a..9b6b43b32ac8 100644
--- a/tools/perf/util/ui/browsers/top.c
+++ b/tools/perf/util/ui/browsers/top.c
@@ -11,10 +11,12 @@
#include "../helpline.h"
#include "../libslang.h"
#include "../util.h"
+#include "../ui.h"
#include "../../evlist.h"
#include "../../hist.h"
#include "../../sort.h"
#include "../../symbol.h"
+#include "../../session.h"
#include "../../top.h"
struct perf_top_browser {
@@ -43,10 +45,10 @@ static void perf_top_browser__write(struct ui_browser *browser, void *entry, int
if (top->evlist->nr_entries == 1 || !top->display_weighted) {
slsmg_printf("%20.2f ", syme->weight);
- width -= 24;
+ width -= 21;
} else {
slsmg_printf("%9.1f %10ld ", syme->weight, syme->snap_count);
- width -= 23;
+ width -= 20;
}
slsmg_printf("%4.1f%%", pcnt);
@@ -143,6 +145,25 @@ do_annotation:
symbol__tui_annotate(sym, syme->map, 0, top->delay_secs * 1000);
}
+static void perf_top_browser__warn_lost(struct perf_top_browser *browser)
+{
+ struct perf_top *top = browser->b.priv;
+ char msg[128];
+ int len;
+
+ top->total_lost_warned = top->session->hists.stats.total_lost;
+ pthread_mutex_lock(&ui__lock);
+ ui_browser__set_color(&browser->b, HE_COLORSET_TOP);
+ len = snprintf(msg, sizeof(msg),
+ " WARNING: LOST %" PRIu64 " events, Check IO/CPU overload",
+ top->total_lost_warned);
+ if (len > browser->b.width)
+ len = browser->b.width;
+ SLsmg_gotorc(0, browser->b.width - len);
+ slsmg_write_nstring(msg, len);
+ pthread_mutex_unlock(&ui__lock);
+}
+
static int perf_top_browser__run(struct perf_top_browser *browser)
{
int key;
@@ -174,6 +195,9 @@ static int perf_top_browser__run(struct perf_top_browser *browser)
ui_browser__set_color(&browser->b, NEWT_COLORSET_ROOT);
SLsmg_gotorc(0, 0);
slsmg_write_nstring(title, browser->b.width);
+
+ if (top->total_lost_warned != top->session->hists.stats.total_lost)
+ perf_top_browser__warn_lost(browser);
break;
case 'a':
case NEWT_KEY_RIGHT:
OpenPOWER on IntegriCloud