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

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

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

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

	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;
}

42 43 44 45 46 47 48 49 50 51 52
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;
}

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

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

64 65 66 67 68 69 70 71
	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");
		}
72
	}
73

74 75 76
	return printed;
}

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

85 86
static size_t __map_groups__fprintf_removed_maps(struct map_groups *self,
						 enum map_type type, FILE *fp)
87 88 89 90 91 92 93 94 95 96 97 98 99 100
{
	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;
}
101

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

110
static size_t map_groups__fprintf(struct map_groups *self, FILE *fp)
111
{
112
	size_t printed = map_groups__fprintf_maps(self, fp);
113
	printed += fprintf(fp, "Removed maps:\n");
114 115 116 117 118 119 120
	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);
121 122
}

123
struct thread *perf_session__findnew(struct perf_session *self, pid_t pid)
124
{
125
	struct rb_node **p = &self->threads.rb_node;
126 127 128 129 130 131 132 133
	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:
	 */
134 135
	if (self->last_match && self->last_match->pid == pid)
		return self->last_match;
136 137 138 139 140 141

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

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

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

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

	return th;
}

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

	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) {
176 177 178
			fputs("overlapping maps:\n", stderr);
			map__fprintf(map, stderr);
			map__fprintf(pos, stderr);
179 180
		}

181
		rb_erase(&pos->rb_node, root);
182 183 184 185 186
		/*
		 * We may have references to this map, for instance in some
		 * hist_entry instances, so just move them to a separate
		 * list.
		 */
187
		list_add_tail(&pos->node, &self->removed_maps[map->type]);
188
	}
189 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
}

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;
}
230

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

237 238 239 240 241
/*
 * 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)
242
{
243
	struct rb_node *nd;
244 245 246 247 248
	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;
249
		map_groups__insert(self, new);
250 251 252 253 254 255 256
	}
	return 0;
}

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

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

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

270
size_t perf_session__fprintf(struct perf_session *self, FILE *fp)
271 272 273 274
{
	size_t ret = 0;
	struct rb_node *nd;

275
	for (nd = rb_first(&self->threads); nd; nd = rb_next(nd)) {
276 277 278 279 280 281 282
		struct thread *pos = rb_entry(nd, struct thread, rb_node);

		ret += thread__fprintf(pos, fp);
	}

	return ret;
}
283

284 285 286
struct symbol *map_groups__find_symbol(struct map_groups *self,
				       enum map_type type, u64 addr,
				       symbol_filter_t filter)
287
{
288
	struct map *map = map_groups__find(self, type, addr);
289 290

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

	return NULL;
}