xref: /openbmc/linux/tools/perf/util/thread.c (revision e8e0929d)
1 #include "../perf.h"
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include "thread.h"
6 #include "util.h"
7 #include "debug.h"
8 
9 static struct thread *thread__new(pid_t pid)
10 {
11 	struct thread *self = calloc(1, sizeof(*self));
12 
13 	if (self != NULL) {
14 		self->pid = pid;
15 		self->comm = malloc(32);
16 		if (self->comm)
17 			snprintf(self->comm, 32, ":%d", self->pid);
18 		INIT_LIST_HEAD(&self->maps);
19 	}
20 
21 	return self;
22 }
23 
24 int thread__set_comm(struct thread *self, const char *comm)
25 {
26 	if (self->comm)
27 		free(self->comm);
28 	self->comm = strdup(comm);
29 	return self->comm ? 0 : -ENOMEM;
30 }
31 
32 static size_t thread__fprintf(struct thread *self, FILE *fp)
33 {
34 	struct map *pos;
35 	size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm);
36 
37 	list_for_each_entry(pos, &self->maps, node)
38 		ret += map__fprintf(pos, fp);
39 
40 	return ret;
41 }
42 
43 struct thread *
44 threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
45 {
46 	struct rb_node **p = &threads->rb_node;
47 	struct rb_node *parent = NULL;
48 	struct thread *th;
49 
50 	/*
51 	 * Font-end cache - PID lookups come in blocks,
52 	 * so most of the time we dont have to look up
53 	 * the full rbtree:
54 	 */
55 	if (*last_match && (*last_match)->pid == pid)
56 		return *last_match;
57 
58 	while (*p != NULL) {
59 		parent = *p;
60 		th = rb_entry(parent, struct thread, rb_node);
61 
62 		if (th->pid == pid) {
63 			*last_match = th;
64 			return th;
65 		}
66 
67 		if (pid < th->pid)
68 			p = &(*p)->rb_left;
69 		else
70 			p = &(*p)->rb_right;
71 	}
72 
73 	th = thread__new(pid);
74 	if (th != NULL) {
75 		rb_link_node(&th->rb_node, parent, p);
76 		rb_insert_color(&th->rb_node, threads);
77 		*last_match = th;
78 	}
79 
80 	return th;
81 }
82 
83 struct thread *
84 register_idle_thread(struct rb_root *threads, struct thread **last_match)
85 {
86 	struct thread *thread = threads__findnew(0, threads, last_match);
87 
88 	if (!thread || thread__set_comm(thread, "swapper")) {
89 		fprintf(stderr, "problem inserting idle task.\n");
90 		exit(-1);
91 	}
92 
93 	return thread;
94 }
95 
96 void thread__insert_map(struct thread *self, struct map *map)
97 {
98 	struct map *pos, *tmp;
99 
100 	list_for_each_entry_safe(pos, tmp, &self->maps, node) {
101 		if (map__overlap(pos, map)) {
102 			if (verbose >= 2) {
103 				printf("overlapping maps:\n");
104 				map__fprintf(map, stdout);
105 				map__fprintf(pos, stdout);
106 			}
107 
108 			if (map->start <= pos->start && map->end > pos->start)
109 				pos->start = map->end;
110 
111 			if (map->end >= pos->end && map->start < pos->end)
112 				pos->end = map->start;
113 
114 			if (verbose >= 2) {
115 				printf("after collision:\n");
116 				map__fprintf(pos, stdout);
117 			}
118 
119 			if (pos->start >= pos->end) {
120 				list_del_init(&pos->node);
121 				free(pos);
122 			}
123 		}
124 	}
125 
126 	list_add_tail(&map->node, &self->maps);
127 }
128 
129 int thread__fork(struct thread *self, struct thread *parent)
130 {
131 	struct map *map;
132 
133 	if (self->comm)
134 		free(self->comm);
135 	self->comm = strdup(parent->comm);
136 	if (!self->comm)
137 		return -ENOMEM;
138 
139 	list_for_each_entry(map, &parent->maps, node) {
140 		struct map *new = map__clone(map);
141 		if (!new)
142 			return -ENOMEM;
143 		thread__insert_map(self, new);
144 	}
145 
146 	return 0;
147 }
148 
149 struct map *thread__find_map(struct thread *self, u64 ip)
150 {
151 	struct map *pos;
152 
153 	if (self == NULL)
154 		return NULL;
155 
156 	list_for_each_entry(pos, &self->maps, node)
157 		if (ip >= pos->start && ip <= pos->end)
158 			return pos;
159 
160 	return NULL;
161 }
162 
163 size_t threads__fprintf(FILE *fp, struct rb_root *threads)
164 {
165 	size_t ret = 0;
166 	struct rb_node *nd;
167 
168 	for (nd = rb_first(threads); nd; nd = rb_next(nd)) {
169 		struct thread *pos = rb_entry(nd, struct thread, rb_node);
170 
171 		ret += thread__fprintf(pos, fp);
172 	}
173 
174 	return ret;
175 }
176