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 9*d5b889f2SArnaldo Carvalho de Melo static struct rb_root threads; 10*d5b889f2SArnaldo Carvalho de Melo static struct thread *last_match; 11*d5b889f2SArnaldo 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 366baa0a5aSFrederic Weisbecker static size_t thread__fprintf(struct thread *self, FILE *fp) 376baa0a5aSFrederic Weisbecker { 381b46cddfSArnaldo Carvalho de Melo struct rb_node *nd; 39439d473bSArnaldo Carvalho de Melo struct map *pos; 40439d473bSArnaldo Carvalho de Melo size_t ret = fprintf(fp, "Thread %d %s\nCurrent maps:\n", 41439d473bSArnaldo Carvalho de Melo self->pid, self->comm); 426baa0a5aSFrederic Weisbecker 431b46cddfSArnaldo Carvalho de Melo for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) { 44439d473bSArnaldo Carvalho de Melo pos = rb_entry(nd, struct map, rb_node); 456baa0a5aSFrederic Weisbecker ret += map__fprintf(pos, fp); 461b46cddfSArnaldo Carvalho de Melo } 476baa0a5aSFrederic Weisbecker 48439d473bSArnaldo Carvalho de Melo ret = fprintf(fp, "Removed maps:\n"); 49439d473bSArnaldo Carvalho de Melo 50439d473bSArnaldo Carvalho de Melo list_for_each_entry(pos, &self->removed_maps, node) 51439d473bSArnaldo Carvalho de Melo ret += map__fprintf(pos, fp); 52439d473bSArnaldo Carvalho de Melo 536baa0a5aSFrederic Weisbecker return ret; 546baa0a5aSFrederic Weisbecker } 556baa0a5aSFrederic Weisbecker 56*d5b889f2SArnaldo Carvalho de Melo struct thread *threads__findnew(pid_t pid) 576baa0a5aSFrederic Weisbecker { 58*d5b889f2SArnaldo Carvalho de Melo struct rb_node **p = &threads.rb_node; 596baa0a5aSFrederic Weisbecker struct rb_node *parent = NULL; 606baa0a5aSFrederic Weisbecker struct thread *th; 616baa0a5aSFrederic Weisbecker 626baa0a5aSFrederic Weisbecker /* 636baa0a5aSFrederic Weisbecker * Font-end cache - PID lookups come in blocks, 646baa0a5aSFrederic Weisbecker * so most of the time we dont have to look up 656baa0a5aSFrederic Weisbecker * the full rbtree: 666baa0a5aSFrederic Weisbecker */ 67*d5b889f2SArnaldo Carvalho de Melo if (last_match && last_match->pid == pid) 68*d5b889f2SArnaldo Carvalho de Melo return last_match; 696baa0a5aSFrederic Weisbecker 706baa0a5aSFrederic Weisbecker while (*p != NULL) { 716baa0a5aSFrederic Weisbecker parent = *p; 726baa0a5aSFrederic Weisbecker th = rb_entry(parent, struct thread, rb_node); 736baa0a5aSFrederic Weisbecker 746baa0a5aSFrederic Weisbecker if (th->pid == pid) { 75*d5b889f2SArnaldo Carvalho de Melo last_match = th; 766baa0a5aSFrederic Weisbecker return th; 776baa0a5aSFrederic Weisbecker } 786baa0a5aSFrederic Weisbecker 796baa0a5aSFrederic Weisbecker if (pid < th->pid) 806baa0a5aSFrederic Weisbecker p = &(*p)->rb_left; 816baa0a5aSFrederic Weisbecker else 826baa0a5aSFrederic Weisbecker p = &(*p)->rb_right; 836baa0a5aSFrederic Weisbecker } 846baa0a5aSFrederic Weisbecker 8597ea1a7fSFrederic Weisbecker th = thread__new(pid); 866baa0a5aSFrederic Weisbecker if (th != NULL) { 876baa0a5aSFrederic Weisbecker rb_link_node(&th->rb_node, parent, p); 88*d5b889f2SArnaldo Carvalho de Melo rb_insert_color(&th->rb_node, &threads); 89*d5b889f2SArnaldo Carvalho de Melo last_match = th; 906baa0a5aSFrederic Weisbecker } 916baa0a5aSFrederic Weisbecker 926baa0a5aSFrederic Weisbecker return th; 936baa0a5aSFrederic Weisbecker } 946baa0a5aSFrederic Weisbecker 95*d5b889f2SArnaldo Carvalho de Melo struct thread *register_idle_thread(void) 965b447a6aSFrederic Weisbecker { 97*d5b889f2SArnaldo Carvalho de Melo struct thread *thread = threads__findnew(0); 985b447a6aSFrederic Weisbecker 9980ed0987SIngo Molnar if (!thread || thread__set_comm(thread, "swapper")) { 1005b447a6aSFrederic Weisbecker fprintf(stderr, "problem inserting idle task.\n"); 1015b447a6aSFrederic Weisbecker exit(-1); 1025b447a6aSFrederic Weisbecker } 1035b447a6aSFrederic Weisbecker 1045b447a6aSFrederic Weisbecker return thread; 1055b447a6aSFrederic Weisbecker } 1065b447a6aSFrederic Weisbecker 1071b46cddfSArnaldo Carvalho de Melo static void thread__remove_overlappings(struct thread *self, struct map *map) 1086baa0a5aSFrederic Weisbecker { 1091b46cddfSArnaldo Carvalho de Melo struct rb_node *next = rb_first(&self->maps); 1106baa0a5aSFrederic Weisbecker 1111b46cddfSArnaldo Carvalho de Melo while (next) { 1121b46cddfSArnaldo Carvalho de Melo struct map *pos = rb_entry(next, struct map, rb_node); 1131b46cddfSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 1141b46cddfSArnaldo Carvalho de Melo 1151b46cddfSArnaldo Carvalho de Melo if (!map__overlap(pos, map)) 1161b46cddfSArnaldo Carvalho de Melo continue; 1171b46cddfSArnaldo Carvalho de Melo 1186e086437SFrederic Weisbecker if (verbose >= 2) { 1196e086437SFrederic Weisbecker printf("overlapping maps:\n"); 1206e086437SFrederic Weisbecker map__fprintf(map, stdout); 1216e086437SFrederic Weisbecker map__fprintf(pos, stdout); 1226e086437SFrederic Weisbecker } 1236e086437SFrederic Weisbecker 1241b46cddfSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, &self->maps); 125439d473bSArnaldo Carvalho de Melo /* 126439d473bSArnaldo Carvalho de Melo * We may have references to this map, for instance in some 127439d473bSArnaldo Carvalho de Melo * hist_entry instances, so just move them to a separate 128439d473bSArnaldo Carvalho de Melo * list. 129439d473bSArnaldo Carvalho de Melo */ 130439d473bSArnaldo Carvalho de Melo list_add_tail(&pos->node, &self->removed_maps); 1316baa0a5aSFrederic Weisbecker } 1326e086437SFrederic Weisbecker } 1336baa0a5aSFrederic Weisbecker 1341b46cddfSArnaldo Carvalho de Melo void maps__insert(struct rb_root *maps, struct map *map) 1351b46cddfSArnaldo Carvalho de Melo { 1361b46cddfSArnaldo Carvalho de Melo struct rb_node **p = &maps->rb_node; 1371b46cddfSArnaldo Carvalho de Melo struct rb_node *parent = NULL; 1381b46cddfSArnaldo Carvalho de Melo const u64 ip = map->start; 1391b46cddfSArnaldo Carvalho de Melo struct map *m; 1401b46cddfSArnaldo Carvalho de Melo 1411b46cddfSArnaldo Carvalho de Melo while (*p != NULL) { 1421b46cddfSArnaldo Carvalho de Melo parent = *p; 1431b46cddfSArnaldo Carvalho de Melo m = rb_entry(parent, struct map, rb_node); 1441b46cddfSArnaldo Carvalho de Melo if (ip < m->start) 1451b46cddfSArnaldo Carvalho de Melo p = &(*p)->rb_left; 1461b46cddfSArnaldo Carvalho de Melo else 1471b46cddfSArnaldo Carvalho de Melo p = &(*p)->rb_right; 1481b46cddfSArnaldo Carvalho de Melo } 1491b46cddfSArnaldo Carvalho de Melo 1501b46cddfSArnaldo Carvalho de Melo rb_link_node(&map->rb_node, parent, p); 1511b46cddfSArnaldo Carvalho de Melo rb_insert_color(&map->rb_node, maps); 1521b46cddfSArnaldo Carvalho de Melo } 1531b46cddfSArnaldo Carvalho de Melo 1541b46cddfSArnaldo Carvalho de Melo struct map *maps__find(struct rb_root *maps, u64 ip) 1551b46cddfSArnaldo Carvalho de Melo { 1561b46cddfSArnaldo Carvalho de Melo struct rb_node **p = &maps->rb_node; 1571b46cddfSArnaldo Carvalho de Melo struct rb_node *parent = NULL; 1581b46cddfSArnaldo Carvalho de Melo struct map *m; 1591b46cddfSArnaldo Carvalho de Melo 1601b46cddfSArnaldo Carvalho de Melo while (*p != NULL) { 1611b46cddfSArnaldo Carvalho de Melo parent = *p; 1621b46cddfSArnaldo Carvalho de Melo m = rb_entry(parent, struct map, rb_node); 1631b46cddfSArnaldo Carvalho de Melo if (ip < m->start) 1641b46cddfSArnaldo Carvalho de Melo p = &(*p)->rb_left; 1651b46cddfSArnaldo Carvalho de Melo else if (ip > m->end) 1661b46cddfSArnaldo Carvalho de Melo p = &(*p)->rb_right; 1671b46cddfSArnaldo Carvalho de Melo else 1681b46cddfSArnaldo Carvalho de Melo return m; 1691b46cddfSArnaldo Carvalho de Melo } 1701b46cddfSArnaldo Carvalho de Melo 1711b46cddfSArnaldo Carvalho de Melo return NULL; 1721b46cddfSArnaldo Carvalho de Melo } 1731b46cddfSArnaldo Carvalho de Melo 1741b46cddfSArnaldo Carvalho de Melo void thread__insert_map(struct thread *self, struct map *map) 1751b46cddfSArnaldo Carvalho de Melo { 1761b46cddfSArnaldo Carvalho de Melo thread__remove_overlappings(self, map); 1771b46cddfSArnaldo Carvalho de Melo maps__insert(&self->maps, map); 1786baa0a5aSFrederic Weisbecker } 1796baa0a5aSFrederic Weisbecker 1806baa0a5aSFrederic Weisbecker int thread__fork(struct thread *self, struct thread *parent) 1816baa0a5aSFrederic Weisbecker { 1821b46cddfSArnaldo Carvalho de Melo struct rb_node *nd; 1836baa0a5aSFrederic Weisbecker 1846baa0a5aSFrederic Weisbecker if (self->comm) 1856baa0a5aSFrederic Weisbecker free(self->comm); 1866baa0a5aSFrederic Weisbecker self->comm = strdup(parent->comm); 1876baa0a5aSFrederic Weisbecker if (!self->comm) 1886baa0a5aSFrederic Weisbecker return -ENOMEM; 1896baa0a5aSFrederic Weisbecker 1901b46cddfSArnaldo Carvalho de Melo for (nd = rb_first(&parent->maps); nd; nd = rb_next(nd)) { 1911b46cddfSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 1926baa0a5aSFrederic Weisbecker struct map *new = map__clone(map); 1936baa0a5aSFrederic Weisbecker if (!new) 1946baa0a5aSFrederic Weisbecker return -ENOMEM; 1956baa0a5aSFrederic Weisbecker thread__insert_map(self, new); 1966baa0a5aSFrederic Weisbecker } 1976baa0a5aSFrederic Weisbecker 1986baa0a5aSFrederic Weisbecker return 0; 1996baa0a5aSFrederic Weisbecker } 2006baa0a5aSFrederic Weisbecker 201*d5b889f2SArnaldo Carvalho de Melo size_t threads__fprintf(FILE *fp) 2026baa0a5aSFrederic Weisbecker { 2036baa0a5aSFrederic Weisbecker size_t ret = 0; 2046baa0a5aSFrederic Weisbecker struct rb_node *nd; 2056baa0a5aSFrederic Weisbecker 206*d5b889f2SArnaldo Carvalho de Melo for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { 2076baa0a5aSFrederic Weisbecker struct thread *pos = rb_entry(nd, struct thread, rb_node); 2086baa0a5aSFrederic Weisbecker 2096baa0a5aSFrederic Weisbecker ret += thread__fprintf(pos, fp); 2106baa0a5aSFrederic Weisbecker } 2116baa0a5aSFrederic Weisbecker 2126baa0a5aSFrederic Weisbecker return ret; 2136baa0a5aSFrederic Weisbecker } 214