16baa0a5aSFrederic Weisbecker #include "../perf.h" 26baa0a5aSFrederic Weisbecker #include <stdlib.h> 36baa0a5aSFrederic Weisbecker #include <stdio.h> 46baa0a5aSFrederic Weisbecker #include <string.h> 56baa0a5aSFrederic Weisbecker #include "thread.h" 66baa0a5aSFrederic Weisbecker #include "util.h" 76e086437SFrederic Weisbecker #include "debug.h" 86baa0a5aSFrederic Weisbecker 9d5b889f2SArnaldo Carvalho de Melo static struct rb_root threads; 10d5b889f2SArnaldo Carvalho de Melo static struct thread *last_match; 11d5b889f2SArnaldo Carvalho de Melo 1297ea1a7fSFrederic Weisbecker static struct thread *thread__new(pid_t pid) 136baa0a5aSFrederic Weisbecker { 140ec04e16SIngo Molnar struct thread *self = calloc(1, sizeof(*self)); 156baa0a5aSFrederic Weisbecker 166baa0a5aSFrederic Weisbecker if (self != NULL) { 176baa0a5aSFrederic Weisbecker self->pid = pid; 186baa0a5aSFrederic Weisbecker self->comm = malloc(32); 196baa0a5aSFrederic Weisbecker if (self->comm) 206baa0a5aSFrederic Weisbecker snprintf(self->comm, 32, ":%d", self->pid); 211b46cddfSArnaldo Carvalho de Melo self->maps = RB_ROOT; 22439d473bSArnaldo Carvalho de Melo INIT_LIST_HEAD(&self->removed_maps); 236baa0a5aSFrederic Weisbecker } 246baa0a5aSFrederic Weisbecker 256baa0a5aSFrederic Weisbecker return self; 266baa0a5aSFrederic Weisbecker } 276baa0a5aSFrederic Weisbecker 286baa0a5aSFrederic Weisbecker int thread__set_comm(struct thread *self, const char *comm) 296baa0a5aSFrederic Weisbecker { 306baa0a5aSFrederic Weisbecker if (self->comm) 316baa0a5aSFrederic Weisbecker free(self->comm); 326baa0a5aSFrederic Weisbecker self->comm = strdup(comm); 336baa0a5aSFrederic Weisbecker return self->comm ? 0 : -ENOMEM; 346baa0a5aSFrederic Weisbecker } 356baa0a5aSFrederic Weisbecker 36*a4fb581bSFrederic Weisbecker int thread__comm_len(struct thread *self) 37*a4fb581bSFrederic Weisbecker { 38*a4fb581bSFrederic Weisbecker if (!self->comm_len) { 39*a4fb581bSFrederic Weisbecker if (!self->comm) 40*a4fb581bSFrederic Weisbecker return 0; 41*a4fb581bSFrederic Weisbecker self->comm_len = strlen(self->comm); 42*a4fb581bSFrederic Weisbecker } 43*a4fb581bSFrederic Weisbecker 44*a4fb581bSFrederic Weisbecker return self->comm_len; 45*a4fb581bSFrederic Weisbecker } 46*a4fb581bSFrederic Weisbecker 476baa0a5aSFrederic Weisbecker static size_t thread__fprintf(struct thread *self, FILE *fp) 486baa0a5aSFrederic Weisbecker { 491b46cddfSArnaldo Carvalho de Melo struct rb_node *nd; 50439d473bSArnaldo Carvalho de Melo struct map *pos; 51439d473bSArnaldo Carvalho de Melo size_t ret = fprintf(fp, "Thread %d %s\nCurrent maps:\n", 52439d473bSArnaldo Carvalho de Melo self->pid, self->comm); 536baa0a5aSFrederic Weisbecker 541b46cddfSArnaldo Carvalho de Melo for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) { 55439d473bSArnaldo Carvalho de Melo pos = rb_entry(nd, struct map, rb_node); 566baa0a5aSFrederic Weisbecker ret += map__fprintf(pos, fp); 571b46cddfSArnaldo Carvalho de Melo } 586baa0a5aSFrederic Weisbecker 59439d473bSArnaldo Carvalho de Melo ret = fprintf(fp, "Removed maps:\n"); 60439d473bSArnaldo Carvalho de Melo 61439d473bSArnaldo Carvalho de Melo list_for_each_entry(pos, &self->removed_maps, node) 62439d473bSArnaldo Carvalho de Melo ret += map__fprintf(pos, fp); 63439d473bSArnaldo Carvalho de Melo 646baa0a5aSFrederic Weisbecker return ret; 656baa0a5aSFrederic Weisbecker } 666baa0a5aSFrederic Weisbecker 67d5b889f2SArnaldo Carvalho de Melo struct thread *threads__findnew(pid_t pid) 686baa0a5aSFrederic Weisbecker { 69d5b889f2SArnaldo Carvalho de Melo struct rb_node **p = &threads.rb_node; 706baa0a5aSFrederic Weisbecker struct rb_node *parent = NULL; 716baa0a5aSFrederic Weisbecker struct thread *th; 726baa0a5aSFrederic Weisbecker 736baa0a5aSFrederic Weisbecker /* 746baa0a5aSFrederic Weisbecker * Font-end cache - PID lookups come in blocks, 756baa0a5aSFrederic Weisbecker * so most of the time we dont have to look up 766baa0a5aSFrederic Weisbecker * the full rbtree: 776baa0a5aSFrederic Weisbecker */ 78d5b889f2SArnaldo Carvalho de Melo if (last_match && last_match->pid == pid) 79d5b889f2SArnaldo Carvalho de Melo return last_match; 806baa0a5aSFrederic Weisbecker 816baa0a5aSFrederic Weisbecker while (*p != NULL) { 826baa0a5aSFrederic Weisbecker parent = *p; 836baa0a5aSFrederic Weisbecker th = rb_entry(parent, struct thread, rb_node); 846baa0a5aSFrederic Weisbecker 856baa0a5aSFrederic Weisbecker if (th->pid == pid) { 86d5b889f2SArnaldo Carvalho de Melo last_match = th; 876baa0a5aSFrederic Weisbecker return th; 886baa0a5aSFrederic Weisbecker } 896baa0a5aSFrederic Weisbecker 906baa0a5aSFrederic Weisbecker if (pid < th->pid) 916baa0a5aSFrederic Weisbecker p = &(*p)->rb_left; 926baa0a5aSFrederic Weisbecker else 936baa0a5aSFrederic Weisbecker p = &(*p)->rb_right; 946baa0a5aSFrederic Weisbecker } 956baa0a5aSFrederic Weisbecker 9697ea1a7fSFrederic Weisbecker th = thread__new(pid); 976baa0a5aSFrederic Weisbecker if (th != NULL) { 986baa0a5aSFrederic Weisbecker rb_link_node(&th->rb_node, parent, p); 99d5b889f2SArnaldo Carvalho de Melo rb_insert_color(&th->rb_node, &threads); 100d5b889f2SArnaldo Carvalho de Melo last_match = th; 1016baa0a5aSFrederic Weisbecker } 1026baa0a5aSFrederic Weisbecker 1036baa0a5aSFrederic Weisbecker return th; 1046baa0a5aSFrederic Weisbecker } 1056baa0a5aSFrederic Weisbecker 106d5b889f2SArnaldo Carvalho de Melo struct thread *register_idle_thread(void) 1075b447a6aSFrederic Weisbecker { 108d5b889f2SArnaldo Carvalho de Melo struct thread *thread = threads__findnew(0); 1095b447a6aSFrederic Weisbecker 11080ed0987SIngo Molnar if (!thread || thread__set_comm(thread, "swapper")) { 1115b447a6aSFrederic Weisbecker fprintf(stderr, "problem inserting idle task.\n"); 1125b447a6aSFrederic Weisbecker exit(-1); 1135b447a6aSFrederic Weisbecker } 1145b447a6aSFrederic Weisbecker 1155b447a6aSFrederic Weisbecker return thread; 1165b447a6aSFrederic Weisbecker } 1175b447a6aSFrederic Weisbecker 1181b46cddfSArnaldo Carvalho de Melo static void thread__remove_overlappings(struct thread *self, struct map *map) 1196baa0a5aSFrederic Weisbecker { 1201b46cddfSArnaldo Carvalho de Melo struct rb_node *next = rb_first(&self->maps); 1216baa0a5aSFrederic Weisbecker 1221b46cddfSArnaldo Carvalho de Melo while (next) { 1231b46cddfSArnaldo Carvalho de Melo struct map *pos = rb_entry(next, struct map, rb_node); 1241b46cddfSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 1251b46cddfSArnaldo Carvalho de Melo 1261b46cddfSArnaldo Carvalho de Melo if (!map__overlap(pos, map)) 1271b46cddfSArnaldo Carvalho de Melo continue; 1281b46cddfSArnaldo Carvalho de Melo 1296e086437SFrederic Weisbecker if (verbose >= 2) { 1306e086437SFrederic Weisbecker printf("overlapping maps:\n"); 1316e086437SFrederic Weisbecker map__fprintf(map, stdout); 1326e086437SFrederic Weisbecker map__fprintf(pos, stdout); 1336e086437SFrederic Weisbecker } 1346e086437SFrederic Weisbecker 1351b46cddfSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, &self->maps); 136439d473bSArnaldo Carvalho de Melo /* 137439d473bSArnaldo Carvalho de Melo * We may have references to this map, for instance in some 138439d473bSArnaldo Carvalho de Melo * hist_entry instances, so just move them to a separate 139439d473bSArnaldo Carvalho de Melo * list. 140439d473bSArnaldo Carvalho de Melo */ 141439d473bSArnaldo Carvalho de Melo list_add_tail(&pos->node, &self->removed_maps); 1426baa0a5aSFrederic Weisbecker } 1436e086437SFrederic Weisbecker } 1446baa0a5aSFrederic Weisbecker 1451b46cddfSArnaldo Carvalho de Melo void maps__insert(struct rb_root *maps, struct map *map) 1461b46cddfSArnaldo Carvalho de Melo { 1471b46cddfSArnaldo Carvalho de Melo struct rb_node **p = &maps->rb_node; 1481b46cddfSArnaldo Carvalho de Melo struct rb_node *parent = NULL; 1491b46cddfSArnaldo Carvalho de Melo const u64 ip = map->start; 1501b46cddfSArnaldo Carvalho de Melo struct map *m; 1511b46cddfSArnaldo Carvalho de Melo 1521b46cddfSArnaldo Carvalho de Melo while (*p != NULL) { 1531b46cddfSArnaldo Carvalho de Melo parent = *p; 1541b46cddfSArnaldo Carvalho de Melo m = rb_entry(parent, struct map, rb_node); 1551b46cddfSArnaldo Carvalho de Melo if (ip < m->start) 1561b46cddfSArnaldo Carvalho de Melo p = &(*p)->rb_left; 1571b46cddfSArnaldo Carvalho de Melo else 1581b46cddfSArnaldo Carvalho de Melo p = &(*p)->rb_right; 1591b46cddfSArnaldo Carvalho de Melo } 1601b46cddfSArnaldo Carvalho de Melo 1611b46cddfSArnaldo Carvalho de Melo rb_link_node(&map->rb_node, parent, p); 1621b46cddfSArnaldo Carvalho de Melo rb_insert_color(&map->rb_node, maps); 1631b46cddfSArnaldo Carvalho de Melo } 1641b46cddfSArnaldo Carvalho de Melo 1651b46cddfSArnaldo Carvalho de Melo struct map *maps__find(struct rb_root *maps, u64 ip) 1661b46cddfSArnaldo Carvalho de Melo { 1671b46cddfSArnaldo Carvalho de Melo struct rb_node **p = &maps->rb_node; 1681b46cddfSArnaldo Carvalho de Melo struct rb_node *parent = NULL; 1691b46cddfSArnaldo Carvalho de Melo struct map *m; 1701b46cddfSArnaldo Carvalho de Melo 1711b46cddfSArnaldo Carvalho de Melo while (*p != NULL) { 1721b46cddfSArnaldo Carvalho de Melo parent = *p; 1731b46cddfSArnaldo Carvalho de Melo m = rb_entry(parent, struct map, rb_node); 1741b46cddfSArnaldo Carvalho de Melo if (ip < m->start) 1751b46cddfSArnaldo Carvalho de Melo p = &(*p)->rb_left; 1761b46cddfSArnaldo Carvalho de Melo else if (ip > m->end) 1771b46cddfSArnaldo Carvalho de Melo p = &(*p)->rb_right; 1781b46cddfSArnaldo Carvalho de Melo else 1791b46cddfSArnaldo Carvalho de Melo return m; 1801b46cddfSArnaldo Carvalho de Melo } 1811b46cddfSArnaldo Carvalho de Melo 1821b46cddfSArnaldo Carvalho de Melo return NULL; 1831b46cddfSArnaldo Carvalho de Melo } 1841b46cddfSArnaldo Carvalho de Melo 1851b46cddfSArnaldo Carvalho de Melo void thread__insert_map(struct thread *self, struct map *map) 1861b46cddfSArnaldo Carvalho de Melo { 1871b46cddfSArnaldo Carvalho de Melo thread__remove_overlappings(self, map); 1881b46cddfSArnaldo Carvalho de Melo maps__insert(&self->maps, map); 1896baa0a5aSFrederic Weisbecker } 1906baa0a5aSFrederic Weisbecker 1916baa0a5aSFrederic Weisbecker int thread__fork(struct thread *self, struct thread *parent) 1926baa0a5aSFrederic Weisbecker { 1931b46cddfSArnaldo Carvalho de Melo struct rb_node *nd; 1946baa0a5aSFrederic Weisbecker 1956baa0a5aSFrederic Weisbecker if (self->comm) 1966baa0a5aSFrederic Weisbecker free(self->comm); 1976baa0a5aSFrederic Weisbecker self->comm = strdup(parent->comm); 1986baa0a5aSFrederic Weisbecker if (!self->comm) 1996baa0a5aSFrederic Weisbecker return -ENOMEM; 2006baa0a5aSFrederic Weisbecker 2011b46cddfSArnaldo Carvalho de Melo for (nd = rb_first(&parent->maps); nd; nd = rb_next(nd)) { 2021b46cddfSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 2036baa0a5aSFrederic Weisbecker struct map *new = map__clone(map); 2046baa0a5aSFrederic Weisbecker if (!new) 2056baa0a5aSFrederic Weisbecker return -ENOMEM; 2066baa0a5aSFrederic Weisbecker thread__insert_map(self, new); 2076baa0a5aSFrederic Weisbecker } 2086baa0a5aSFrederic Weisbecker 2096baa0a5aSFrederic Weisbecker return 0; 2106baa0a5aSFrederic Weisbecker } 2116baa0a5aSFrederic Weisbecker 212d5b889f2SArnaldo Carvalho de Melo size_t threads__fprintf(FILE *fp) 2136baa0a5aSFrederic Weisbecker { 2146baa0a5aSFrederic Weisbecker size_t ret = 0; 2156baa0a5aSFrederic Weisbecker struct rb_node *nd; 2166baa0a5aSFrederic Weisbecker 217d5b889f2SArnaldo Carvalho de Melo for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { 2186baa0a5aSFrederic Weisbecker struct thread *pos = rb_entry(nd, struct thread, rb_node); 2196baa0a5aSFrederic Weisbecker 2206baa0a5aSFrederic Weisbecker ret += thread__fprintf(pos, fp); 2216baa0a5aSFrederic Weisbecker } 2226baa0a5aSFrederic Weisbecker 2236baa0a5aSFrederic Weisbecker return ret; 2246baa0a5aSFrederic Weisbecker } 225