thread.c 6.4 KB
Newer Older
1 2 3 4 5 6
#include "../perf.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "thread.h"
#include "util.h"
7
#include "debug.h"
8

9 10 11
static struct rb_root threads;
static struct thread *last_match;

12
void map_groups__init(struct map_groups *self)
13 14 15 16 17 18 19 20
{
	int i;
	for (i = 0; i < MAP__NR_TYPES; ++i) {
		self->maps[i] = RB_ROOT;
		INIT_LIST_HEAD(&self->removed_maps[i]);
	}
}

21
static struct thread *thread__new(pid_t pid)
22
{
23
	struct thread *self = zalloc(sizeof(*self));
24 25

	if (self != NULL) {
26 27
		map_groups__init(&self->mg);
		self->pid = pid;
28 29 30
		self->comm = malloc(32);
		if (self->comm)
			snprintf(self->comm, 32, ":%d", self->pid);
31 32 33 34 35 36 37 38 39 40 41 42 43
	}

	return self;
}

int thread__set_comm(struct thread *self, const char *comm)
{
	if (self->comm)
		free(self->comm);
	self->comm = strdup(comm);
	return self->comm ? 0 : -ENOMEM;
}

44 45 46 47 48 49 50 51 52 53 54
int thread__comm_len(struct thread *self)
{
	if (!self->comm_len) {
		if (!self->comm)
			return 0;
		self->comm_len = strlen(self->comm);
	}

	return self->comm_len;
}

55 56
static const char *map_type__name[MAP__NR_TYPES] = {
	[MAP__FUNCTION] = "Functions",
57
	[MAP__VARIABLE] = "Variables",
58 59
};

60 61
static size_t __map_groups__fprintf_maps(struct map_groups *self,
					 enum map_type type, FILE *fp)
62
{
63
	size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
64
	struct rb_node *nd;
65

66 67 68 69 70 71 72 73
	for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
		struct map *pos = rb_entry(nd, struct map, rb_node);
		printed += fprintf(fp, "Map:");
		printed += map__fprintf(pos, fp);
		if (verbose > 1) {
			printed += dso__fprintf(pos->dso, type, fp);
			printed += fprintf(fp, "--\n");
		}
74
	}
75

76 77 78
	return printed;
}

79
size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp)
80 81 82
{
	size_t printed = 0, i;
	for (i = 0; i < MAP__NR_TYPES; ++i)
83
		printed += __map_groups__fprintf_maps(self, i, fp);
84 85
	return printed;
}
86

87 88
static size_t __map_groups__fprintf_removed_maps(struct map_groups *self,
						 enum map_type type, FILE *fp)
89 90 91 92 93 94 95 96 97 98 99 100 101 102
{
	struct map *pos;
	size_t printed = 0;

	list_for_each_entry(pos, &self->removed_maps[type], node) {
		printed += fprintf(fp, "Map:");
		printed += map__fprintf(pos, fp);
		if (verbose > 1) {
			printed += dso__fprintf(pos->dso, type, fp);
			printed += fprintf(fp, "--\n");
		}
	}
	return printed;
}
103

104
static size_t map_groups__fprintf_removed_maps(struct map_groups *self, FILE *fp)
105 106 107
{
	size_t printed = 0, i;
	for (i = 0; i < MAP__NR_TYPES; ++i)
108
		printed += __map_groups__fprintf_removed_maps(self, i, fp);
109 110 111
	return printed;
}

112
static size_t map_groups__fprintf(struct map_groups *self, FILE *fp)
113
{
114
	size_t printed = map_groups__fprintf_maps(self, fp);
115
	printed += fprintf(fp, "Removed maps:\n");
116 117 118 119 120 121 122
	return printed + map_groups__fprintf_removed_maps(self, fp);
}

static size_t thread__fprintf(struct thread *self, FILE *fp)
{
	return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) +
	       map_groups__fprintf(&self->mg, fp);
123 124
}

125
struct thread *threads__findnew(pid_t pid)
126
{
127
	struct rb_node **p = &threads.rb_node;
128 129 130 131 132 133 134 135
	struct rb_node *parent = NULL;
	struct thread *th;

	/*
	 * Font-end cache - PID lookups come in blocks,
	 * so most of the time we dont have to look up
	 * the full rbtree:
	 */
136 137
	if (last_match && last_match->pid == pid)
		return last_match;
138 139 140 141 142 143

	while (*p != NULL) {
		parent = *p;
		th = rb_entry(parent, struct thread, rb_node);

		if (th->pid == pid) {
144
			last_match = th;
145 146 147 148 149 150 151 152 153
			return th;
		}

		if (pid < th->pid)
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
	}

154
	th = thread__new(pid);
155 156
	if (th != NULL) {
		rb_link_node(&th->rb_node, parent, p);
157 158
		rb_insert_color(&th->rb_node, &threads);
		last_match = th;
159 160 161 162 163
	}

	return th;
}

164 165
static void map_groups__remove_overlappings(struct map_groups *self,
					    struct map *map)
166
{
167 168
	struct rb_root *root = &self->maps[map->type];
	struct rb_node *next = rb_first(root);
169 170 171 172 173 174 175 176 177

	while (next) {
		struct map *pos = rb_entry(next, struct map, rb_node);
		next = rb_next(&pos->rb_node);

		if (!map__overlap(pos, map))
			continue;

		if (verbose >= 2) {
178 179 180
			fputs("overlapping maps:\n", stderr);
			map__fprintf(map, stderr);
			map__fprintf(pos, stderr);
181 182
		}

183
		rb_erase(&pos->rb_node, root);
184 185 186 187 188
		/*
		 * We may have references to this map, for instance in some
		 * hist_entry instances, so just move them to a separate
		 * list.
		 */
189
		list_add_tail(&pos->node, &self->removed_maps[map->type]);
190
	}
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
}

void maps__insert(struct rb_root *maps, struct map *map)
{
	struct rb_node **p = &maps->rb_node;
	struct rb_node *parent = NULL;
	const u64 ip = map->start;
	struct map *m;

	while (*p != NULL) {
		parent = *p;
		m = rb_entry(parent, struct map, rb_node);
		if (ip < m->start)
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
	}

	rb_link_node(&map->rb_node, parent, p);
	rb_insert_color(&map->rb_node, maps);
}

struct map *maps__find(struct rb_root *maps, u64 ip)
{
	struct rb_node **p = &maps->rb_node;
	struct rb_node *parent = NULL;
	struct map *m;

	while (*p != NULL) {
		parent = *p;
		m = rb_entry(parent, struct map, rb_node);
		if (ip < m->start)
			p = &(*p)->rb_left;
		else if (ip > m->end)
			p = &(*p)->rb_right;
		else
			return m;
	}

	return NULL;
}
232

233 234
void thread__insert_map(struct thread *self, struct map *map)
{
235 236
	map_groups__remove_overlappings(&self->mg, map);
	map_groups__insert(&self->mg, map);
237 238
}

239 240 241 242 243
/*
 * XXX This should not really _copy_ te maps, but refcount them.
 */
static int map_groups__clone(struct map_groups *self,
			     struct map_groups *parent, enum map_type type)
244
{
245
	struct rb_node *nd;
246 247 248 249 250
	for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) {
		struct map *map = rb_entry(nd, struct map, rb_node);
		struct map *new = map__clone(map);
		if (new == NULL)
			return -ENOMEM;
251
		map_groups__insert(self, new);
252 253 254 255 256 257 258
	}
	return 0;
}

int thread__fork(struct thread *self, struct thread *parent)
{
	int i;
259 260 261 262 263 264 265

	if (self->comm)
		free(self->comm);
	self->comm = strdup(parent->comm);
	if (!self->comm)
		return -ENOMEM;

266
	for (i = 0; i < MAP__NR_TYPES; ++i)
267
		if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
268 269 270 271
			return -ENOMEM;
	return 0;
}

272
size_t threads__fprintf(FILE *fp)
273 274 275 276
{
	size_t ret = 0;
	struct rb_node *nd;

277
	for (nd = rb_first(&threads); nd; nd = rb_next(nd)) {
278 279 280 281 282 283 284
		struct thread *pos = rb_entry(nd, struct thread, rb_node);

		ret += thread__fprintf(pos, fp);
	}

	return ret;
}
285

286 287 288
struct symbol *map_groups__find_symbol(struct map_groups *self,
				       enum map_type type, u64 addr,
				       symbol_filter_t filter)
289
{
290
	struct map *map = map_groups__find(self, type, addr);
291 292 293 294 295 296

	if (map != NULL)
		return map__find_symbol(map, map->map_ip(map, addr), filter);

	return NULL;
}