提交 f1942b96 编写于 作者: I Ingo Molnar

Merge tag 'perf-core-for-mingo' of...

Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

Pull perf/core refactorings and improvements from Arnaldo Carvalho de Melo:

User visible changes:

  - Add hint for 'Too many events are opened.' error message (Jiri Olsa)

Infrastructure changes:

  - Protect accesses to map rbtrees with a lock and refcount struct map,
    reducing memory usage as maps not used get freed. The 'dso' struct is
    next in line. (Arnaldo Carvalho de Melo)

  - Annotation and branch related option parsing refactorings to
    share code with upcoming patches (Andi Kleen)
Signed-off-by: NArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: NIngo Molnar <mingo@kernel.org>
...@@ -59,6 +59,10 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, ...@@ -59,6 +59,10 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
(al->sym == NULL || (al->sym == NULL ||
strcmp(ann->sym_hist_filter, al->sym->name) != 0)) { strcmp(ann->sym_hist_filter, al->sym->name) != 0)) {
/* We're only interested in a symbol named sym_hist_filter */ /* We're only interested in a symbol named sym_hist_filter */
/*
* FIXME: why isn't this done in the symbol_filter when loading
* the DSO?
*/
if (al->sym != NULL) { if (al->sym != NULL) {
rb_erase(&al->sym->rb_node, rb_erase(&al->sym->rb_node,
&al->map->dso->symbols[al->map->type]); &al->map->dso->symbols[al->map->type]);
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "util/thread_map.h" #include "util/thread_map.h"
#include "util/data.h" #include "util/data.h"
#include "util/auxtrace.h" #include "util/auxtrace.h"
#include "util/parse-branch-options.h"
#include <unistd.h> #include <unistd.h>
#include <sched.h> #include <sched.h>
...@@ -751,94 +752,6 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) ...@@ -751,94 +752,6 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
return status; return status;
} }
#define BRANCH_OPT(n, m) \
{ .name = n, .mode = (m) }
#define BRANCH_END { .name = NULL }
struct branch_mode {
const char *name;
int mode;
};
static const struct branch_mode branch_modes[] = {
BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
BRANCH_OPT("cond", PERF_SAMPLE_BRANCH_COND),
BRANCH_END
};
static int
parse_branch_stack(const struct option *opt, const char *str, int unset)
{
#define ONLY_PLM \
(PERF_SAMPLE_BRANCH_USER |\
PERF_SAMPLE_BRANCH_KERNEL |\
PERF_SAMPLE_BRANCH_HV)
uint64_t *mode = (uint64_t *)opt->value;
const struct branch_mode *br;
char *s, *os = NULL, *p;
int ret = -1;
if (unset)
return 0;
/*
* cannot set it twice, -b + --branch-filter for instance
*/
if (*mode)
return -1;
/* str may be NULL in case no arg is passed to -b */
if (str) {
/* because str is read-only */
s = os = strdup(str);
if (!s)
return -1;
for (;;) {
p = strchr(s, ',');
if (p)
*p = '\0';
for (br = branch_modes; br->name; br++) {
if (!strcasecmp(s, br->name))
break;
}
if (!br->name) {
ui__warning("unknown branch filter %s,"
" check man page\n", s);
goto error;
}
*mode |= br->mode;
if (!p)
break;
s = p + 1;
}
}
ret = 0;
/* default to any branch */
if ((*mode & ~ONLY_PLM) == 0) {
*mode = PERF_SAMPLE_BRANCH_ANY;
}
error:
free(os);
return ret;
}
static void callchain_debug(void) static void callchain_debug(void)
{ {
static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF", "LBR" }; static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF", "LBR" };
......
...@@ -26,7 +26,7 @@ int test__vmlinux_matches_kallsyms(void) ...@@ -26,7 +26,7 @@ int test__vmlinux_matches_kallsyms(void)
struct map *kallsyms_map, *vmlinux_map, *map; struct map *kallsyms_map, *vmlinux_map, *map;
struct machine kallsyms, vmlinux; struct machine kallsyms, vmlinux;
enum map_type type = MAP__FUNCTION; enum map_type type = MAP__FUNCTION;
struct rb_root *maps = &vmlinux.kmaps.maps[type]; struct maps *maps = &vmlinux.kmaps.maps[type];
u64 mem_start, mem_end; u64 mem_start, mem_end;
/* /*
......
...@@ -75,6 +75,7 @@ libperf-$(CONFIG_X86) += tsc.o ...@@ -75,6 +75,7 @@ libperf-$(CONFIG_X86) += tsc.o
libperf-y += cloexec.o libperf-y += cloexec.o
libperf-y += thread-stack.o libperf-y += thread-stack.o
libperf-$(CONFIG_AUXTRACE) += auxtrace.o libperf-$(CONFIG_AUXTRACE) += auxtrace.o
libperf-y += parse-branch-options.o
libperf-$(CONFIG_LIBELF) += symbol-elf.o libperf-$(CONFIG_LIBELF) += symbol-elf.o
libperf-$(CONFIG_LIBELF) += probe-event.o libperf-$(CONFIG_LIBELF) += probe-event.o
......
...@@ -506,6 +506,17 @@ static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map, ...@@ -506,6 +506,17 @@ static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map,
return 0; return 0;
} }
static struct annotation *symbol__get_annotation(struct symbol *sym)
{
struct annotation *notes = symbol__annotation(sym);
if (notes->src == NULL) {
if (symbol__alloc_hist(sym) < 0)
return NULL;
}
return notes;
}
static int symbol__inc_addr_samples(struct symbol *sym, struct map *map, static int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
int evidx, u64 addr) int evidx, u64 addr)
{ {
...@@ -513,13 +524,9 @@ static int symbol__inc_addr_samples(struct symbol *sym, struct map *map, ...@@ -513,13 +524,9 @@ static int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
if (sym == NULL) if (sym == NULL)
return 0; return 0;
notes = symbol__get_annotation(sym);
notes = symbol__annotation(sym); if (notes == NULL)
if (notes->src == NULL) {
if (symbol__alloc_hist(sym) < 0)
return -ENOMEM; return -ENOMEM;
}
return __symbol__inc_addr_samples(sym, map, notes, evidx, addr); return __symbol__inc_addr_samples(sym, map, notes, evidx, addr);
} }
......
...@@ -331,7 +331,7 @@ int perf_event__synthesize_modules(struct perf_tool *tool, ...@@ -331,7 +331,7 @@ int perf_event__synthesize_modules(struct perf_tool *tool,
int rc = 0; int rc = 0;
struct map *pos; struct map *pos;
struct map_groups *kmaps = &machine->kmaps; struct map_groups *kmaps = &machine->kmaps;
struct rb_root *maps = &kmaps->maps[MAP__FUNCTION]; struct maps *maps = &kmaps->maps[MAP__FUNCTION];
union perf_event *event = zalloc((sizeof(event->mmap) + union perf_event *event = zalloc((sizeof(event->mmap) +
machine->id_hdr_size)); machine->id_hdr_size));
if (event == NULL) { if (event == NULL) {
......
...@@ -2149,7 +2149,9 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, ...@@ -2149,7 +2149,9 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
case EMFILE: case EMFILE:
return scnprintf(msg, size, "%s", return scnprintf(msg, size, "%s",
"Too many events are opened.\n" "Too many events are opened.\n"
"Try again after reducing the number of events."); "Probably the maximum number of open file descriptors has been reached.\n"
"Hint: Try again after reducing the number of events.\n"
"Hint: Try increasing the limit with 'ulimit -n <limit>'");
case ENODEV: case ENODEV:
if (target->cpu_list) if (target->cpu_list)
return scnprintf(msg, size, "%s", return scnprintf(msg, size, "%s",
......
...@@ -759,7 +759,6 @@ void machine__destroy_kernel_maps(struct machine *machine) ...@@ -759,7 +759,6 @@ void machine__destroy_kernel_maps(struct machine *machine)
kmap->ref_reloc_sym = NULL; kmap->ref_reloc_sym = NULL;
} }
map__delete(machine->vmlinux_maps[type]);
machine->vmlinux_maps[type] = NULL; machine->vmlinux_maps[type] = NULL;
} }
} }
...@@ -1247,6 +1246,7 @@ int machine__process_mmap2_event(struct machine *machine, ...@@ -1247,6 +1246,7 @@ int machine__process_mmap2_event(struct machine *machine,
thread__insert_map(thread, map); thread__insert_map(thread, map);
thread__put(thread); thread__put(thread);
map__put(map);
return 0; return 0;
out_problem_map: out_problem_map:
...@@ -1297,6 +1297,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event ...@@ -1297,6 +1297,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
thread__insert_map(thread, map); thread__insert_map(thread, map);
thread__put(thread); thread__put(thread);
map__put(map);
return 0; return 0;
out_problem_map: out_problem_map:
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#include "machine.h" #include "machine.h"
#include <linux/string.h> #include <linux/string.h>
static void __maps__insert(struct maps *maps, struct map *map);
const char *map_type__name[MAP__NR_TYPES] = { const char *map_type__name[MAP__NR_TYPES] = {
[MAP__FUNCTION] = "Functions", [MAP__FUNCTION] = "Functions",
[MAP__VARIABLE] = "Variables", [MAP__VARIABLE] = "Variables",
...@@ -137,6 +139,7 @@ void map__init(struct map *map, enum map_type type, ...@@ -137,6 +139,7 @@ void map__init(struct map *map, enum map_type type,
map->groups = NULL; map->groups = NULL;
map->referenced = false; map->referenced = false;
map->erange_warned = false; map->erange_warned = false;
atomic_set(&map->refcnt, 1);
} }
struct map *map__new(struct machine *machine, u64 start, u64 len, struct map *map__new(struct machine *machine, u64 start, u64 len,
...@@ -223,9 +226,16 @@ struct map *map__new2(u64 start, struct dso *dso, enum map_type type) ...@@ -223,9 +226,16 @@ struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
void map__delete(struct map *map) void map__delete(struct map *map)
{ {
BUG_ON(!RB_EMPTY_NODE(&map->rb_node));
free(map); free(map);
} }
void map__put(struct map *map)
{
if (map && atomic_dec_and_test(&map->refcnt))
map__delete(map);
}
void map__fixup_start(struct map *map) void map__fixup_start(struct map *map)
{ {
struct rb_root *symbols = &map->dso->symbols[map->type]; struct rb_root *symbols = &map->dso->symbols[map->type];
...@@ -418,48 +428,61 @@ u64 map__objdump_2mem(struct map *map, u64 ip) ...@@ -418,48 +428,61 @@ u64 map__objdump_2mem(struct map *map, u64 ip)
return ip + map->reloc; return ip + map->reloc;
} }
static void maps__init(struct maps *maps)
{
maps->entries = RB_ROOT;
pthread_rwlock_init(&maps->lock, NULL);
INIT_LIST_HEAD(&maps->removed_maps);
}
void map_groups__init(struct map_groups *mg, struct machine *machine) void map_groups__init(struct map_groups *mg, struct machine *machine)
{ {
int i; int i;
for (i = 0; i < MAP__NR_TYPES; ++i) { for (i = 0; i < MAP__NR_TYPES; ++i) {
mg->maps[i] = RB_ROOT; maps__init(&mg->maps[i]);
INIT_LIST_HEAD(&mg->removed_maps[i]);
} }
mg->machine = machine; mg->machine = machine;
atomic_set(&mg->refcnt, 1); atomic_set(&mg->refcnt, 1);
} }
static void maps__delete(struct rb_root *maps) static void __maps__purge(struct maps *maps)
{ {
struct rb_node *next = rb_first(maps); struct rb_root *root = &maps->entries;
struct rb_node *next = rb_first(root);
while (next) { while (next) {
struct map *pos = rb_entry(next, struct map, rb_node); struct map *pos = rb_entry(next, struct map, rb_node);
next = rb_next(&pos->rb_node); next = rb_next(&pos->rb_node);
rb_erase(&pos->rb_node, maps); rb_erase_init(&pos->rb_node, root);
map__delete(pos); map__put(pos);
} }
} }
static void maps__delete_removed(struct list_head *maps) static void __maps__purge_removed_maps(struct maps *maps)
{ {
struct map *pos, *n; struct map *pos, *n;
list_for_each_entry_safe(pos, n, maps, node) { list_for_each_entry_safe(pos, n, &maps->removed_maps, node) {
list_del(&pos->node); list_del_init(&pos->node);
map__delete(pos); map__put(pos);
} }
} }
static void maps__exit(struct maps *maps)
{
pthread_rwlock_wrlock(&maps->lock);
__maps__purge(maps);
__maps__purge_removed_maps(maps);
pthread_rwlock_unlock(&maps->lock);
}
void map_groups__exit(struct map_groups *mg) void map_groups__exit(struct map_groups *mg)
{ {
int i; int i;
for (i = 0; i < MAP__NR_TYPES; ++i) { for (i = 0; i < MAP__NR_TYPES; ++i)
maps__delete(&mg->maps[i]); maps__exit(&mg->maps[i]);
maps__delete_removed(&mg->removed_maps[i]);
}
} }
bool map_groups__empty(struct map_groups *mg) bool map_groups__empty(struct map_groups *mg)
...@@ -469,7 +492,7 @@ bool map_groups__empty(struct map_groups *mg) ...@@ -469,7 +492,7 @@ bool map_groups__empty(struct map_groups *mg)
for (i = 0; i < MAP__NR_TYPES; ++i) { for (i = 0; i < MAP__NR_TYPES; ++i) {
if (maps__first(&mg->maps[i])) if (maps__first(&mg->maps[i]))
return false; return false;
if (!list_empty(&mg->removed_maps[i])) if (!list_empty(&mg->maps[i].removed_maps))
return false; return false;
} }
...@@ -521,20 +544,28 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg, ...@@ -521,20 +544,28 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
struct map **mapp, struct map **mapp,
symbol_filter_t filter) symbol_filter_t filter)
{ {
struct maps *maps = &mg->maps[type];
struct symbol *sym;
struct rb_node *nd; struct rb_node *nd;
for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) { pthread_rwlock_rdlock(&maps->lock);
for (nd = rb_first(&maps->entries); nd; nd = rb_next(nd)) {
struct map *pos = rb_entry(nd, struct map, rb_node); struct map *pos = rb_entry(nd, struct map, rb_node);
struct symbol *sym = map__find_symbol_by_name(pos, name, filter);
sym = map__find_symbol_by_name(pos, name, filter);
if (sym == NULL) if (sym == NULL)
continue; continue;
if (mapp != NULL) if (mapp != NULL)
*mapp = pos; *mapp = pos;
return sym; goto out;
} }
return NULL; sym = NULL;
out:
pthread_rwlock_unlock(&maps->lock);
return sym;
} }
int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter) int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter)
...@@ -554,25 +585,35 @@ int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter) ...@@ -554,25 +585,35 @@ int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter)
return ams->sym ? 0 : -1; return ams->sym ? 0 : -1;
} }
size_t __map_groups__fprintf_maps(struct map_groups *mg, enum map_type type, static size_t maps__fprintf(struct maps *maps, FILE *fp)
FILE *fp)
{ {
size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); size_t printed = 0;
struct rb_node *nd; struct rb_node *nd;
for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) { pthread_rwlock_rdlock(&maps->lock);
for (nd = rb_first(&maps->entries); nd; nd = rb_next(nd)) {
struct map *pos = rb_entry(nd, struct map, rb_node); struct map *pos = rb_entry(nd, struct map, rb_node);
printed += fprintf(fp, "Map:"); printed += fprintf(fp, "Map:");
printed += map__fprintf(pos, fp); printed += map__fprintf(pos, fp);
if (verbose > 2) { if (verbose > 2) {
printed += dso__fprintf(pos->dso, type, fp); printed += dso__fprintf(pos->dso, pos->type, fp);
printed += fprintf(fp, "--\n"); printed += fprintf(fp, "--\n");
} }
} }
pthread_rwlock_unlock(&maps->lock);
return printed; return printed;
} }
size_t __map_groups__fprintf_maps(struct map_groups *mg, enum map_type type,
FILE *fp)
{
size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
return printed += maps__fprintf(&mg->maps[type], fp);
}
static size_t map_groups__fprintf_maps(struct map_groups *mg, FILE *fp) static size_t map_groups__fprintf_maps(struct map_groups *mg, FILE *fp)
{ {
size_t printed = 0, i; size_t printed = 0, i;
...@@ -587,7 +628,7 @@ static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg, ...@@ -587,7 +628,7 @@ static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg,
struct map *pos; struct map *pos;
size_t printed = 0; size_t printed = 0;
list_for_each_entry(pos, &mg->removed_maps[type], node) { list_for_each_entry(pos, &mg->maps[type].removed_maps, node) {
printed += fprintf(fp, "Map:"); printed += fprintf(fp, "Map:");
printed += map__fprintf(pos, fp); printed += map__fprintf(pos, fp);
if (verbose > 1) { if (verbose > 1) {
...@@ -614,13 +655,17 @@ size_t map_groups__fprintf(struct map_groups *mg, FILE *fp) ...@@ -614,13 +655,17 @@ size_t map_groups__fprintf(struct map_groups *mg, FILE *fp)
return printed + map_groups__fprintf_removed_maps(mg, fp); return printed + map_groups__fprintf_removed_maps(mg, fp);
} }
int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp)
FILE *fp)
{ {
struct rb_root *root = &mg->maps[map->type]; struct rb_root *root;
struct rb_node *next = rb_first(root); struct rb_node *next;
int err = 0; int err = 0;
pthread_rwlock_wrlock(&maps->lock);
root = &maps->entries;
next = rb_first(root);
while (next) { while (next) {
struct map *pos = rb_entry(next, struct map, rb_node); struct map *pos = rb_entry(next, struct map, rb_node);
next = rb_next(&pos->rb_node); next = rb_next(&pos->rb_node);
...@@ -634,7 +679,7 @@ int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, ...@@ -634,7 +679,7 @@ int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
map__fprintf(pos, fp); map__fprintf(pos, fp);
} }
rb_erase(&pos->rb_node, root); rb_erase_init(&pos->rb_node, root);
/* /*
* Now check if we need to create new maps for areas not * Now check if we need to create new maps for areas not
* overlapped by the new map: * overlapped by the new map:
...@@ -644,11 +689,11 @@ int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, ...@@ -644,11 +689,11 @@ int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
if (before == NULL) { if (before == NULL) {
err = -ENOMEM; err = -ENOMEM;
goto move_map; goto put_map;
} }
before->end = map->start; before->end = map->start;
map_groups__insert(mg, before); __maps__insert(maps, before);
if (verbose >= 2) if (verbose >= 2)
map__fprintf(before, fp); map__fprintf(before, fp);
} }
...@@ -658,28 +703,37 @@ int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, ...@@ -658,28 +703,37 @@ int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
if (after == NULL) { if (after == NULL) {
err = -ENOMEM; err = -ENOMEM;
goto move_map; goto put_map;
} }
after->start = map->end; after->start = map->end;
map_groups__insert(mg, after); __maps__insert(maps, after);
if (verbose >= 2) if (verbose >= 2)
map__fprintf(after, fp); map__fprintf(after, fp);
} }
move_map: put_map:
/* /*
* If we have references, just move them to a separate list. * If we have references, just move them to a separate list.
*/ */
if (pos->referenced) if (pos->referenced)
list_add_tail(&pos->node, &mg->removed_maps[map->type]); list_add_tail(&pos->node, &maps->removed_maps);
else else
map__delete(pos); map__put(pos);
if (err) if (err)
return err; goto out;
} }
return 0; err = 0;
out:
pthread_rwlock_unlock(&maps->lock);
return err;
}
int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
FILE *fp)
{
return maps__fixup_overlappings(&mg->maps[map->type], map, fp);
} }
/* /*
...@@ -688,21 +742,28 @@ int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, ...@@ -688,21 +742,28 @@ int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
int map_groups__clone(struct map_groups *mg, int map_groups__clone(struct map_groups *mg,
struct map_groups *parent, enum map_type type) struct map_groups *parent, enum map_type type)
{ {
int err = -ENOMEM;
struct map *map; struct map *map;
struct rb_root *maps = &parent->maps[type]; struct maps *maps = &parent->maps[type];
pthread_rwlock_rdlock(&maps->lock);
for (map = maps__first(maps); map; map = map__next(map)) { for (map = maps__first(maps); map; map = map__next(map)) {
struct map *new = map__clone(map); struct map *new = map__clone(map);
if (new == NULL) if (new == NULL)
return -ENOMEM; goto out_unlock;
map_groups__insert(mg, new); map_groups__insert(mg, new);
} }
return 0;
err = 0;
out_unlock:
pthread_rwlock_unlock(&maps->lock);
return err;
} }
void maps__insert(struct rb_root *maps, struct map *map) static void __maps__insert(struct maps *maps, struct map *map)
{ {
struct rb_node **p = &maps->rb_node; struct rb_node **p = &maps->entries.rb_node;
struct rb_node *parent = NULL; struct rb_node *parent = NULL;
const u64 ip = map->start; const u64 ip = map->start;
struct map *m; struct map *m;
...@@ -717,20 +778,38 @@ void maps__insert(struct rb_root *maps, struct map *map) ...@@ -717,20 +778,38 @@ void maps__insert(struct rb_root *maps, struct map *map)
} }
rb_link_node(&map->rb_node, parent, p); rb_link_node(&map->rb_node, parent, p);
rb_insert_color(&map->rb_node, maps); rb_insert_color(&map->rb_node, &maps->entries);
map__get(map);
} }
void maps__remove(struct rb_root *maps, struct map *map) void maps__insert(struct maps *maps, struct map *map)
{ {
rb_erase(&map->rb_node, maps); pthread_rwlock_wrlock(&maps->lock);
__maps__insert(maps, map);
pthread_rwlock_unlock(&maps->lock);
} }
struct map *maps__find(struct rb_root *maps, u64 ip) static void __maps__remove(struct maps *maps, struct map *map)
{ {
struct rb_node **p = &maps->rb_node; rb_erase_init(&map->rb_node, &maps->entries);
struct rb_node *parent = NULL; map__put(map);
}
void maps__remove(struct maps *maps, struct map *map)
{
pthread_rwlock_wrlock(&maps->lock);
__maps__remove(maps, map);
pthread_rwlock_unlock(&maps->lock);
}
struct map *maps__find(struct maps *maps, u64 ip)
{
struct rb_node **p, *parent = NULL;
struct map *m; struct map *m;
pthread_rwlock_rdlock(&maps->lock);
p = &maps->entries.rb_node;
while (*p != NULL) { while (*p != NULL) {
parent = *p; parent = *p;
m = rb_entry(parent, struct map, rb_node); m = rb_entry(parent, struct map, rb_node);
...@@ -739,15 +818,18 @@ struct map *maps__find(struct rb_root *maps, u64 ip) ...@@ -739,15 +818,18 @@ struct map *maps__find(struct rb_root *maps, u64 ip)
else if (ip >= m->end) else if (ip >= m->end)
p = &(*p)->rb_right; p = &(*p)->rb_right;
else else
return m; goto out;
} }
return NULL; m = NULL;
out:
pthread_rwlock_unlock(&maps->lock);
return m;
} }
struct map *maps__first(struct rb_root *maps) struct map *maps__first(struct maps *maps)
{ {
struct rb_node *first = rb_first(maps); struct rb_node *first = rb_first(&maps->entries);
if (first) if (first)
return rb_entry(first, struct map, rb_node); return rb_entry(first, struct map, rb_node);
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include <pthread.h>
#include <stdio.h> #include <stdio.h>
#include <stdbool.h> #include <stdbool.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -51,6 +52,7 @@ struct map { ...@@ -51,6 +52,7 @@ struct map {
struct dso *dso; struct dso *dso;
struct map_groups *groups; struct map_groups *groups;
atomic_t refcnt;
}; };
struct kmap { struct kmap {
...@@ -58,9 +60,14 @@ struct kmap { ...@@ -58,9 +60,14 @@ struct kmap {
struct map_groups *kmaps; struct map_groups *kmaps;
}; };
struct maps {
struct rb_root entries;
pthread_rwlock_t lock;
struct list_head removed_maps;
};
struct map_groups { struct map_groups {
struct rb_root maps[MAP__NR_TYPES]; struct maps maps[MAP__NR_TYPES];
struct list_head removed_maps[MAP__NR_TYPES];
struct machine *machine; struct machine *machine;
atomic_t refcnt; atomic_t refcnt;
}; };
...@@ -144,6 +151,16 @@ struct map *map__new(struct machine *machine, u64 start, u64 len, ...@@ -144,6 +151,16 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,
struct map *map__new2(u64 start, struct dso *dso, enum map_type type); struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
void map__delete(struct map *map); void map__delete(struct map *map);
struct map *map__clone(struct map *map); struct map *map__clone(struct map *map);
static inline struct map *map__get(struct map *map)
{
if (map)
atomic_inc(&map->refcnt);
return map;
}
void map__put(struct map *map);
int map__overlap(struct map *l, struct map *r); int map__overlap(struct map *l, struct map *r);
size_t map__fprintf(struct map *map, FILE *fp); size_t map__fprintf(struct map *map, FILE *fp);
size_t map__fprintf_dsoname(struct map *map, FILE *fp); size_t map__fprintf_dsoname(struct map *map, FILE *fp);
...@@ -162,10 +179,10 @@ void map__reloc_vmlinux(struct map *map); ...@@ -162,10 +179,10 @@ void map__reloc_vmlinux(struct map *map);
size_t __map_groups__fprintf_maps(struct map_groups *mg, enum map_type type, size_t __map_groups__fprintf_maps(struct map_groups *mg, enum map_type type,
FILE *fp); FILE *fp);
void maps__insert(struct rb_root *maps, struct map *map); void maps__insert(struct maps *maps, struct map *map);
void maps__remove(struct rb_root *maps, struct map *map); void maps__remove(struct maps *maps, struct map *map);
struct map *maps__find(struct rb_root *maps, u64 addr); struct map *maps__find(struct maps *maps, u64 addr);
struct map *maps__first(struct rb_root *maps); struct map *maps__first(struct maps *maps);
struct map *map__next(struct map *map); struct map *map__next(struct map *map);
void map_groups__init(struct map_groups *mg, struct machine *machine); void map_groups__init(struct map_groups *mg, struct machine *machine);
void map_groups__exit(struct map_groups *mg); void map_groups__exit(struct map_groups *mg);
......
#include "perf.h"
#include "util/util.h"
#include "util/debug.h"
#include "util/parse-options.h"
#include "util/parse-branch-options.h"
#define BRANCH_OPT(n, m) \
{ .name = n, .mode = (m) }
#define BRANCH_END { .name = NULL }
struct branch_mode {
const char *name;
int mode;
};
static const struct branch_mode branch_modes[] = {
BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
BRANCH_OPT("cond", PERF_SAMPLE_BRANCH_COND),
BRANCH_END
};
int
parse_branch_stack(const struct option *opt, const char *str, int unset)
{
#define ONLY_PLM \
(PERF_SAMPLE_BRANCH_USER |\
PERF_SAMPLE_BRANCH_KERNEL |\
PERF_SAMPLE_BRANCH_HV)
uint64_t *mode = (uint64_t *)opt->value;
const struct branch_mode *br;
char *s, *os = NULL, *p;
int ret = -1;
if (unset)
return 0;
/*
* cannot set it twice, -b + --branch-filter for instance
*/
if (*mode)
return -1;
/* str may be NULL in case no arg is passed to -b */
if (str) {
/* because str is read-only */
s = os = strdup(str);
if (!s)
return -1;
for (;;) {
p = strchr(s, ',');
if (p)
*p = '\0';
for (br = branch_modes; br->name; br++) {
if (!strcasecmp(s, br->name))
break;
}
if (!br->name) {
ui__warning("unknown branch filter %s,"
" check man page\n", s);
goto error;
}
*mode |= br->mode;
if (!p)
break;
s = p + 1;
}
}
ret = 0;
/* default to any branch */
if ((*mode & ~ONLY_PLM) == 0) {
*mode = PERF_SAMPLE_BRANCH_ANY;
}
error:
free(os);
return ret;
}
#ifndef _PERF_PARSE_BRANCH_OPTIONS_H
#define _PERF_PARSE_BRANCH_OPTIONS_H 1
struct option;
int parse_branch_stack(const struct option *opt, const char *str, int unset);
#endif /* _PERF_PARSE_BRANCH_OPTIONS_H */
...@@ -163,7 +163,7 @@ static u64 kernel_get_symbol_address_by_name(const char *name, bool reloc) ...@@ -163,7 +163,7 @@ static u64 kernel_get_symbol_address_by_name(const char *name, bool reloc)
static struct map *kernel_get_module_map(const char *module) static struct map *kernel_get_module_map(const char *module)
{ {
struct map_groups *grp = &host_machine->kmaps; struct map_groups *grp = &host_machine->kmaps;
struct rb_root *maps = &grp->maps[MAP__FUNCTION]; struct maps *maps = &grp->maps[MAP__FUNCTION];
struct map *pos; struct map *pos;
/* A file path -- this is an offline module */ /* A file path -- this is an offline module */
...@@ -195,7 +195,7 @@ static void put_target_map(struct map *map, bool user) ...@@ -195,7 +195,7 @@ static void put_target_map(struct map *map, bool user)
{ {
if (map && user) { if (map && user) {
/* Only the user map needs to be released */ /* Only the user map needs to be released */
map__delete(map); map__put(map);
} }
} }
...@@ -1791,7 +1791,7 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp, ...@@ -1791,7 +1791,7 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
out: out:
if (map && !is_kprobe) { if (map && !is_kprobe) {
map__delete(map); map__put(map);
} }
return ret; return ret;
...@@ -2884,7 +2884,7 @@ int show_available_funcs(const char *target, struct strfilter *_filter, ...@@ -2884,7 +2884,7 @@ int show_available_funcs(const char *target, struct strfilter *_filter,
dso__fprintf_symbols_by_name(map->dso, map->type, stdout); dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
end: end:
if (user) { if (user) {
map__delete(map); map__put(map);
} }
exit_symbol_maps(); exit_symbol_maps();
......
...@@ -972,8 +972,10 @@ int dso__load_sym(struct dso *dso, struct map *map, ...@@ -972,8 +972,10 @@ int dso__load_sym(struct dso *dso, struct map *map,
map->unmap_ip = map__unmap_ip; map->unmap_ip = map__unmap_ip;
/* Ensure maps are correctly ordered */ /* Ensure maps are correctly ordered */
if (kmaps) { if (kmaps) {
map__get(map);
map_groups__remove(kmaps, map); map_groups__remove(kmaps, map);
map_groups__insert(kmaps, map); map_groups__insert(kmaps, map);
map__put(map);
} }
} }
......
...@@ -202,12 +202,14 @@ void symbols__fixup_end(struct rb_root *symbols) ...@@ -202,12 +202,14 @@ void symbols__fixup_end(struct rb_root *symbols)
void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
{ {
struct rb_root *maps = &mg->maps[type]; struct maps *maps = &mg->maps[type];
struct map *next, *curr; struct map *next, *curr;
pthread_rwlock_wrlock(&maps->lock);
curr = maps__first(maps); curr = maps__first(maps);
if (curr == NULL) if (curr == NULL)
return; goto out_unlock;
for (next = map__next(curr); next; next = map__next(curr)) { for (next = map__next(curr); next; next = map__next(curr)) {
curr->end = next->start; curr->end = next->start;
...@@ -219,6 +221,9 @@ void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) ...@@ -219,6 +221,9 @@ void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
* last map final address. * last map final address.
*/ */
curr->end = ~0ULL; curr->end = ~0ULL;
out_unlock:
pthread_rwlock_unlock(&maps->lock);
} }
struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name) struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name)
...@@ -654,14 +659,14 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map, ...@@ -654,14 +659,14 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map,
curr_map = map_groups__find(kmaps, map->type, pos->start); curr_map = map_groups__find(kmaps, map->type, pos->start);
if (!curr_map || (filter && filter(curr_map, pos))) { if (!curr_map || (filter && filter(curr_map, pos))) {
rb_erase(&pos->rb_node, root); rb_erase_init(&pos->rb_node, root);
symbol__delete(pos); symbol__delete(pos);
} else { } else {
pos->start -= curr_map->start - curr_map->pgoff; pos->start -= curr_map->start - curr_map->pgoff;
if (pos->end) if (pos->end)
pos->end -= curr_map->start - curr_map->pgoff; pos->end -= curr_map->start - curr_map->pgoff;
if (curr_map != map) { if (curr_map != map) {
rb_erase(&pos->rb_node, root); rb_erase_init(&pos->rb_node, root);
symbols__insert( symbols__insert(
&curr_map->dso->symbols[curr_map->type], &curr_map->dso->symbols[curr_map->type],
pos); pos);
...@@ -1168,20 +1173,23 @@ static int dso__load_kcore(struct dso *dso, struct map *map, ...@@ -1168,20 +1173,23 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
/* Add new maps */ /* Add new maps */
while (!list_empty(&md.maps)) { while (!list_empty(&md.maps)) {
new_map = list_entry(md.maps.next, struct map, node); new_map = list_entry(md.maps.next, struct map, node);
list_del(&new_map->node); list_del_init(&new_map->node);
if (new_map == replacement_map) { if (new_map == replacement_map) {
map->start = new_map->start; map->start = new_map->start;
map->end = new_map->end; map->end = new_map->end;
map->pgoff = new_map->pgoff; map->pgoff = new_map->pgoff;
map->map_ip = new_map->map_ip; map->map_ip = new_map->map_ip;
map->unmap_ip = new_map->unmap_ip; map->unmap_ip = new_map->unmap_ip;
map__delete(new_map);
/* Ensure maps are correctly ordered */ /* Ensure maps are correctly ordered */
map__get(map);
map_groups__remove(kmaps, map); map_groups__remove(kmaps, map);
map_groups__insert(kmaps, map); map_groups__insert(kmaps, map);
map__put(map);
} else { } else {
map_groups__insert(kmaps, new_map); map_groups__insert(kmaps, new_map);
} }
map__put(new_map);
} }
/* /*
...@@ -1206,8 +1214,8 @@ static int dso__load_kcore(struct dso *dso, struct map *map, ...@@ -1206,8 +1214,8 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
out_err: out_err:
while (!list_empty(&md.maps)) { while (!list_empty(&md.maps)) {
map = list_entry(md.maps.next, struct map, node); map = list_entry(md.maps.next, struct map, node);
list_del(&map->node); list_del_init(&map->node);
map__delete(map); map__put(map);
} }
close(fd); close(fd);
return -EINVAL; return -EINVAL;
...@@ -1520,15 +1528,21 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) ...@@ -1520,15 +1528,21 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
struct map *map_groups__find_by_name(struct map_groups *mg, struct map *map_groups__find_by_name(struct map_groups *mg,
enum map_type type, const char *name) enum map_type type, const char *name)
{ {
struct rb_root *maps = &mg->maps[type]; struct maps *maps = &mg->maps[type];
struct map *map; struct map *map;
pthread_rwlock_rdlock(&maps->lock);
for (map = maps__first(maps); map; map = map__next(map)) { for (map = maps__first(maps); map; map = map__next(map)) {
if (map->dso && strcmp(map->dso->short_name, name) == 0) if (map->dso && strcmp(map->dso->short_name, name) == 0)
return map; goto out_unlock;
} }
return NULL; map = NULL;
out_unlock:
pthread_rwlock_unlock(&maps->lock);
return map;
} }
int dso__load_vmlinux(struct dso *dso, struct map *map, int dso__load_vmlinux(struct dso *dso, struct map *map,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册