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 96baa0a5aSFrederic Weisbecker static struct thread *thread__new(pid_t pid) 106baa0a5aSFrederic Weisbecker { 110ec04e16SIngo Molnar struct thread *self = calloc(1, sizeof(*self)); 126baa0a5aSFrederic Weisbecker 136baa0a5aSFrederic Weisbecker if (self != NULL) { 146baa0a5aSFrederic Weisbecker self->pid = pid; 156baa0a5aSFrederic Weisbecker self->comm = malloc(32); 166baa0a5aSFrederic Weisbecker if (self->comm) 176baa0a5aSFrederic Weisbecker snprintf(self->comm, 32, ":%d", self->pid); 181b46cddfSArnaldo Carvalho de Melo self->maps = RB_ROOT; 19*439d473bSArnaldo Carvalho de Melo INIT_LIST_HEAD(&self->removed_maps); 206baa0a5aSFrederic Weisbecker } 216baa0a5aSFrederic Weisbecker 226baa0a5aSFrederic Weisbecker return self; 236baa0a5aSFrederic Weisbecker } 246baa0a5aSFrederic Weisbecker 256baa0a5aSFrederic Weisbecker int thread__set_comm(struct thread *self, const char *comm) 266baa0a5aSFrederic Weisbecker { 276baa0a5aSFrederic Weisbecker if (self->comm) 286baa0a5aSFrederic Weisbecker free(self->comm); 296baa0a5aSFrederic Weisbecker self->comm = strdup(comm); 306baa0a5aSFrederic Weisbecker return self->comm ? 0 : -ENOMEM; 316baa0a5aSFrederic Weisbecker } 326baa0a5aSFrederic Weisbecker 336baa0a5aSFrederic Weisbecker static size_t thread__fprintf(struct thread *self, FILE *fp) 346baa0a5aSFrederic Weisbecker { 351b46cddfSArnaldo Carvalho de Melo struct rb_node *nd; 36*439d473bSArnaldo Carvalho de Melo struct map *pos; 37*439d473bSArnaldo Carvalho de Melo size_t ret = fprintf(fp, "Thread %d %s\nCurrent maps:\n", 38*439d473bSArnaldo Carvalho de Melo self->pid, self->comm); 396baa0a5aSFrederic Weisbecker 401b46cddfSArnaldo Carvalho de Melo for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) { 41*439d473bSArnaldo Carvalho de Melo pos = rb_entry(nd, struct map, rb_node); 426baa0a5aSFrederic Weisbecker ret += map__fprintf(pos, fp); 431b46cddfSArnaldo Carvalho de Melo } 446baa0a5aSFrederic Weisbecker 45*439d473bSArnaldo Carvalho de Melo ret = fprintf(fp, "Removed maps:\n"); 46*439d473bSArnaldo Carvalho de Melo 47*439d473bSArnaldo Carvalho de Melo list_for_each_entry(pos, &self->removed_maps, node) 48*439d473bSArnaldo Carvalho de Melo ret += map__fprintf(pos, fp); 49*439d473bSArnaldo Carvalho de Melo 506baa0a5aSFrederic Weisbecker return ret; 516baa0a5aSFrederic Weisbecker } 526baa0a5aSFrederic Weisbecker 536baa0a5aSFrederic Weisbecker struct thread * 546baa0a5aSFrederic Weisbecker threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match) 556baa0a5aSFrederic Weisbecker { 566baa0a5aSFrederic Weisbecker struct rb_node **p = &threads->rb_node; 576baa0a5aSFrederic Weisbecker struct rb_node *parent = NULL; 586baa0a5aSFrederic Weisbecker struct thread *th; 596baa0a5aSFrederic Weisbecker 606baa0a5aSFrederic Weisbecker /* 616baa0a5aSFrederic Weisbecker * Font-end cache - PID lookups come in blocks, 626baa0a5aSFrederic Weisbecker * so most of the time we dont have to look up 636baa0a5aSFrederic Weisbecker * the full rbtree: 646baa0a5aSFrederic Weisbecker */ 656baa0a5aSFrederic Weisbecker if (*last_match && (*last_match)->pid == pid) 666baa0a5aSFrederic Weisbecker return *last_match; 676baa0a5aSFrederic Weisbecker 686baa0a5aSFrederic Weisbecker while (*p != NULL) { 696baa0a5aSFrederic Weisbecker parent = *p; 706baa0a5aSFrederic Weisbecker th = rb_entry(parent, struct thread, rb_node); 716baa0a5aSFrederic Weisbecker 726baa0a5aSFrederic Weisbecker if (th->pid == pid) { 736baa0a5aSFrederic Weisbecker *last_match = th; 746baa0a5aSFrederic Weisbecker return th; 756baa0a5aSFrederic Weisbecker } 766baa0a5aSFrederic Weisbecker 776baa0a5aSFrederic Weisbecker if (pid < th->pid) 786baa0a5aSFrederic Weisbecker p = &(*p)->rb_left; 796baa0a5aSFrederic Weisbecker else 806baa0a5aSFrederic Weisbecker p = &(*p)->rb_right; 816baa0a5aSFrederic Weisbecker } 826baa0a5aSFrederic Weisbecker 836baa0a5aSFrederic Weisbecker th = thread__new(pid); 846baa0a5aSFrederic Weisbecker if (th != NULL) { 856baa0a5aSFrederic Weisbecker rb_link_node(&th->rb_node, parent, p); 866baa0a5aSFrederic Weisbecker rb_insert_color(&th->rb_node, threads); 876baa0a5aSFrederic Weisbecker *last_match = th; 886baa0a5aSFrederic Weisbecker } 896baa0a5aSFrederic Weisbecker 906baa0a5aSFrederic Weisbecker return th; 916baa0a5aSFrederic Weisbecker } 926baa0a5aSFrederic Weisbecker 935b447a6aSFrederic Weisbecker struct thread * 945b447a6aSFrederic Weisbecker register_idle_thread(struct rb_root *threads, struct thread **last_match) 955b447a6aSFrederic Weisbecker { 965b447a6aSFrederic Weisbecker struct thread *thread = threads__findnew(0, threads, last_match); 975b447a6aSFrederic Weisbecker 9880ed0987SIngo Molnar if (!thread || thread__set_comm(thread, "swapper")) { 995b447a6aSFrederic Weisbecker fprintf(stderr, "problem inserting idle task.\n"); 1005b447a6aSFrederic Weisbecker exit(-1); 1015b447a6aSFrederic Weisbecker } 1025b447a6aSFrederic Weisbecker 1035b447a6aSFrederic Weisbecker return thread; 1045b447a6aSFrederic Weisbecker } 1055b447a6aSFrederic Weisbecker 1061b46cddfSArnaldo Carvalho de Melo static void thread__remove_overlappings(struct thread *self, struct map *map) 1076baa0a5aSFrederic Weisbecker { 1081b46cddfSArnaldo Carvalho de Melo struct rb_node *next = rb_first(&self->maps); 1096baa0a5aSFrederic Weisbecker 1101b46cddfSArnaldo Carvalho de Melo while (next) { 1111b46cddfSArnaldo Carvalho de Melo struct map *pos = rb_entry(next, struct map, rb_node); 1121b46cddfSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 1131b46cddfSArnaldo Carvalho de Melo 1141b46cddfSArnaldo Carvalho de Melo if (!map__overlap(pos, map)) 1151b46cddfSArnaldo Carvalho de Melo continue; 1161b46cddfSArnaldo Carvalho de Melo 1176e086437SFrederic Weisbecker if (verbose >= 2) { 1186e086437SFrederic Weisbecker printf("overlapping maps:\n"); 1196e086437SFrederic Weisbecker map__fprintf(map, stdout); 1206e086437SFrederic Weisbecker map__fprintf(pos, stdout); 1216e086437SFrederic Weisbecker } 1226e086437SFrederic Weisbecker 1231b46cddfSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, &self->maps); 124*439d473bSArnaldo Carvalho de Melo /* 125*439d473bSArnaldo Carvalho de Melo * We may have references to this map, for instance in some 126*439d473bSArnaldo Carvalho de Melo * hist_entry instances, so just move them to a separate 127*439d473bSArnaldo Carvalho de Melo * list. 128*439d473bSArnaldo Carvalho de Melo */ 129*439d473bSArnaldo Carvalho de Melo list_add_tail(&pos->node, &self->removed_maps); 1306baa0a5aSFrederic Weisbecker } 1316e086437SFrederic Weisbecker } 1326baa0a5aSFrederic Weisbecker 1331b46cddfSArnaldo Carvalho de Melo void maps__insert(struct rb_root *maps, struct map *map) 1341b46cddfSArnaldo Carvalho de Melo { 1351b46cddfSArnaldo Carvalho de Melo struct rb_node **p = &maps->rb_node; 1361b46cddfSArnaldo Carvalho de Melo struct rb_node *parent = NULL; 1371b46cddfSArnaldo Carvalho de Melo const u64 ip = map->start; 1381b46cddfSArnaldo Carvalho de Melo struct map *m; 1391b46cddfSArnaldo Carvalho de Melo 1401b46cddfSArnaldo Carvalho de Melo while (*p != NULL) { 1411b46cddfSArnaldo Carvalho de Melo parent = *p; 1421b46cddfSArnaldo Carvalho de Melo m = rb_entry(parent, struct map, rb_node); 1431b46cddfSArnaldo Carvalho de Melo if (ip < m->start) 1441b46cddfSArnaldo Carvalho de Melo p = &(*p)->rb_left; 1451b46cddfSArnaldo Carvalho de Melo else 1461b46cddfSArnaldo Carvalho de Melo p = &(*p)->rb_right; 1471b46cddfSArnaldo Carvalho de Melo } 1481b46cddfSArnaldo Carvalho de Melo 1491b46cddfSArnaldo Carvalho de Melo rb_link_node(&map->rb_node, parent, p); 1501b46cddfSArnaldo Carvalho de Melo rb_insert_color(&map->rb_node, maps); 1511b46cddfSArnaldo Carvalho de Melo } 1521b46cddfSArnaldo Carvalho de Melo 1531b46cddfSArnaldo Carvalho de Melo struct map *maps__find(struct rb_root *maps, u64 ip) 1541b46cddfSArnaldo Carvalho de Melo { 1551b46cddfSArnaldo Carvalho de Melo struct rb_node **p = &maps->rb_node; 1561b46cddfSArnaldo Carvalho de Melo struct rb_node *parent = NULL; 1571b46cddfSArnaldo Carvalho de Melo struct map *m; 1581b46cddfSArnaldo Carvalho de Melo 1591b46cddfSArnaldo Carvalho de Melo while (*p != NULL) { 1601b46cddfSArnaldo Carvalho de Melo parent = *p; 1611b46cddfSArnaldo Carvalho de Melo m = rb_entry(parent, struct map, rb_node); 1621b46cddfSArnaldo Carvalho de Melo if (ip < m->start) 1631b46cddfSArnaldo Carvalho de Melo p = &(*p)->rb_left; 1641b46cddfSArnaldo Carvalho de Melo else if (ip > m->end) 1651b46cddfSArnaldo Carvalho de Melo p = &(*p)->rb_right; 1661b46cddfSArnaldo Carvalho de Melo else 1671b46cddfSArnaldo Carvalho de Melo return m; 1681b46cddfSArnaldo Carvalho de Melo } 1691b46cddfSArnaldo Carvalho de Melo 1701b46cddfSArnaldo Carvalho de Melo return NULL; 1711b46cddfSArnaldo Carvalho de Melo } 1721b46cddfSArnaldo Carvalho de Melo 1731b46cddfSArnaldo Carvalho de Melo void thread__insert_map(struct thread *self, struct map *map) 1741b46cddfSArnaldo Carvalho de Melo { 1751b46cddfSArnaldo Carvalho de Melo thread__remove_overlappings(self, map); 1761b46cddfSArnaldo Carvalho de Melo maps__insert(&self->maps, map); 1776baa0a5aSFrederic Weisbecker } 1786baa0a5aSFrederic Weisbecker 1796baa0a5aSFrederic Weisbecker int thread__fork(struct thread *self, struct thread *parent) 1806baa0a5aSFrederic Weisbecker { 1811b46cddfSArnaldo Carvalho de Melo struct rb_node *nd; 1826baa0a5aSFrederic Weisbecker 1836baa0a5aSFrederic Weisbecker if (self->comm) 1846baa0a5aSFrederic Weisbecker free(self->comm); 1856baa0a5aSFrederic Weisbecker self->comm = strdup(parent->comm); 1866baa0a5aSFrederic Weisbecker if (!self->comm) 1876baa0a5aSFrederic Weisbecker return -ENOMEM; 1886baa0a5aSFrederic Weisbecker 1891b46cddfSArnaldo Carvalho de Melo for (nd = rb_first(&parent->maps); nd; nd = rb_next(nd)) { 1901b46cddfSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 1916baa0a5aSFrederic Weisbecker struct map *new = map__clone(map); 1926baa0a5aSFrederic Weisbecker if (!new) 1936baa0a5aSFrederic Weisbecker return -ENOMEM; 1946baa0a5aSFrederic Weisbecker thread__insert_map(self, new); 1956baa0a5aSFrederic Weisbecker } 1966baa0a5aSFrederic Weisbecker 1976baa0a5aSFrederic Weisbecker return 0; 1986baa0a5aSFrederic Weisbecker } 1996baa0a5aSFrederic Weisbecker 2006baa0a5aSFrederic Weisbecker size_t threads__fprintf(FILE *fp, struct rb_root *threads) 2016baa0a5aSFrederic Weisbecker { 2026baa0a5aSFrederic Weisbecker size_t ret = 0; 2036baa0a5aSFrederic Weisbecker struct rb_node *nd; 2046baa0a5aSFrederic Weisbecker 2056baa0a5aSFrederic Weisbecker for (nd = rb_first(threads); nd; nd = rb_next(nd)) { 2066baa0a5aSFrederic Weisbecker struct thread *pos = rb_entry(nd, struct thread, rb_node); 2076baa0a5aSFrederic Weisbecker 2086baa0a5aSFrederic Weisbecker ret += thread__fprintf(pos, fp); 2096baa0a5aSFrederic Weisbecker } 2106baa0a5aSFrederic Weisbecker 2116baa0a5aSFrederic Weisbecker return ret; 2126baa0a5aSFrederic Weisbecker } 213