diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2015-06-01 14:40:01 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2015-06-08 09:31:40 -0400 |
commit | e88078442232f3bbcb4ff1d24b3f9ab3dca472b9 (patch) | |
tree | d755616b5eb4d95607e4d75f36f221b9e7de4972 /tools | |
parent | 9f2de31542f1ac38a15117f90ee6b8449951d86e (diff) |
perf tools: Protect accesses the dso rbtrees/lists with a rw lock
To allow concurrent access, next step: refcount struct dso instances, so
that we can ditch unused them when the last map pointing to it goes
away.
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: http://lkml.kernel.org/n/tip-yk1k08etpd2aoe3tnrf0oizn@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/util/dso.c | 52 | ||||
-rw-r--r-- | tools/perf/util/dso.h | 10 | ||||
-rw-r--r-- | tools/perf/util/machine.c | 27 | ||||
-rw-r--r-- | tools/perf/util/vdso.c | 53 |
4 files changed, 95 insertions, 47 deletions
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 5ec9e892c89b..ff0204ac4321 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c | |||
@@ -889,8 +889,8 @@ struct dso *machine__findnew_kernel(struct machine *machine, const char *name, | |||
889 | * Either one of the dso or name parameter must be non-NULL or the | 889 | * Either one of the dso or name parameter must be non-NULL or the |
890 | * function will not work. | 890 | * function will not work. |
891 | */ | 891 | */ |
892 | static struct dso *dso__findlink_by_longname(struct rb_root *root, | 892 | static struct dso *__dso__findlink_by_longname(struct rb_root *root, |
893 | struct dso *dso, const char *name) | 893 | struct dso *dso, const char *name) |
894 | { | 894 | { |
895 | struct rb_node **p = &root->rb_node; | 895 | struct rb_node **p = &root->rb_node; |
896 | struct rb_node *parent = NULL; | 896 | struct rb_node *parent = NULL; |
@@ -937,10 +937,10 @@ static struct dso *dso__findlink_by_longname(struct rb_root *root, | |||
937 | return NULL; | 937 | return NULL; |
938 | } | 938 | } |
939 | 939 | ||
940 | static inline struct dso * | 940 | static inline struct dso *__dso__find_by_longname(struct rb_root *root, |
941 | dso__find_by_longname(const struct rb_root *root, const char *name) | 941 | const char *name) |
942 | { | 942 | { |
943 | return dso__findlink_by_longname((struct rb_root *)root, NULL, name); | 943 | return __dso__findlink_by_longname(root, NULL, name); |
944 | } | 944 | } |
945 | 945 | ||
946 | void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated) | 946 | void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated) |
@@ -1149,14 +1149,20 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits) | |||
1149 | return have_build_id; | 1149 | return have_build_id; |
1150 | } | 1150 | } |
1151 | 1151 | ||
1152 | void dsos__add(struct dsos *dsos, struct dso *dso) | 1152 | void __dsos__add(struct dsos *dsos, struct dso *dso) |
1153 | { | 1153 | { |
1154 | list_add_tail(&dso->node, &dsos->head); | 1154 | list_add_tail(&dso->node, &dsos->head); |
1155 | dso__findlink_by_longname(&dsos->root, dso, NULL); | 1155 | __dso__findlink_by_longname(&dsos->root, dso, NULL); |
1156 | } | ||
1157 | |||
1158 | void dsos__add(struct dsos *dsos, struct dso *dso) | ||
1159 | { | ||
1160 | pthread_rwlock_wrlock(&dsos->lock); | ||
1161 | __dsos__add(dsos, dso); | ||
1162 | pthread_rwlock_unlock(&dsos->lock); | ||
1156 | } | 1163 | } |
1157 | 1164 | ||
1158 | struct dso *dsos__find(const struct dsos *dsos, const char *name, | 1165 | struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short) |
1159 | bool cmp_short) | ||
1160 | { | 1166 | { |
1161 | struct dso *pos; | 1167 | struct dso *pos; |
1162 | 1168 | ||
@@ -1166,15 +1172,24 @@ struct dso *dsos__find(const struct dsos *dsos, const char *name, | |||
1166 | return pos; | 1172 | return pos; |
1167 | return NULL; | 1173 | return NULL; |
1168 | } | 1174 | } |
1169 | return dso__find_by_longname(&dsos->root, name); | 1175 | return __dso__find_by_longname(&dsos->root, name); |
1170 | } | 1176 | } |
1171 | 1177 | ||
1172 | struct dso *dsos__addnew(struct dsos *dsos, const char *name) | 1178 | struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short) |
1179 | { | ||
1180 | struct dso *dso; | ||
1181 | pthread_rwlock_rdlock(&dsos->lock); | ||
1182 | dso = __dsos__find(dsos, name, cmp_short); | ||
1183 | pthread_rwlock_unlock(&dsos->lock); | ||
1184 | return dso; | ||
1185 | } | ||
1186 | |||
1187 | struct dso *__dsos__addnew(struct dsos *dsos, const char *name) | ||
1173 | { | 1188 | { |
1174 | struct dso *dso = dso__new(name); | 1189 | struct dso *dso = dso__new(name); |
1175 | 1190 | ||
1176 | if (dso != NULL) { | 1191 | if (dso != NULL) { |
1177 | dsos__add(dsos, dso); | 1192 | __dsos__add(dsos, dso); |
1178 | dso__set_basename(dso); | 1193 | dso__set_basename(dso); |
1179 | } | 1194 | } |
1180 | return dso; | 1195 | return dso; |
@@ -1182,9 +1197,18 @@ struct dso *dsos__addnew(struct dsos *dsos, const char *name) | |||
1182 | 1197 | ||
1183 | struct dso *__dsos__findnew(struct dsos *dsos, const char *name) | 1198 | struct dso *__dsos__findnew(struct dsos *dsos, const char *name) |
1184 | { | 1199 | { |
1185 | struct dso *dso = dsos__find(dsos, name, false); | 1200 | struct dso *dso = __dsos__find(dsos, name, false); |
1201 | |||
1202 | return dso ? dso : __dsos__addnew(dsos, name); | ||
1203 | } | ||
1186 | 1204 | ||
1187 | return dso ? dso : dsos__addnew(dsos, name); | 1205 | struct dso *dsos__findnew(struct dsos *dsos, const char *name) |
1206 | { | ||
1207 | struct dso *dso; | ||
1208 | pthread_rwlock_wrlock(&dsos->lock); | ||
1209 | dso = __dsos__findnew(dsos, name); | ||
1210 | pthread_rwlock_unlock(&dsos->lock); | ||
1211 | return dso; | ||
1188 | } | 1212 | } |
1189 | 1213 | ||
1190 | size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, | 1214 | size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, |
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index ba2d90ed881f..c16ab5d849c3 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | #include <linux/rbtree.h> | 5 | #include <linux/rbtree.h> |
6 | #include <stdbool.h> | 6 | #include <stdbool.h> |
7 | #include <pthread.h> | ||
7 | #include <linux/types.h> | 8 | #include <linux/types.h> |
8 | #include <linux/bitops.h> | 9 | #include <linux/bitops.h> |
9 | #include "map.h" | 10 | #include "map.h" |
@@ -124,6 +125,7 @@ struct dso_cache { | |||
124 | struct dsos { | 125 | struct dsos { |
125 | struct list_head head; | 126 | struct list_head head; |
126 | struct rb_root root; /* rbtree root sorted by long name */ | 127 | struct rb_root root; /* rbtree root sorted by long name */ |
128 | pthread_rwlock_t lock; | ||
127 | }; | 129 | }; |
128 | 130 | ||
129 | struct auxtrace_cache; | 131 | struct auxtrace_cache; |
@@ -297,11 +299,13 @@ struct map *dso__new_map(const char *name); | |||
297 | struct dso *machine__findnew_kernel(struct machine *machine, const char *name, | 299 | struct dso *machine__findnew_kernel(struct machine *machine, const char *name, |
298 | const char *short_name, int dso_type); | 300 | const char *short_name, int dso_type); |
299 | 301 | ||
302 | void __dsos__add(struct dsos *dsos, struct dso *dso); | ||
300 | void dsos__add(struct dsos *dsos, struct dso *dso); | 303 | void dsos__add(struct dsos *dsos, struct dso *dso); |
301 | struct dso *dsos__addnew(struct dsos *dsos, const char *name); | 304 | struct dso *__dsos__addnew(struct dsos *dsos, const char *name); |
302 | struct dso *dsos__find(const struct dsos *dsos, const char *name, | 305 | struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short); |
303 | bool cmp_short); | 306 | struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short); |
304 | struct dso *__dsos__findnew(struct dsos *dsos, const char *name); | 307 | struct dso *__dsos__findnew(struct dsos *dsos, const char *name); |
308 | struct dso *dsos__findnew(struct dsos *dsos, const char *name); | ||
305 | bool __dsos__read_build_ids(struct list_head *head, bool with_hits); | 309 | bool __dsos__read_build_ids(struct list_head *head, bool with_hits); |
306 | 310 | ||
307 | size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, | 311 | size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, |
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index dfd419797e6e..0cf56d6f073a 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -20,6 +20,7 @@ static void dsos__init(struct dsos *dsos) | |||
20 | { | 20 | { |
21 | INIT_LIST_HEAD(&dsos->head); | 21 | INIT_LIST_HEAD(&dsos->head); |
22 | dsos->root = RB_ROOT; | 22 | dsos->root = RB_ROOT; |
23 | pthread_rwlock_init(&dsos->lock, NULL); | ||
23 | } | 24 | } |
24 | 25 | ||
25 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid) | 26 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid) |
@@ -81,15 +82,21 @@ out_delete: | |||
81 | return NULL; | 82 | return NULL; |
82 | } | 83 | } |
83 | 84 | ||
84 | static void dsos__delete(struct dsos *dsos) | 85 | static void dsos__exit(struct dsos *dsos) |
85 | { | 86 | { |
86 | struct dso *pos, *n; | 87 | struct dso *pos, *n; |
87 | 88 | ||
89 | pthread_rwlock_wrlock(&dsos->lock); | ||
90 | |||
88 | list_for_each_entry_safe(pos, n, &dsos->head, node) { | 91 | list_for_each_entry_safe(pos, n, &dsos->head, node) { |
89 | RB_CLEAR_NODE(&pos->rb_node); | 92 | RB_CLEAR_NODE(&pos->rb_node); |
90 | list_del(&pos->node); | 93 | list_del(&pos->node); |
91 | dso__delete(pos); | 94 | dso__delete(pos); |
92 | } | 95 | } |
96 | |||
97 | pthread_rwlock_unlock(&dsos->lock); | ||
98 | |||
99 | pthread_rwlock_destroy(&dsos->lock); | ||
93 | } | 100 | } |
94 | 101 | ||
95 | void machine__delete_threads(struct machine *machine) | 102 | void machine__delete_threads(struct machine *machine) |
@@ -110,7 +117,7 @@ void machine__delete_threads(struct machine *machine) | |||
110 | void machine__exit(struct machine *machine) | 117 | void machine__exit(struct machine *machine) |
111 | { | 118 | { |
112 | map_groups__exit(&machine->kmaps); | 119 | map_groups__exit(&machine->kmaps); |
113 | dsos__delete(&machine->dsos); | 120 | dsos__exit(&machine->dsos); |
114 | machine__exit_vdso(machine); | 121 | machine__exit_vdso(machine); |
115 | zfree(&machine->root_dir); | 122 | zfree(&machine->root_dir); |
116 | zfree(&machine->current_tid); | 123 | zfree(&machine->current_tid); |
@@ -496,11 +503,13 @@ static struct dso *machine__findnew_module_dso(struct machine *machine, | |||
496 | { | 503 | { |
497 | struct dso *dso; | 504 | struct dso *dso; |
498 | 505 | ||
499 | dso = dsos__find(&machine->dsos, m->name, true); | 506 | pthread_rwlock_wrlock(&machine->dsos.lock); |
507 | |||
508 | dso = __dsos__find(&machine->dsos, m->name, true); | ||
500 | if (!dso) { | 509 | if (!dso) { |
501 | dso = dsos__addnew(&machine->dsos, m->name); | 510 | dso = __dsos__addnew(&machine->dsos, m->name); |
502 | if (dso == NULL) | 511 | if (dso == NULL) |
503 | return NULL; | 512 | goto out_unlock; |
504 | 513 | ||
505 | if (machine__is_host(machine)) | 514 | if (machine__is_host(machine)) |
506 | dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE; | 515 | dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE; |
@@ -515,6 +524,8 @@ static struct dso *machine__findnew_module_dso(struct machine *machine, | |||
515 | dso__set_long_name(dso, strdup(filename), true); | 524 | dso__set_long_name(dso, strdup(filename), true); |
516 | } | 525 | } |
517 | 526 | ||
527 | out_unlock: | ||
528 | pthread_rwlock_unlock(&machine->dsos.lock); | ||
518 | return dso; | 529 | return dso; |
519 | } | 530 | } |
520 | 531 | ||
@@ -1156,6 +1167,8 @@ static int machine__process_kernel_mmap_event(struct machine *machine, | |||
1156 | struct dso *kernel = NULL; | 1167 | struct dso *kernel = NULL; |
1157 | struct dso *dso; | 1168 | struct dso *dso; |
1158 | 1169 | ||
1170 | pthread_rwlock_rdlock(&machine->dsos.lock); | ||
1171 | |||
1159 | list_for_each_entry(dso, &machine->dsos.head, node) { | 1172 | list_for_each_entry(dso, &machine->dsos.head, node) { |
1160 | 1173 | ||
1161 | /* | 1174 | /* |
@@ -1184,6 +1197,8 @@ static int machine__process_kernel_mmap_event(struct machine *machine, | |||
1184 | break; | 1197 | break; |
1185 | } | 1198 | } |
1186 | 1199 | ||
1200 | pthread_rwlock_unlock(&machine->dsos.lock); | ||
1201 | |||
1187 | if (kernel == NULL) | 1202 | if (kernel == NULL) |
1188 | kernel = machine__findnew_dso(machine, kmmap_prefix); | 1203 | kernel = machine__findnew_dso(machine, kmmap_prefix); |
1189 | if (kernel == NULL) | 1204 | if (kernel == NULL) |
@@ -1948,5 +1963,5 @@ int machine__get_kernel_start(struct machine *machine) | |||
1948 | 1963 | ||
1949 | struct dso *machine__findnew_dso(struct machine *machine, const char *filename) | 1964 | struct dso *machine__findnew_dso(struct machine *machine, const char *filename) |
1950 | { | 1965 | { |
1951 | return __dsos__findnew(&machine->dsos, filename); | 1966 | return dsos__findnew(&machine->dsos, filename); |
1952 | } | 1967 | } |
diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c index 2e8f6886ca72..c646c74c34f8 100644 --- a/tools/perf/util/vdso.c +++ b/tools/perf/util/vdso.c | |||
@@ -120,14 +120,14 @@ void machine__exit_vdso(struct machine *machine) | |||
120 | zfree(&machine->vdso_info); | 120 | zfree(&machine->vdso_info); |
121 | } | 121 | } |
122 | 122 | ||
123 | static struct dso *machine__addnew_vdso(struct machine *machine, const char *short_name, | 123 | static struct dso *__machine__addnew_vdso(struct machine *machine, const char *short_name, |
124 | const char *long_name) | 124 | const char *long_name) |
125 | { | 125 | { |
126 | struct dso *dso; | 126 | struct dso *dso; |
127 | 127 | ||
128 | dso = dso__new(short_name); | 128 | dso = dso__new(short_name); |
129 | if (dso != NULL) { | 129 | if (dso != NULL) { |
130 | dsos__add(&machine->dsos, dso); | 130 | __dsos__add(&machine->dsos, dso); |
131 | dso__set_long_name(dso, long_name, false); | 131 | dso__set_long_name(dso, long_name, false); |
132 | } | 132 | } |
133 | 133 | ||
@@ -230,27 +230,31 @@ static const char *vdso__get_compat_file(struct vdso_file *vdso_file) | |||
230 | return vdso_file->temp_file_name; | 230 | return vdso_file->temp_file_name; |
231 | } | 231 | } |
232 | 232 | ||
233 | static struct dso *vdso__findnew_compat(struct machine *machine, | 233 | static struct dso *__machine__findnew_compat(struct machine *machine, |
234 | struct vdso_file *vdso_file) | 234 | struct vdso_file *vdso_file) |
235 | { | 235 | { |
236 | const char *file_name; | 236 | const char *file_name; |
237 | struct dso *dso; | 237 | struct dso *dso; |
238 | 238 | ||
239 | dso = dsos__find(&machine->dsos, vdso_file->dso_name, true); | 239 | pthread_rwlock_wrlock(&machine->dsos.lock); |
240 | dso = __dsos__find(&machine->dsos, vdso_file->dso_name, true); | ||
240 | if (dso) | 241 | if (dso) |
241 | return dso; | 242 | goto out_unlock; |
242 | 243 | ||
243 | file_name = vdso__get_compat_file(vdso_file); | 244 | file_name = vdso__get_compat_file(vdso_file); |
244 | if (!file_name) | 245 | if (!file_name) |
245 | return NULL; | 246 | goto out_unlock; |
246 | 247 | ||
247 | return machine__addnew_vdso(machine, vdso_file->dso_name, file_name); | 248 | dso = __machine__addnew_vdso(machine, vdso_file->dso_name, file_name); |
249 | out_unlock: | ||
250 | pthread_rwlock_unlock(&machine->dsos.lock); | ||
251 | return dso; | ||
248 | } | 252 | } |
249 | 253 | ||
250 | static int machine__findnew_vdso_compat(struct machine *machine, | 254 | static int __machine__findnew_vdso_compat(struct machine *machine, |
251 | struct thread *thread, | 255 | struct thread *thread, |
252 | struct vdso_info *vdso_info, | 256 | struct vdso_info *vdso_info, |
253 | struct dso **dso) | 257 | struct dso **dso) |
254 | { | 258 | { |
255 | enum dso_type dso_type; | 259 | enum dso_type dso_type; |
256 | 260 | ||
@@ -267,10 +271,10 @@ static int machine__findnew_vdso_compat(struct machine *machine, | |||
267 | 271 | ||
268 | switch (dso_type) { | 272 | switch (dso_type) { |
269 | case DSO__TYPE_32BIT: | 273 | case DSO__TYPE_32BIT: |
270 | *dso = vdso__findnew_compat(machine, &vdso_info->vdso32); | 274 | *dso = __machine__findnew_compat(machine, &vdso_info->vdso32); |
271 | return 1; | 275 | return 1; |
272 | case DSO__TYPE_X32BIT: | 276 | case DSO__TYPE_X32BIT: |
273 | *dso = vdso__findnew_compat(machine, &vdso_info->vdsox32); | 277 | *dso = __machine__findnew_compat(machine, &vdso_info->vdsox32); |
274 | return 1; | 278 | return 1; |
275 | case DSO__TYPE_UNKNOWN: | 279 | case DSO__TYPE_UNKNOWN: |
276 | case DSO__TYPE_64BIT: | 280 | case DSO__TYPE_64BIT: |
@@ -285,31 +289,32 @@ struct dso *machine__findnew_vdso(struct machine *machine, | |||
285 | struct thread *thread __maybe_unused) | 289 | struct thread *thread __maybe_unused) |
286 | { | 290 | { |
287 | struct vdso_info *vdso_info; | 291 | struct vdso_info *vdso_info; |
288 | struct dso *dso; | 292 | struct dso *dso = NULL; |
289 | 293 | ||
294 | pthread_rwlock_wrlock(&machine->dsos.lock); | ||
290 | if (!machine->vdso_info) | 295 | if (!machine->vdso_info) |
291 | machine->vdso_info = vdso_info__new(); | 296 | machine->vdso_info = vdso_info__new(); |
292 | 297 | ||
293 | vdso_info = machine->vdso_info; | 298 | vdso_info = machine->vdso_info; |
294 | if (!vdso_info) | 299 | if (!vdso_info) |
295 | return NULL; | 300 | goto out_unlock; |
296 | 301 | ||
297 | #if BITS_PER_LONG == 64 | 302 | #if BITS_PER_LONG == 64 |
298 | if (machine__findnew_vdso_compat(machine, thread, vdso_info, &dso)) | 303 | if (__machine__findnew_vdso_compat(machine, thread, vdso_info, &dso)) |
299 | return dso; | 304 | goto out_unlock; |
300 | #endif | 305 | #endif |
301 | 306 | ||
302 | dso = dsos__find(&machine->dsos, DSO__NAME_VDSO, true); | 307 | dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO, true); |
303 | if (!dso) { | 308 | if (!dso) { |
304 | char *file; | 309 | char *file; |
305 | 310 | ||
306 | file = get_file(&vdso_info->vdso); | 311 | file = get_file(&vdso_info->vdso); |
307 | if (!file) | 312 | if (file) |
308 | return NULL; | 313 | dso = __machine__addnew_vdso(machine, DSO__NAME_VDSO, file); |
309 | |||
310 | dso = machine__addnew_vdso(machine, DSO__NAME_VDSO, file); | ||
311 | } | 314 | } |
312 | 315 | ||
316 | out_unlock: | ||
317 | pthread_rwlock_unlock(&machine->dsos.lock); | ||
313 | return dso; | 318 | return dso; |
314 | } | 319 | } |
315 | 320 | ||