16baa0a5aSFrederic Weisbecker #include "../perf.h" 26baa0a5aSFrederic Weisbecker #include <stdlib.h> 36baa0a5aSFrederic Weisbecker #include <stdio.h> 46baa0a5aSFrederic Weisbecker #include <string.h> 5b3165f41SArnaldo Carvalho de Melo #include "session.h" 66baa0a5aSFrederic Weisbecker #include "thread.h" 76baa0a5aSFrederic Weisbecker #include "util.h" 86e086437SFrederic Weisbecker #include "debug.h" 96baa0a5aSFrederic Weisbecker 109958e1f0SArnaldo Carvalho de Melo void map_groups__init(struct map_groups *self) 1195011c60SArnaldo Carvalho de Melo { 1295011c60SArnaldo Carvalho de Melo int i; 1395011c60SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) { 1495011c60SArnaldo Carvalho de Melo self->maps[i] = RB_ROOT; 1595011c60SArnaldo Carvalho de Melo INIT_LIST_HEAD(&self->removed_maps[i]); 1695011c60SArnaldo Carvalho de Melo } 1795011c60SArnaldo Carvalho de Melo } 1895011c60SArnaldo Carvalho de Melo 1997ea1a7fSFrederic Weisbecker static struct thread *thread__new(pid_t pid) 206baa0a5aSFrederic Weisbecker { 2136479484SArnaldo Carvalho de Melo struct thread *self = zalloc(sizeof(*self)); 226baa0a5aSFrederic Weisbecker 236baa0a5aSFrederic Weisbecker if (self != NULL) { 249958e1f0SArnaldo Carvalho de Melo map_groups__init(&self->mg); 259958e1f0SArnaldo Carvalho de Melo self->pid = pid; 266baa0a5aSFrederic Weisbecker self->comm = malloc(32); 276baa0a5aSFrederic Weisbecker if (self->comm) 286baa0a5aSFrederic Weisbecker snprintf(self->comm, 32, ":%d", self->pid); 296baa0a5aSFrederic Weisbecker } 306baa0a5aSFrederic Weisbecker 316baa0a5aSFrederic Weisbecker return self; 326baa0a5aSFrederic Weisbecker } 336baa0a5aSFrederic Weisbecker 34*4385d580SDavid S. Miller static void map_groups__flush(struct map_groups *self) 35*4385d580SDavid S. Miller { 36*4385d580SDavid S. Miller int type; 37*4385d580SDavid S. Miller 38*4385d580SDavid S. Miller for (type = 0; type < MAP__NR_TYPES; type++) { 39*4385d580SDavid S. Miller struct rb_root *root = &self->maps[type]; 40*4385d580SDavid S. Miller struct rb_node *next = rb_first(root); 41*4385d580SDavid S. Miller 42*4385d580SDavid S. Miller while (next) { 43*4385d580SDavid S. Miller struct map *pos = rb_entry(next, struct map, rb_node); 44*4385d580SDavid S. Miller next = rb_next(&pos->rb_node); 45*4385d580SDavid S. Miller rb_erase(&pos->rb_node, root); 46*4385d580SDavid S. Miller /* 47*4385d580SDavid S. Miller * We may have references to this map, for 48*4385d580SDavid S. Miller * instance in some hist_entry instances, so 49*4385d580SDavid S. Miller * just move them to a separate list. 50*4385d580SDavid S. Miller */ 51*4385d580SDavid S. Miller list_add_tail(&pos->node, &self->removed_maps[pos->type]); 52*4385d580SDavid S. Miller } 53*4385d580SDavid S. Miller } 54*4385d580SDavid S. Miller } 55*4385d580SDavid S. Miller 566baa0a5aSFrederic Weisbecker int thread__set_comm(struct thread *self, const char *comm) 576baa0a5aSFrederic Weisbecker { 58*4385d580SDavid S. Miller int err; 59*4385d580SDavid S. Miller 606baa0a5aSFrederic Weisbecker if (self->comm) 616baa0a5aSFrederic Weisbecker free(self->comm); 626baa0a5aSFrederic Weisbecker self->comm = strdup(comm); 63*4385d580SDavid S. Miller err = self->comm == NULL ? -ENOMEM : 0; 64*4385d580SDavid S. Miller if (!err) { 65faa5c5c3SArnaldo Carvalho de Melo self->comm_set = true; 66*4385d580SDavid S. Miller map_groups__flush(&self->mg); 67*4385d580SDavid S. Miller } 68*4385d580SDavid S. Miller return err; 696baa0a5aSFrederic Weisbecker } 706baa0a5aSFrederic Weisbecker 71a4fb581bSFrederic Weisbecker int thread__comm_len(struct thread *self) 72a4fb581bSFrederic Weisbecker { 73a4fb581bSFrederic Weisbecker if (!self->comm_len) { 74a4fb581bSFrederic Weisbecker if (!self->comm) 75a4fb581bSFrederic Weisbecker return 0; 76a4fb581bSFrederic Weisbecker self->comm_len = strlen(self->comm); 77a4fb581bSFrederic Weisbecker } 78a4fb581bSFrederic Weisbecker 79a4fb581bSFrederic Weisbecker return self->comm_len; 80a4fb581bSFrederic Weisbecker } 81a4fb581bSFrederic Weisbecker 829958e1f0SArnaldo Carvalho de Melo static size_t __map_groups__fprintf_maps(struct map_groups *self, 8395011c60SArnaldo Carvalho de Melo enum map_type type, FILE *fp) 8495011c60SArnaldo Carvalho de Melo { 8595011c60SArnaldo Carvalho de Melo size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); 8695011c60SArnaldo Carvalho de Melo struct rb_node *nd; 8795011c60SArnaldo Carvalho de Melo 8895011c60SArnaldo Carvalho de Melo for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { 8995011c60SArnaldo Carvalho de Melo struct map *pos = rb_entry(nd, struct map, rb_node); 9095011c60SArnaldo Carvalho de Melo printed += fprintf(fp, "Map:"); 9195011c60SArnaldo Carvalho de Melo printed += map__fprintf(pos, fp); 9295011c60SArnaldo Carvalho de Melo if (verbose > 1) { 9395011c60SArnaldo Carvalho de Melo printed += dso__fprintf(pos->dso, type, fp); 9495011c60SArnaldo Carvalho de Melo printed += fprintf(fp, "--\n"); 9595011c60SArnaldo Carvalho de Melo } 961b46cddfSArnaldo Carvalho de Melo } 976baa0a5aSFrederic Weisbecker 9895011c60SArnaldo Carvalho de Melo return printed; 9995011c60SArnaldo Carvalho de Melo } 100439d473bSArnaldo Carvalho de Melo 1019958e1f0SArnaldo Carvalho de Melo size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp) 10295011c60SArnaldo Carvalho de Melo { 10395011c60SArnaldo Carvalho de Melo size_t printed = 0, i; 10495011c60SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 1059958e1f0SArnaldo Carvalho de Melo printed += __map_groups__fprintf_maps(self, i, fp); 10695011c60SArnaldo Carvalho de Melo return printed; 10795011c60SArnaldo Carvalho de Melo } 108439d473bSArnaldo Carvalho de Melo 1099958e1f0SArnaldo Carvalho de Melo static size_t __map_groups__fprintf_removed_maps(struct map_groups *self, 11095011c60SArnaldo Carvalho de Melo enum map_type type, FILE *fp) 11195011c60SArnaldo Carvalho de Melo { 11295011c60SArnaldo Carvalho de Melo struct map *pos; 11395011c60SArnaldo Carvalho de Melo size_t printed = 0; 11495011c60SArnaldo Carvalho de Melo 11595011c60SArnaldo Carvalho de Melo list_for_each_entry(pos, &self->removed_maps[type], node) { 11695011c60SArnaldo Carvalho de Melo printed += fprintf(fp, "Map:"); 11795011c60SArnaldo Carvalho de Melo printed += map__fprintf(pos, fp); 11895011c60SArnaldo Carvalho de Melo if (verbose > 1) { 11995011c60SArnaldo Carvalho de Melo printed += dso__fprintf(pos->dso, type, fp); 12095011c60SArnaldo Carvalho de Melo printed += fprintf(fp, "--\n"); 12195011c60SArnaldo Carvalho de Melo } 12295011c60SArnaldo Carvalho de Melo } 12395011c60SArnaldo Carvalho de Melo return printed; 12495011c60SArnaldo Carvalho de Melo } 12595011c60SArnaldo Carvalho de Melo 1269958e1f0SArnaldo Carvalho de Melo static size_t map_groups__fprintf_removed_maps(struct map_groups *self, FILE *fp) 12795011c60SArnaldo Carvalho de Melo { 12895011c60SArnaldo Carvalho de Melo size_t printed = 0, i; 12995011c60SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 1309958e1f0SArnaldo Carvalho de Melo printed += __map_groups__fprintf_removed_maps(self, i, fp); 13195011c60SArnaldo Carvalho de Melo return printed; 13295011c60SArnaldo Carvalho de Melo } 13395011c60SArnaldo Carvalho de Melo 1349958e1f0SArnaldo Carvalho de Melo static size_t map_groups__fprintf(struct map_groups *self, FILE *fp) 1359958e1f0SArnaldo Carvalho de Melo { 1369958e1f0SArnaldo Carvalho de Melo size_t printed = map_groups__fprintf_maps(self, fp); 1379958e1f0SArnaldo Carvalho de Melo printed += fprintf(fp, "Removed maps:\n"); 1389958e1f0SArnaldo Carvalho de Melo return printed + map_groups__fprintf_removed_maps(self, fp); 1399958e1f0SArnaldo Carvalho de Melo } 1409958e1f0SArnaldo Carvalho de Melo 14195011c60SArnaldo Carvalho de Melo static size_t thread__fprintf(struct thread *self, FILE *fp) 14295011c60SArnaldo Carvalho de Melo { 1439958e1f0SArnaldo Carvalho de Melo return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) + 1449958e1f0SArnaldo Carvalho de Melo map_groups__fprintf(&self->mg, fp); 1456baa0a5aSFrederic Weisbecker } 1466baa0a5aSFrederic Weisbecker 147b3165f41SArnaldo Carvalho de Melo struct thread *perf_session__findnew(struct perf_session *self, pid_t pid) 1486baa0a5aSFrederic Weisbecker { 149b3165f41SArnaldo Carvalho de Melo struct rb_node **p = &self->threads.rb_node; 1506baa0a5aSFrederic Weisbecker struct rb_node *parent = NULL; 1516baa0a5aSFrederic Weisbecker struct thread *th; 1526baa0a5aSFrederic Weisbecker 1536baa0a5aSFrederic Weisbecker /* 1546baa0a5aSFrederic Weisbecker * Font-end cache - PID lookups come in blocks, 1556baa0a5aSFrederic Weisbecker * so most of the time we dont have to look up 1566baa0a5aSFrederic Weisbecker * the full rbtree: 1576baa0a5aSFrederic Weisbecker */ 158b3165f41SArnaldo Carvalho de Melo if (self->last_match && self->last_match->pid == pid) 159b3165f41SArnaldo Carvalho de Melo return self->last_match; 1606baa0a5aSFrederic Weisbecker 1616baa0a5aSFrederic Weisbecker while (*p != NULL) { 1626baa0a5aSFrederic Weisbecker parent = *p; 1636baa0a5aSFrederic Weisbecker th = rb_entry(parent, struct thread, rb_node); 1646baa0a5aSFrederic Weisbecker 1656baa0a5aSFrederic Weisbecker if (th->pid == pid) { 166b3165f41SArnaldo Carvalho de Melo self->last_match = th; 1676baa0a5aSFrederic Weisbecker return th; 1686baa0a5aSFrederic Weisbecker } 1696baa0a5aSFrederic Weisbecker 1706baa0a5aSFrederic Weisbecker if (pid < th->pid) 1716baa0a5aSFrederic Weisbecker p = &(*p)->rb_left; 1726baa0a5aSFrederic Weisbecker else 1736baa0a5aSFrederic Weisbecker p = &(*p)->rb_right; 1746baa0a5aSFrederic Weisbecker } 1756baa0a5aSFrederic Weisbecker 17697ea1a7fSFrederic Weisbecker th = thread__new(pid); 1776baa0a5aSFrederic Weisbecker if (th != NULL) { 1786baa0a5aSFrederic Weisbecker rb_link_node(&th->rb_node, parent, p); 179b3165f41SArnaldo Carvalho de Melo rb_insert_color(&th->rb_node, &self->threads); 180b3165f41SArnaldo Carvalho de Melo self->last_match = th; 1816baa0a5aSFrederic Weisbecker } 1826baa0a5aSFrederic Weisbecker 1836baa0a5aSFrederic Weisbecker return th; 1846baa0a5aSFrederic Weisbecker } 1856baa0a5aSFrederic Weisbecker 1869958e1f0SArnaldo Carvalho de Melo static void map_groups__remove_overlappings(struct map_groups *self, 1879958e1f0SArnaldo Carvalho de Melo struct map *map) 1886baa0a5aSFrederic Weisbecker { 18995011c60SArnaldo Carvalho de Melo struct rb_root *root = &self->maps[map->type]; 19095011c60SArnaldo Carvalho de Melo struct rb_node *next = rb_first(root); 1916baa0a5aSFrederic Weisbecker 1921b46cddfSArnaldo Carvalho de Melo while (next) { 1931b46cddfSArnaldo Carvalho de Melo struct map *pos = rb_entry(next, struct map, rb_node); 1941b46cddfSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 1951b46cddfSArnaldo Carvalho de Melo 1961b46cddfSArnaldo Carvalho de Melo if (!map__overlap(pos, map)) 1971b46cddfSArnaldo Carvalho de Melo continue; 1981b46cddfSArnaldo Carvalho de Melo 1996e086437SFrederic Weisbecker if (verbose >= 2) { 2006beba7adSArnaldo Carvalho de Melo fputs("overlapping maps:\n", stderr); 2016beba7adSArnaldo Carvalho de Melo map__fprintf(map, stderr); 2026beba7adSArnaldo Carvalho de Melo map__fprintf(pos, stderr); 2036e086437SFrederic Weisbecker } 2046e086437SFrederic Weisbecker 20595011c60SArnaldo Carvalho de Melo rb_erase(&pos->rb_node, root); 206439d473bSArnaldo Carvalho de Melo /* 207439d473bSArnaldo Carvalho de Melo * We may have references to this map, for instance in some 208439d473bSArnaldo Carvalho de Melo * hist_entry instances, so just move them to a separate 209439d473bSArnaldo Carvalho de Melo * list. 210439d473bSArnaldo Carvalho de Melo */ 21195011c60SArnaldo Carvalho de Melo list_add_tail(&pos->node, &self->removed_maps[map->type]); 2126baa0a5aSFrederic Weisbecker } 2136e086437SFrederic Weisbecker } 2146baa0a5aSFrederic Weisbecker 2151b46cddfSArnaldo Carvalho de Melo void maps__insert(struct rb_root *maps, struct map *map) 2161b46cddfSArnaldo Carvalho de Melo { 2171b46cddfSArnaldo Carvalho de Melo struct rb_node **p = &maps->rb_node; 2181b46cddfSArnaldo Carvalho de Melo struct rb_node *parent = NULL; 2191b46cddfSArnaldo Carvalho de Melo const u64 ip = map->start; 2201b46cddfSArnaldo Carvalho de Melo struct map *m; 2211b46cddfSArnaldo Carvalho de Melo 2221b46cddfSArnaldo Carvalho de Melo while (*p != NULL) { 2231b46cddfSArnaldo Carvalho de Melo parent = *p; 2241b46cddfSArnaldo Carvalho de Melo m = rb_entry(parent, struct map, rb_node); 2251b46cddfSArnaldo Carvalho de Melo if (ip < m->start) 2261b46cddfSArnaldo Carvalho de Melo p = &(*p)->rb_left; 2271b46cddfSArnaldo Carvalho de Melo else 2281b46cddfSArnaldo Carvalho de Melo p = &(*p)->rb_right; 2291b46cddfSArnaldo Carvalho de Melo } 2301b46cddfSArnaldo Carvalho de Melo 2311b46cddfSArnaldo Carvalho de Melo rb_link_node(&map->rb_node, parent, p); 2321b46cddfSArnaldo Carvalho de Melo rb_insert_color(&map->rb_node, maps); 2331b46cddfSArnaldo Carvalho de Melo } 2341b46cddfSArnaldo Carvalho de Melo 2351b46cddfSArnaldo Carvalho de Melo struct map *maps__find(struct rb_root *maps, u64 ip) 2361b46cddfSArnaldo Carvalho de Melo { 2371b46cddfSArnaldo Carvalho de Melo struct rb_node **p = &maps->rb_node; 2381b46cddfSArnaldo Carvalho de Melo struct rb_node *parent = NULL; 2391b46cddfSArnaldo Carvalho de Melo struct map *m; 2401b46cddfSArnaldo Carvalho de Melo 2411b46cddfSArnaldo Carvalho de Melo while (*p != NULL) { 2421b46cddfSArnaldo Carvalho de Melo parent = *p; 2431b46cddfSArnaldo Carvalho de Melo m = rb_entry(parent, struct map, rb_node); 2441b46cddfSArnaldo Carvalho de Melo if (ip < m->start) 2451b46cddfSArnaldo Carvalho de Melo p = &(*p)->rb_left; 2461b46cddfSArnaldo Carvalho de Melo else if (ip > m->end) 2471b46cddfSArnaldo Carvalho de Melo p = &(*p)->rb_right; 2481b46cddfSArnaldo Carvalho de Melo else 2491b46cddfSArnaldo Carvalho de Melo return m; 2501b46cddfSArnaldo Carvalho de Melo } 2511b46cddfSArnaldo Carvalho de Melo 2521b46cddfSArnaldo Carvalho de Melo return NULL; 2531b46cddfSArnaldo Carvalho de Melo } 2541b46cddfSArnaldo Carvalho de Melo 2551b46cddfSArnaldo Carvalho de Melo void thread__insert_map(struct thread *self, struct map *map) 2561b46cddfSArnaldo Carvalho de Melo { 2579958e1f0SArnaldo Carvalho de Melo map_groups__remove_overlappings(&self->mg, map); 2589958e1f0SArnaldo Carvalho de Melo map_groups__insert(&self->mg, map); 25995011c60SArnaldo Carvalho de Melo } 26095011c60SArnaldo Carvalho de Melo 2619958e1f0SArnaldo Carvalho de Melo /* 2629958e1f0SArnaldo Carvalho de Melo * XXX This should not really _copy_ te maps, but refcount them. 2639958e1f0SArnaldo Carvalho de Melo */ 2649958e1f0SArnaldo Carvalho de Melo static int map_groups__clone(struct map_groups *self, 2659958e1f0SArnaldo Carvalho de Melo struct map_groups *parent, enum map_type type) 26695011c60SArnaldo Carvalho de Melo { 26795011c60SArnaldo Carvalho de Melo struct rb_node *nd; 26895011c60SArnaldo Carvalho de Melo for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) { 26995011c60SArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 27095011c60SArnaldo Carvalho de Melo struct map *new = map__clone(map); 27195011c60SArnaldo Carvalho de Melo if (new == NULL) 27295011c60SArnaldo Carvalho de Melo return -ENOMEM; 2739958e1f0SArnaldo Carvalho de Melo map_groups__insert(self, new); 27495011c60SArnaldo Carvalho de Melo } 27595011c60SArnaldo Carvalho de Melo return 0; 2766baa0a5aSFrederic Weisbecker } 2776baa0a5aSFrederic Weisbecker 2786baa0a5aSFrederic Weisbecker int thread__fork(struct thread *self, struct thread *parent) 2796baa0a5aSFrederic Weisbecker { 28095011c60SArnaldo Carvalho de Melo int i; 2816baa0a5aSFrederic Weisbecker 282faa5c5c3SArnaldo Carvalho de Melo if (parent->comm_set) { 2836baa0a5aSFrederic Weisbecker if (self->comm) 2846baa0a5aSFrederic Weisbecker free(self->comm); 2856baa0a5aSFrederic Weisbecker self->comm = strdup(parent->comm); 2866baa0a5aSFrederic Weisbecker if (!self->comm) 2876baa0a5aSFrederic Weisbecker return -ENOMEM; 288faa5c5c3SArnaldo Carvalho de Melo self->comm_set = true; 289faa5c5c3SArnaldo Carvalho de Melo } 2906baa0a5aSFrederic Weisbecker 29195011c60SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 2929958e1f0SArnaldo Carvalho de Melo if (map_groups__clone(&self->mg, &parent->mg, i) < 0) 2936baa0a5aSFrederic Weisbecker return -ENOMEM; 2946baa0a5aSFrederic Weisbecker return 0; 2956baa0a5aSFrederic Weisbecker } 2966baa0a5aSFrederic Weisbecker 297b3165f41SArnaldo Carvalho de Melo size_t perf_session__fprintf(struct perf_session *self, FILE *fp) 2986baa0a5aSFrederic Weisbecker { 2996baa0a5aSFrederic Weisbecker size_t ret = 0; 3006baa0a5aSFrederic Weisbecker struct rb_node *nd; 3016baa0a5aSFrederic Weisbecker 302b3165f41SArnaldo Carvalho de Melo for (nd = rb_first(&self->threads); nd; nd = rb_next(nd)) { 3036baa0a5aSFrederic Weisbecker struct thread *pos = rb_entry(nd, struct thread, rb_node); 3046baa0a5aSFrederic Weisbecker 3056baa0a5aSFrederic Weisbecker ret += thread__fprintf(pos, fp); 3066baa0a5aSFrederic Weisbecker } 3076baa0a5aSFrederic Weisbecker 3086baa0a5aSFrederic Weisbecker return ret; 3096baa0a5aSFrederic Weisbecker } 3101ed091c4SArnaldo Carvalho de Melo 3119958e1f0SArnaldo Carvalho de Melo struct symbol *map_groups__find_symbol(struct map_groups *self, 3121ed091c4SArnaldo Carvalho de Melo enum map_type type, u64 addr, 3131ed091c4SArnaldo Carvalho de Melo symbol_filter_t filter) 3141ed091c4SArnaldo Carvalho de Melo { 3159958e1f0SArnaldo Carvalho de Melo struct map *map = map_groups__find(self, type, addr); 3161ed091c4SArnaldo Carvalho de Melo 3171ed091c4SArnaldo Carvalho de Melo if (map != NULL) 3189de89fe7SArnaldo Carvalho de Melo return map__find_symbol(map, map->map_ip(map, addr), filter); 3191ed091c4SArnaldo Carvalho de Melo 3201ed091c4SArnaldo Carvalho de Melo return NULL; 3211ed091c4SArnaldo Carvalho de Melo } 322