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); 18*1b46cddfSArnaldo Carvalho de Melo self->maps = RB_ROOT; 196baa0a5aSFrederic Weisbecker } 206baa0a5aSFrederic Weisbecker 216baa0a5aSFrederic Weisbecker return self; 226baa0a5aSFrederic Weisbecker } 236baa0a5aSFrederic Weisbecker 246baa0a5aSFrederic Weisbecker int thread__set_comm(struct thread *self, const char *comm) 256baa0a5aSFrederic Weisbecker { 266baa0a5aSFrederic Weisbecker if (self->comm) 276baa0a5aSFrederic Weisbecker free(self->comm); 286baa0a5aSFrederic Weisbecker self->comm = strdup(comm); 296baa0a5aSFrederic Weisbecker return self->comm ? 0 : -ENOMEM; 306baa0a5aSFrederic Weisbecker } 316baa0a5aSFrederic Weisbecker 326baa0a5aSFrederic Weisbecker static size_t thread__fprintf(struct thread *self, FILE *fp) 336baa0a5aSFrederic Weisbecker { 34*1b46cddfSArnaldo Carvalho de Melo struct rb_node *nd; 356baa0a5aSFrederic Weisbecker size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); 366baa0a5aSFrederic Weisbecker 37*1b46cddfSArnaldo Carvalho de Melo for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) { 38*1b46cddfSArnaldo Carvalho de Melo struct map *pos = rb_entry(nd, struct map, rb_node); 396baa0a5aSFrederic Weisbecker ret += map__fprintf(pos, fp); 40*1b46cddfSArnaldo Carvalho de Melo } 416baa0a5aSFrederic Weisbecker 426baa0a5aSFrederic Weisbecker return ret; 436baa0a5aSFrederic Weisbecker } 446baa0a5aSFrederic Weisbecker 456baa0a5aSFrederic Weisbecker struct thread * 466baa0a5aSFrederic Weisbecker threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match) 476baa0a5aSFrederic Weisbecker { 486baa0a5aSFrederic Weisbecker struct rb_node **p = &threads->rb_node; 496baa0a5aSFrederic Weisbecker struct rb_node *parent = NULL; 506baa0a5aSFrederic Weisbecker struct thread *th; 516baa0a5aSFrederic Weisbecker 526baa0a5aSFrederic Weisbecker /* 536baa0a5aSFrederic Weisbecker * Font-end cache - PID lookups come in blocks, 546baa0a5aSFrederic Weisbecker * so most of the time we dont have to look up 556baa0a5aSFrederic Weisbecker * the full rbtree: 566baa0a5aSFrederic Weisbecker */ 576baa0a5aSFrederic Weisbecker if (*last_match && (*last_match)->pid == pid) 586baa0a5aSFrederic Weisbecker return *last_match; 596baa0a5aSFrederic Weisbecker 606baa0a5aSFrederic Weisbecker while (*p != NULL) { 616baa0a5aSFrederic Weisbecker parent = *p; 626baa0a5aSFrederic Weisbecker th = rb_entry(parent, struct thread, rb_node); 636baa0a5aSFrederic Weisbecker 646baa0a5aSFrederic Weisbecker if (th->pid == pid) { 656baa0a5aSFrederic Weisbecker *last_match = th; 666baa0a5aSFrederic Weisbecker return th; 676baa0a5aSFrederic Weisbecker } 686baa0a5aSFrederic Weisbecker 696baa0a5aSFrederic Weisbecker if (pid < th->pid) 706baa0a5aSFrederic Weisbecker p = &(*p)->rb_left; 716baa0a5aSFrederic Weisbecker else 726baa0a5aSFrederic Weisbecker p = &(*p)->rb_right; 736baa0a5aSFrederic Weisbecker } 746baa0a5aSFrederic Weisbecker 756baa0a5aSFrederic Weisbecker th = thread__new(pid); 766baa0a5aSFrederic Weisbecker if (th != NULL) { 776baa0a5aSFrederic Weisbecker rb_link_node(&th->rb_node, parent, p); 786baa0a5aSFrederic Weisbecker rb_insert_color(&th->rb_node, threads); 796baa0a5aSFrederic Weisbecker *last_match = th; 806baa0a5aSFrederic Weisbecker } 816baa0a5aSFrederic Weisbecker 826baa0a5aSFrederic Weisbecker return th; 836baa0a5aSFrederic Weisbecker } 846baa0a5aSFrederic Weisbecker 855b447a6aSFrederic Weisbecker struct thread * 865b447a6aSFrederic Weisbecker register_idle_thread(struct rb_root *threads, struct thread **last_match) 875b447a6aSFrederic Weisbecker { 885b447a6aSFrederic Weisbecker struct thread *thread = threads__findnew(0, threads, last_match); 895b447a6aSFrederic Weisbecker 9080ed0987SIngo Molnar if (!thread || thread__set_comm(thread, "swapper")) { 915b447a6aSFrederic Weisbecker fprintf(stderr, "problem inserting idle task.\n"); 925b447a6aSFrederic Weisbecker exit(-1); 935b447a6aSFrederic Weisbecker } 945b447a6aSFrederic Weisbecker 955b447a6aSFrederic Weisbecker return thread; 965b447a6aSFrederic Weisbecker } 975b447a6aSFrederic Weisbecker 98*1b46cddfSArnaldo Carvalho de Melo static void thread__remove_overlappings(struct thread *self, struct map *map) 996baa0a5aSFrederic Weisbecker { 100*1b46cddfSArnaldo Carvalho de Melo struct rb_node *next = rb_first(&self->maps); 1016baa0a5aSFrederic Weisbecker 102*1b46cddfSArnaldo Carvalho de Melo while (next) { 103*1b46cddfSArnaldo Carvalho de Melo struct map *pos = rb_entry(next, struct map, rb_node); 104*1b46cddfSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 105*1b46cddfSArnaldo Carvalho de Melo 106*1b46cddfSArnaldo Carvalho de Melo if (!map__overlap(pos, map)) 107*1b46cddfSArnaldo Carvalho de Melo continue; 108*1b46cddfSArnaldo Carvalho de Melo 1096e086437SFrederic Weisbecker if (verbose >= 2) { 1106e086437SFrederic Weisbecker printf("overlapping maps:\n"); 1116e086437SFrederic Weisbecker map__fprintf(map, stdout); 1126e086437SFrederic Weisbecker map__fprintf(pos, stdout); 1136e086437SFrederic Weisbecker } 1146e086437SFrederic Weisbecker 1156e086437SFrederic Weisbecker if (map->start <= pos->start && map->end > pos->start) 1166e086437SFrederic Weisbecker pos->start = map->end; 1176e086437SFrederic Weisbecker 1186e086437SFrederic Weisbecker if (map->end >= pos->end && map->start < pos->end) 1196e086437SFrederic Weisbecker pos->end = map->start; 1206e086437SFrederic Weisbecker 1216e086437SFrederic Weisbecker if (verbose >= 2) { 1226e086437SFrederic Weisbecker printf("after collision:\n"); 1236e086437SFrederic Weisbecker map__fprintf(pos, stdout); 1246e086437SFrederic Weisbecker } 1256e086437SFrederic Weisbecker 1266e086437SFrederic Weisbecker if (pos->start >= pos->end) { 127*1b46cddfSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, &self->maps); 1286baa0a5aSFrederic Weisbecker free(pos); 1296baa0a5aSFrederic Weisbecker } 1306baa0a5aSFrederic Weisbecker } 1316e086437SFrederic Weisbecker } 1326baa0a5aSFrederic Weisbecker 133*1b46cddfSArnaldo Carvalho de Melo void maps__insert(struct rb_root *maps, struct map *map) 134*1b46cddfSArnaldo Carvalho de Melo { 135*1b46cddfSArnaldo Carvalho de Melo struct rb_node **p = &maps->rb_node; 136*1b46cddfSArnaldo Carvalho de Melo struct rb_node *parent = NULL; 137*1b46cddfSArnaldo Carvalho de Melo const u64 ip = map->start; 138*1b46cddfSArnaldo Carvalho de Melo struct map *m; 139*1b46cddfSArnaldo Carvalho de Melo 140*1b46cddfSArnaldo Carvalho de Melo while (*p != NULL) { 141*1b46cddfSArnaldo Carvalho de Melo parent = *p; 142*1b46cddfSArnaldo Carvalho de Melo m = rb_entry(parent, struct map, rb_node); 143*1b46cddfSArnaldo Carvalho de Melo if (ip < m->start) 144*1b46cddfSArnaldo Carvalho de Melo p = &(*p)->rb_left; 145*1b46cddfSArnaldo Carvalho de Melo else 146*1b46cddfSArnaldo Carvalho de Melo p = &(*p)->rb_right; 147*1b46cddfSArnaldo Carvalho de Melo } 148*1b46cddfSArnaldo Carvalho de Melo 149*1b46cddfSArnaldo Carvalho de Melo rb_link_node(&map->rb_node, parent, p); 150*1b46cddfSArnaldo Carvalho de Melo rb_insert_color(&map->rb_node, maps); 151*1b46cddfSArnaldo Carvalho de Melo } 152*1b46cddfSArnaldo Carvalho de Melo 153*1b46cddfSArnaldo Carvalho de Melo struct map *maps__find(struct rb_root *maps, u64 ip) 154*1b46cddfSArnaldo Carvalho de Melo { 155*1b46cddfSArnaldo Carvalho de Melo struct rb_node **p = &maps->rb_node; 156*1b46cddfSArnaldo Carvalho de Melo struct rb_node *parent = NULL; 157*1b46cddfSArnaldo Carvalho de Melo struct map *m; 158*1b46cddfSArnaldo Carvalho de Melo 159*1b46cddfSArnaldo Carvalho de Melo while (*p != NULL) { 160*1b46cddfSArnaldo Carvalho de Melo parent = *p; 161*1b46cddfSArnaldo Carvalho de Melo m = rb_entry(parent, struct map, rb_node); 162*1b46cddfSArnaldo Carvalho de Melo if (ip < m->start) 163*1b46cddfSArnaldo Carvalho de Melo p = &(*p)->rb_left; 164*1b46cddfSArnaldo Carvalho de Melo else if (ip > m->end) 165*1b46cddfSArnaldo Carvalho de Melo p = &(*p)->rb_right; 166*1b46cddfSArnaldo Carvalho de Melo else 167*1b46cddfSArnaldo Carvalho de Melo return m; 168*1b46cddfSArnaldo Carvalho de Melo } 169*1b46cddfSArnaldo Carvalho de Melo 170*1b46cddfSArnaldo Carvalho de Melo return NULL; 171*1b46cddfSArnaldo Carvalho de Melo } 172*1b46cddfSArnaldo Carvalho de Melo 173*1b46cddfSArnaldo Carvalho de Melo void thread__insert_map(struct thread *self, struct map *map) 174*1b46cddfSArnaldo Carvalho de Melo { 175*1b46cddfSArnaldo Carvalho de Melo thread__remove_overlappings(self, map); 176*1b46cddfSArnaldo 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 { 181*1b46cddfSArnaldo 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 189*1b46cddfSArnaldo Carvalho de Melo for (nd = rb_first(&parent->maps); nd; nd = rb_next(nd)) { 190*1b46cddfSArnaldo 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