diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-18 11:19:03 -0400 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-18 11:19:03 -0400 | 
| commit | 4d7b4ac22fbec1a03206c6cde353f2fd6942f828 (patch) | |
| tree | 2d96a9e9c28cf6fa628a278decc00ad55a8b043b /tools/perf/util/thread.c | |
| parent | 3aaf51ace5975050ab43c7d4d7e439e0ae7d13d7 (diff) | |
| parent | 94f3ca95787ada3d64339a4ecb2754236ab563f6 (diff) | |
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (311 commits)
  perf tools: Add mode to build without newt support
  perf symbols: symbol inconsistency message should be done only at verbose=1
  perf tui: Add explicit -lslang option
  perf options: Type check all the remaining OPT_ variants
  perf options: Type check OPT_BOOLEAN and fix the offenders
  perf options: Check v type in OPT_U?INTEGER
  perf options: Introduce OPT_UINTEGER
  perf tui: Add workaround for slang < 2.1.4
  perf record: Fix bug mismatch with -c option definition
  perf options: Introduce OPT_U64
  perf tui: Add help window to show key associations
  perf tui: Make <- exit menus too
  perf newt: Add single key shortcuts for zoom into DSO and threads
  perf newt: Exit browser unconditionally when CTRL+C, q or Q is pressed
  perf newt: Fix the 'A'/'a' shortcut for annotate
  perf newt: Make <- exit the ui_browser
  x86, perf: P4 PMU - fix counters management logic
  perf newt: Make <- zoom out filters
  perf report: Report number of events, not samples
  perf hist: Clarify events_stats fields usage
  ...
Fix up trivial conflicts in kernel/fork.c and tools/perf/builtin-record.c
Diffstat (limited to 'tools/perf/util/thread.c')
| -rw-r--r-- | tools/perf/util/thread.c | 242 | 
1 files changed, 28 insertions, 214 deletions
| diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index fa968312ee7d..1f7ecd47f499 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
| @@ -7,13 +7,35 @@ | |||
| 7 | #include "util.h" | 7 | #include "util.h" | 
| 8 | #include "debug.h" | 8 | #include "debug.h" | 
| 9 | 9 | ||
| 10 | void map_groups__init(struct map_groups *self) | 10 | int find_all_tid(int pid, pid_t ** all_tid) | 
| 11 | { | 11 | { | 
| 12 | char name[256]; | ||
| 13 | int items; | ||
| 14 | struct dirent **namelist = NULL; | ||
| 15 | int ret = 0; | ||
| 12 | int i; | 16 | int i; | 
| 13 | for (i = 0; i < MAP__NR_TYPES; ++i) { | 17 | |
| 14 | self->maps[i] = RB_ROOT; | 18 | sprintf(name, "/proc/%d/task", pid); | 
| 15 | INIT_LIST_HEAD(&self->removed_maps[i]); | 19 | items = scandir(name, &namelist, NULL, NULL); | 
| 20 | if (items <= 0) | ||
| 21 | return -ENOENT; | ||
| 22 | *all_tid = malloc(sizeof(pid_t) * items); | ||
| 23 | if (!*all_tid) { | ||
| 24 | ret = -ENOMEM; | ||
| 25 | goto failure; | ||
| 16 | } | 26 | } | 
| 27 | |||
| 28 | for (i = 0; i < items; i++) | ||
| 29 | (*all_tid)[i] = atoi(namelist[i]->d_name); | ||
| 30 | |||
| 31 | ret = items; | ||
| 32 | |||
| 33 | failure: | ||
| 34 | for (i=0; i<items; i++) | ||
| 35 | free(namelist[i]); | ||
| 36 | free(namelist); | ||
| 37 | |||
| 38 | return ret; | ||
| 17 | } | 39 | } | 
| 18 | 40 | ||
| 19 | static struct thread *thread__new(pid_t pid) | 41 | static struct thread *thread__new(pid_t pid) | 
| @@ -31,28 +53,6 @@ static struct thread *thread__new(pid_t pid) | |||
| 31 | return self; | 53 | return self; | 
| 32 | } | 54 | } | 
| 33 | 55 | ||
| 34 | static void map_groups__flush(struct map_groups *self) | ||
| 35 | { | ||
| 36 | int type; | ||
| 37 | |||
| 38 | for (type = 0; type < MAP__NR_TYPES; type++) { | ||
| 39 | struct rb_root *root = &self->maps[type]; | ||
| 40 | struct rb_node *next = rb_first(root); | ||
| 41 | |||
| 42 | while (next) { | ||
| 43 | struct map *pos = rb_entry(next, struct map, rb_node); | ||
| 44 | next = rb_next(&pos->rb_node); | ||
| 45 | rb_erase(&pos->rb_node, root); | ||
| 46 | /* | ||
| 47 | * We may have references to this map, for | ||
| 48 | * instance in some hist_entry instances, so | ||
| 49 | * just move them to a separate list. | ||
| 50 | */ | ||
| 51 | list_add_tail(&pos->node, &self->removed_maps[pos->type]); | ||
| 52 | } | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | int thread__set_comm(struct thread *self, const char *comm) | 56 | int thread__set_comm(struct thread *self, const char *comm) | 
| 57 | { | 57 | { | 
| 58 | int err; | 58 | int err; | 
| @@ -79,69 +79,10 @@ int thread__comm_len(struct thread *self) | |||
| 79 | return self->comm_len; | 79 | return self->comm_len; | 
| 80 | } | 80 | } | 
| 81 | 81 | ||
| 82 | size_t __map_groups__fprintf_maps(struct map_groups *self, | ||
| 83 | enum map_type type, FILE *fp) | ||
| 84 | { | ||
| 85 | size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); | ||
| 86 | struct rb_node *nd; | ||
| 87 | |||
| 88 | for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { | ||
| 89 | struct map *pos = rb_entry(nd, struct map, rb_node); | ||
| 90 | printed += fprintf(fp, "Map:"); | ||
| 91 | printed += map__fprintf(pos, fp); | ||
| 92 | if (verbose > 2) { | ||
| 93 | printed += dso__fprintf(pos->dso, type, fp); | ||
| 94 | printed += fprintf(fp, "--\n"); | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | return printed; | ||
| 99 | } | ||
| 100 | |||
| 101 | size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp) | ||
| 102 | { | ||
| 103 | size_t printed = 0, i; | ||
| 104 | for (i = 0; i < MAP__NR_TYPES; ++i) | ||
| 105 | printed += __map_groups__fprintf_maps(self, i, fp); | ||
| 106 | return printed; | ||
| 107 | } | ||
| 108 | |||
| 109 | static size_t __map_groups__fprintf_removed_maps(struct map_groups *self, | ||
| 110 | enum map_type type, FILE *fp) | ||
| 111 | { | ||
| 112 | struct map *pos; | ||
| 113 | size_t printed = 0; | ||
| 114 | |||
| 115 | list_for_each_entry(pos, &self->removed_maps[type], node) { | ||
| 116 | printed += fprintf(fp, "Map:"); | ||
| 117 | printed += map__fprintf(pos, fp); | ||
| 118 | if (verbose > 1) { | ||
| 119 | printed += dso__fprintf(pos->dso, type, fp); | ||
| 120 | printed += fprintf(fp, "--\n"); | ||
| 121 | } | ||
| 122 | } | ||
| 123 | return printed; | ||
| 124 | } | ||
| 125 | |||
| 126 | static size_t map_groups__fprintf_removed_maps(struct map_groups *self, FILE *fp) | ||
| 127 | { | ||
| 128 | size_t printed = 0, i; | ||
| 129 | for (i = 0; i < MAP__NR_TYPES; ++i) | ||
| 130 | printed += __map_groups__fprintf_removed_maps(self, i, fp); | ||
| 131 | return printed; | ||
| 132 | } | ||
| 133 | |||
| 134 | static size_t map_groups__fprintf(struct map_groups *self, FILE *fp) | ||
| 135 | { | ||
| 136 | size_t printed = map_groups__fprintf_maps(self, fp); | ||
| 137 | printed += fprintf(fp, "Removed maps:\n"); | ||
| 138 | return printed + map_groups__fprintf_removed_maps(self, fp); | ||
| 139 | } | ||
| 140 | |||
| 141 | static size_t thread__fprintf(struct thread *self, FILE *fp) | 82 | static size_t thread__fprintf(struct thread *self, FILE *fp) | 
| 142 | { | 83 | { | 
| 143 | return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) + | 84 | return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) + | 
| 144 | map_groups__fprintf(&self->mg, fp); | 85 | map_groups__fprintf(&self->mg, verbose, fp); | 
| 145 | } | 86 | } | 
| 146 | 87 | ||
| 147 | struct thread *perf_session__findnew(struct perf_session *self, pid_t pid) | 88 | struct thread *perf_session__findnew(struct perf_session *self, pid_t pid) | 
| @@ -183,127 +124,12 @@ struct thread *perf_session__findnew(struct perf_session *self, pid_t pid) | |||
| 183 | return th; | 124 | return th; | 
| 184 | } | 125 | } | 
| 185 | 126 | ||
| 186 | static int map_groups__fixup_overlappings(struct map_groups *self, | ||
| 187 | struct map *map) | ||
| 188 | { | ||
| 189 | struct rb_root *root = &self->maps[map->type]; | ||
| 190 | struct rb_node *next = rb_first(root); | ||
| 191 | |||
| 192 | while (next) { | ||
| 193 | struct map *pos = rb_entry(next, struct map, rb_node); | ||
| 194 | next = rb_next(&pos->rb_node); | ||
| 195 | |||
| 196 | if (!map__overlap(pos, map)) | ||
| 197 | continue; | ||
| 198 | |||
| 199 | if (verbose >= 2) { | ||
| 200 | fputs("overlapping maps:\n", stderr); | ||
| 201 | map__fprintf(map, stderr); | ||
| 202 | map__fprintf(pos, stderr); | ||
| 203 | } | ||
| 204 | |||
| 205 | rb_erase(&pos->rb_node, root); | ||
| 206 | /* | ||
| 207 | * We may have references to this map, for instance in some | ||
| 208 | * hist_entry instances, so just move them to a separate | ||
| 209 | * list. | ||
| 210 | */ | ||
| 211 | list_add_tail(&pos->node, &self->removed_maps[map->type]); | ||
| 212 | /* | ||
| 213 | * Now check if we need to create new maps for areas not | ||
| 214 | * overlapped by the new map: | ||
| 215 | */ | ||
| 216 | if (map->start > pos->start) { | ||
| 217 | struct map *before = map__clone(pos); | ||
| 218 | |||
| 219 | if (before == NULL) | ||
| 220 | return -ENOMEM; | ||
| 221 | |||
| 222 | before->end = map->start - 1; | ||
| 223 | map_groups__insert(self, before); | ||
| 224 | if (verbose >= 2) | ||
| 225 | map__fprintf(before, stderr); | ||
| 226 | } | ||
| 227 | |||
| 228 | if (map->end < pos->end) { | ||
| 229 | struct map *after = map__clone(pos); | ||
| 230 | |||
| 231 | if (after == NULL) | ||
| 232 | return -ENOMEM; | ||
| 233 | |||
| 234 | after->start = map->end + 1; | ||
| 235 | map_groups__insert(self, after); | ||
| 236 | if (verbose >= 2) | ||
| 237 | map__fprintf(after, stderr); | ||
| 238 | } | ||
| 239 | } | ||
| 240 | |||
| 241 | return 0; | ||
| 242 | } | ||
| 243 | |||
| 244 | void maps__insert(struct rb_root *maps, struct map *map) | ||
| 245 | { | ||
| 246 | struct rb_node **p = &maps->rb_node; | ||
| 247 | struct rb_node *parent = NULL; | ||
| 248 | const u64 ip = map->start; | ||
| 249 | struct map *m; | ||
| 250 | |||
| 251 | while (*p != NULL) { | ||
| 252 | parent = *p; | ||
| 253 | m = rb_entry(parent, struct map, rb_node); | ||
| 254 | if (ip < m->start) | ||
| 255 | p = &(*p)->rb_left; | ||
| 256 | else | ||
| 257 | p = &(*p)->rb_right; | ||
| 258 | } | ||
| 259 | |||
| 260 | rb_link_node(&map->rb_node, parent, p); | ||
| 261 | rb_insert_color(&map->rb_node, maps); | ||
| 262 | } | ||
| 263 | |||
| 264 | struct map *maps__find(struct rb_root *maps, u64 ip) | ||
| 265 | { | ||
| 266 | struct rb_node **p = &maps->rb_node; | ||
| 267 | struct rb_node *parent = NULL; | ||
| 268 | struct map *m; | ||
| 269 | |||
| 270 | while (*p != NULL) { | ||
| 271 | parent = *p; | ||
| 272 | m = rb_entry(parent, struct map, rb_node); | ||
| 273 | if (ip < m->start) | ||
| 274 | p = &(*p)->rb_left; | ||
| 275 | else if (ip > m->end) | ||
| 276 | p = &(*p)->rb_right; | ||
| 277 | else | ||
| 278 | return m; | ||
| 279 | } | ||
| 280 | |||
| 281 | return NULL; | ||
| 282 | } | ||
| 283 | |||
| 284 | void thread__insert_map(struct thread *self, struct map *map) | 127 | void thread__insert_map(struct thread *self, struct map *map) | 
| 285 | { | 128 | { | 
| 286 | map_groups__fixup_overlappings(&self->mg, map); | 129 | map_groups__fixup_overlappings(&self->mg, map, verbose, stderr); | 
| 287 | map_groups__insert(&self->mg, map); | 130 | map_groups__insert(&self->mg, map); | 
| 288 | } | 131 | } | 
| 289 | 132 | ||
| 290 | /* | ||
| 291 | * XXX This should not really _copy_ te maps, but refcount them. | ||
| 292 | */ | ||
| 293 | static int map_groups__clone(struct map_groups *self, | ||
| 294 | struct map_groups *parent, enum map_type type) | ||
| 295 | { | ||
| 296 | struct rb_node *nd; | ||
| 297 | for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) { | ||
| 298 | struct map *map = rb_entry(nd, struct map, rb_node); | ||
| 299 | struct map *new = map__clone(map); | ||
| 300 | if (new == NULL) | ||
| 301 | return -ENOMEM; | ||
| 302 | map_groups__insert(self, new); | ||
| 303 | } | ||
| 304 | return 0; | ||
| 305 | } | ||
| 306 | |||
| 307 | int thread__fork(struct thread *self, struct thread *parent) | 133 | int thread__fork(struct thread *self, struct thread *parent) | 
| 308 | { | 134 | { | 
| 309 | int i; | 135 | int i; | 
| @@ -336,15 +162,3 @@ size_t perf_session__fprintf(struct perf_session *self, FILE *fp) | |||
| 336 | 162 | ||
| 337 | return ret; | 163 | return ret; | 
| 338 | } | 164 | } | 
| 339 | |||
| 340 | struct symbol *map_groups__find_symbol(struct map_groups *self, | ||
| 341 | enum map_type type, u64 addr, | ||
| 342 | symbol_filter_t filter) | ||
| 343 | { | ||
| 344 | struct map *map = map_groups__find(self, type, addr); | ||
| 345 | |||
| 346 | if (map != NULL) | ||
| 347 | return map__find_symbol(map, map->map_ip(map, addr), filter); | ||
| 348 | |||
| 349 | return NULL; | ||
| 350 | } | ||
