xref: /openbmc/linux/tools/perf/util/thread.c (revision d6d901c23a9c4c7361aa901b5b2dda69703dd5e0)
16baa0a5aSFrederic Weisbecker #include "../perf.h"
26baa0a5aSFrederic Weisbecker #include <stdlib.h>
36baa0a5aSFrederic Weisbecker #include <stdio.h>
46baa0a5aSFrederic Weisbecker #include <string.h>
5b3165f41SArnaldo Carvalho de Melo #include "session.h"
66baa0a5aSFrederic Weisbecker #include "thread.h"
76baa0a5aSFrederic Weisbecker #include "util.h"
86e086437SFrederic Weisbecker #include "debug.h"
96baa0a5aSFrederic Weisbecker 
10*d6d901c2SZhang, Yanmin int find_all_tid(int pid, pid_t ** all_tid)
11*d6d901c2SZhang, Yanmin {
12*d6d901c2SZhang, Yanmin 	char name[256];
13*d6d901c2SZhang, Yanmin 	int items;
14*d6d901c2SZhang, Yanmin 	struct dirent **namelist = NULL;
15*d6d901c2SZhang, Yanmin 	int ret = 0;
16*d6d901c2SZhang, Yanmin 	int i;
17*d6d901c2SZhang, Yanmin 
18*d6d901c2SZhang, Yanmin 	sprintf(name, "/proc/%d/task", pid);
19*d6d901c2SZhang, Yanmin 	items = scandir(name, &namelist, NULL, NULL);
20*d6d901c2SZhang, Yanmin 	if (items <= 0)
21*d6d901c2SZhang, Yanmin                 return -ENOENT;
22*d6d901c2SZhang, Yanmin 	*all_tid = malloc(sizeof(pid_t) * items);
23*d6d901c2SZhang, Yanmin 	if (!*all_tid) {
24*d6d901c2SZhang, Yanmin 		ret = -ENOMEM;
25*d6d901c2SZhang, Yanmin 		goto failure;
26*d6d901c2SZhang, Yanmin 	}
27*d6d901c2SZhang, Yanmin 
28*d6d901c2SZhang, Yanmin 	for (i = 0; i < items; i++)
29*d6d901c2SZhang, Yanmin 		(*all_tid)[i] = atoi(namelist[i]->d_name);
30*d6d901c2SZhang, Yanmin 
31*d6d901c2SZhang, Yanmin 	ret = items;
32*d6d901c2SZhang, Yanmin 
33*d6d901c2SZhang, Yanmin failure:
34*d6d901c2SZhang, Yanmin 	for (i=0; i<items; i++)
35*d6d901c2SZhang, Yanmin 		free(namelist[i]);
36*d6d901c2SZhang, Yanmin 	free(namelist);
37*d6d901c2SZhang, Yanmin 
38*d6d901c2SZhang, Yanmin 	return ret;
39*d6d901c2SZhang, Yanmin }
40*d6d901c2SZhang, Yanmin 
419958e1f0SArnaldo Carvalho de Melo void map_groups__init(struct map_groups *self)
4295011c60SArnaldo Carvalho de Melo {
4395011c60SArnaldo Carvalho de Melo 	int i;
4495011c60SArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i) {
4595011c60SArnaldo Carvalho de Melo 		self->maps[i] = RB_ROOT;
4695011c60SArnaldo Carvalho de Melo 		INIT_LIST_HEAD(&self->removed_maps[i]);
4795011c60SArnaldo Carvalho de Melo 	}
4895011c60SArnaldo Carvalho de Melo }
4995011c60SArnaldo Carvalho de Melo 
5097ea1a7fSFrederic Weisbecker static struct thread *thread__new(pid_t pid)
516baa0a5aSFrederic Weisbecker {
5236479484SArnaldo Carvalho de Melo 	struct thread *self = zalloc(sizeof(*self));
536baa0a5aSFrederic Weisbecker 
546baa0a5aSFrederic Weisbecker 	if (self != NULL) {
559958e1f0SArnaldo Carvalho de Melo 		map_groups__init(&self->mg);
569958e1f0SArnaldo Carvalho de Melo 		self->pid = pid;
576baa0a5aSFrederic Weisbecker 		self->comm = malloc(32);
586baa0a5aSFrederic Weisbecker 		if (self->comm)
596baa0a5aSFrederic Weisbecker 			snprintf(self->comm, 32, ":%d", self->pid);
606baa0a5aSFrederic Weisbecker 	}
616baa0a5aSFrederic Weisbecker 
626baa0a5aSFrederic Weisbecker 	return self;
636baa0a5aSFrederic Weisbecker }
646baa0a5aSFrederic Weisbecker 
654385d580SDavid S. Miller static void map_groups__flush(struct map_groups *self)
664385d580SDavid S. Miller {
674385d580SDavid S. Miller 	int type;
684385d580SDavid S. Miller 
694385d580SDavid S. Miller 	for (type = 0; type < MAP__NR_TYPES; type++) {
704385d580SDavid S. Miller 		struct rb_root *root = &self->maps[type];
714385d580SDavid S. Miller 		struct rb_node *next = rb_first(root);
724385d580SDavid S. Miller 
734385d580SDavid S. Miller 		while (next) {
744385d580SDavid S. Miller 			struct map *pos = rb_entry(next, struct map, rb_node);
754385d580SDavid S. Miller 			next = rb_next(&pos->rb_node);
764385d580SDavid S. Miller 			rb_erase(&pos->rb_node, root);
774385d580SDavid S. Miller 			/*
784385d580SDavid S. Miller 			 * We may have references to this map, for
794385d580SDavid S. Miller 			 * instance in some hist_entry instances, so
804385d580SDavid S. Miller 			 * just move them to a separate list.
814385d580SDavid S. Miller 			 */
824385d580SDavid S. Miller 			list_add_tail(&pos->node, &self->removed_maps[pos->type]);
834385d580SDavid S. Miller 		}
844385d580SDavid S. Miller 	}
854385d580SDavid S. Miller }
864385d580SDavid S. Miller 
876baa0a5aSFrederic Weisbecker int thread__set_comm(struct thread *self, const char *comm)
886baa0a5aSFrederic Weisbecker {
894385d580SDavid S. Miller 	int err;
904385d580SDavid S. Miller 
916baa0a5aSFrederic Weisbecker 	if (self->comm)
926baa0a5aSFrederic Weisbecker 		free(self->comm);
936baa0a5aSFrederic Weisbecker 	self->comm = strdup(comm);
944385d580SDavid S. Miller 	err = self->comm == NULL ? -ENOMEM : 0;
954385d580SDavid S. Miller 	if (!err) {
96faa5c5c3SArnaldo Carvalho de Melo 		self->comm_set = true;
974385d580SDavid S. Miller 		map_groups__flush(&self->mg);
984385d580SDavid S. Miller 	}
994385d580SDavid S. Miller 	return err;
1006baa0a5aSFrederic Weisbecker }
1016baa0a5aSFrederic Weisbecker 
102a4fb581bSFrederic Weisbecker int thread__comm_len(struct thread *self)
103a4fb581bSFrederic Weisbecker {
104a4fb581bSFrederic Weisbecker 	if (!self->comm_len) {
105a4fb581bSFrederic Weisbecker 		if (!self->comm)
106a4fb581bSFrederic Weisbecker 			return 0;
107a4fb581bSFrederic Weisbecker 		self->comm_len = strlen(self->comm);
108a4fb581bSFrederic Weisbecker 	}
109a4fb581bSFrederic Weisbecker 
110a4fb581bSFrederic Weisbecker 	return self->comm_len;
111a4fb581bSFrederic Weisbecker }
112a4fb581bSFrederic Weisbecker 
11365f2ed2bSArnaldo Carvalho de Melo size_t __map_groups__fprintf_maps(struct map_groups *self,
11495011c60SArnaldo Carvalho de Melo 				  enum map_type type, FILE *fp)
11595011c60SArnaldo Carvalho de Melo {
11695011c60SArnaldo Carvalho de Melo 	size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
11795011c60SArnaldo Carvalho de Melo 	struct rb_node *nd;
11895011c60SArnaldo Carvalho de Melo 
11995011c60SArnaldo Carvalho de Melo 	for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
12095011c60SArnaldo Carvalho de Melo 		struct map *pos = rb_entry(nd, struct map, rb_node);
12195011c60SArnaldo Carvalho de Melo 		printed += fprintf(fp, "Map:");
12295011c60SArnaldo Carvalho de Melo 		printed += map__fprintf(pos, fp);
12365f2ed2bSArnaldo Carvalho de Melo 		if (verbose > 2) {
12495011c60SArnaldo Carvalho de Melo 			printed += dso__fprintf(pos->dso, type, fp);
12595011c60SArnaldo Carvalho de Melo 			printed += fprintf(fp, "--\n");
12695011c60SArnaldo Carvalho de Melo 		}
1271b46cddfSArnaldo Carvalho de Melo 	}
1286baa0a5aSFrederic Weisbecker 
12995011c60SArnaldo Carvalho de Melo 	return printed;
13095011c60SArnaldo Carvalho de Melo }
131439d473bSArnaldo Carvalho de Melo 
1329958e1f0SArnaldo Carvalho de Melo size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp)
13395011c60SArnaldo Carvalho de Melo {
13495011c60SArnaldo Carvalho de Melo 	size_t printed = 0, i;
13595011c60SArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
1369958e1f0SArnaldo Carvalho de Melo 		printed += __map_groups__fprintf_maps(self, i, fp);
13795011c60SArnaldo Carvalho de Melo 	return printed;
13895011c60SArnaldo Carvalho de Melo }
139439d473bSArnaldo Carvalho de Melo 
1409958e1f0SArnaldo Carvalho de Melo static size_t __map_groups__fprintf_removed_maps(struct map_groups *self,
14195011c60SArnaldo Carvalho de Melo 						 enum map_type type, FILE *fp)
14295011c60SArnaldo Carvalho de Melo {
14395011c60SArnaldo Carvalho de Melo 	struct map *pos;
14495011c60SArnaldo Carvalho de Melo 	size_t printed = 0;
14595011c60SArnaldo Carvalho de Melo 
14695011c60SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &self->removed_maps[type], node) {
14795011c60SArnaldo Carvalho de Melo 		printed += fprintf(fp, "Map:");
14895011c60SArnaldo Carvalho de Melo 		printed += map__fprintf(pos, fp);
14995011c60SArnaldo Carvalho de Melo 		if (verbose > 1) {
15095011c60SArnaldo Carvalho de Melo 			printed += dso__fprintf(pos->dso, type, fp);
15195011c60SArnaldo Carvalho de Melo 			printed += fprintf(fp, "--\n");
15295011c60SArnaldo Carvalho de Melo 		}
15395011c60SArnaldo Carvalho de Melo 	}
15495011c60SArnaldo Carvalho de Melo 	return printed;
15595011c60SArnaldo Carvalho de Melo }
15695011c60SArnaldo Carvalho de Melo 
1579958e1f0SArnaldo Carvalho de Melo static size_t map_groups__fprintf_removed_maps(struct map_groups *self, FILE *fp)
15895011c60SArnaldo Carvalho de Melo {
15995011c60SArnaldo Carvalho de Melo 	size_t printed = 0, i;
16095011c60SArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
1619958e1f0SArnaldo Carvalho de Melo 		printed += __map_groups__fprintf_removed_maps(self, i, fp);
16295011c60SArnaldo Carvalho de Melo 	return printed;
16395011c60SArnaldo Carvalho de Melo }
16495011c60SArnaldo Carvalho de Melo 
1659958e1f0SArnaldo Carvalho de Melo static size_t map_groups__fprintf(struct map_groups *self, FILE *fp)
1669958e1f0SArnaldo Carvalho de Melo {
1679958e1f0SArnaldo Carvalho de Melo 	size_t printed = map_groups__fprintf_maps(self, fp);
1689958e1f0SArnaldo Carvalho de Melo 	printed += fprintf(fp, "Removed maps:\n");
1699958e1f0SArnaldo Carvalho de Melo 	return printed + map_groups__fprintf_removed_maps(self, fp);
1709958e1f0SArnaldo Carvalho de Melo }
1719958e1f0SArnaldo Carvalho de Melo 
17295011c60SArnaldo Carvalho de Melo static size_t thread__fprintf(struct thread *self, FILE *fp)
17395011c60SArnaldo Carvalho de Melo {
1749958e1f0SArnaldo Carvalho de Melo 	return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) +
1759958e1f0SArnaldo Carvalho de Melo 	       map_groups__fprintf(&self->mg, fp);
1766baa0a5aSFrederic Weisbecker }
1776baa0a5aSFrederic Weisbecker 
178b3165f41SArnaldo Carvalho de Melo struct thread *perf_session__findnew(struct perf_session *self, pid_t pid)
1796baa0a5aSFrederic Weisbecker {
180b3165f41SArnaldo Carvalho de Melo 	struct rb_node **p = &self->threads.rb_node;
1816baa0a5aSFrederic Weisbecker 	struct rb_node *parent = NULL;
1826baa0a5aSFrederic Weisbecker 	struct thread *th;
1836baa0a5aSFrederic Weisbecker 
1846baa0a5aSFrederic Weisbecker 	/*
1856baa0a5aSFrederic Weisbecker 	 * Font-end cache - PID lookups come in blocks,
1866baa0a5aSFrederic Weisbecker 	 * so most of the time we dont have to look up
1876baa0a5aSFrederic Weisbecker 	 * the full rbtree:
1886baa0a5aSFrederic Weisbecker 	 */
189b3165f41SArnaldo Carvalho de Melo 	if (self->last_match && self->last_match->pid == pid)
190b3165f41SArnaldo Carvalho de Melo 		return self->last_match;
1916baa0a5aSFrederic Weisbecker 
1926baa0a5aSFrederic Weisbecker 	while (*p != NULL) {
1936baa0a5aSFrederic Weisbecker 		parent = *p;
1946baa0a5aSFrederic Weisbecker 		th = rb_entry(parent, struct thread, rb_node);
1956baa0a5aSFrederic Weisbecker 
1966baa0a5aSFrederic Weisbecker 		if (th->pid == pid) {
197b3165f41SArnaldo Carvalho de Melo 			self->last_match = th;
1986baa0a5aSFrederic Weisbecker 			return th;
1996baa0a5aSFrederic Weisbecker 		}
2006baa0a5aSFrederic Weisbecker 
2016baa0a5aSFrederic Weisbecker 		if (pid < th->pid)
2026baa0a5aSFrederic Weisbecker 			p = &(*p)->rb_left;
2036baa0a5aSFrederic Weisbecker 		else
2046baa0a5aSFrederic Weisbecker 			p = &(*p)->rb_right;
2056baa0a5aSFrederic Weisbecker 	}
2066baa0a5aSFrederic Weisbecker 
20797ea1a7fSFrederic Weisbecker 	th = thread__new(pid);
2086baa0a5aSFrederic Weisbecker 	if (th != NULL) {
2096baa0a5aSFrederic Weisbecker 		rb_link_node(&th->rb_node, parent, p);
210b3165f41SArnaldo Carvalho de Melo 		rb_insert_color(&th->rb_node, &self->threads);
211b3165f41SArnaldo Carvalho de Melo 		self->last_match = th;
2126baa0a5aSFrederic Weisbecker 	}
2136baa0a5aSFrederic Weisbecker 
2146baa0a5aSFrederic Weisbecker 	return th;
2156baa0a5aSFrederic Weisbecker }
2166baa0a5aSFrederic Weisbecker 
21712245509SArnaldo Carvalho de Melo static int map_groups__fixup_overlappings(struct map_groups *self,
2189958e1f0SArnaldo Carvalho de Melo 					  struct map *map)
2196baa0a5aSFrederic Weisbecker {
22095011c60SArnaldo Carvalho de Melo 	struct rb_root *root = &self->maps[map->type];
22195011c60SArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(root);
2226baa0a5aSFrederic Weisbecker 
2231b46cddfSArnaldo Carvalho de Melo 	while (next) {
2241b46cddfSArnaldo Carvalho de Melo 		struct map *pos = rb_entry(next, struct map, rb_node);
2251b46cddfSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
2261b46cddfSArnaldo Carvalho de Melo 
2271b46cddfSArnaldo Carvalho de Melo 		if (!map__overlap(pos, map))
2281b46cddfSArnaldo Carvalho de Melo 			continue;
2291b46cddfSArnaldo Carvalho de Melo 
2306e086437SFrederic Weisbecker 		if (verbose >= 2) {
2316beba7adSArnaldo Carvalho de Melo 			fputs("overlapping maps:\n", stderr);
2326beba7adSArnaldo Carvalho de Melo 			map__fprintf(map, stderr);
2336beba7adSArnaldo Carvalho de Melo 			map__fprintf(pos, stderr);
2346e086437SFrederic Weisbecker 		}
2356e086437SFrederic Weisbecker 
23695011c60SArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, root);
237439d473bSArnaldo Carvalho de Melo 		/*
238439d473bSArnaldo Carvalho de Melo 		 * We may have references to this map, for instance in some
239439d473bSArnaldo Carvalho de Melo 		 * hist_entry instances, so just move them to a separate
240439d473bSArnaldo Carvalho de Melo 		 * list.
241439d473bSArnaldo Carvalho de Melo 		 */
24295011c60SArnaldo Carvalho de Melo 		list_add_tail(&pos->node, &self->removed_maps[map->type]);
24312245509SArnaldo Carvalho de Melo 		/*
24412245509SArnaldo Carvalho de Melo 		 * Now check if we need to create new maps for areas not
24512245509SArnaldo Carvalho de Melo 		 * overlapped by the new map:
24612245509SArnaldo Carvalho de Melo 		 */
24712245509SArnaldo Carvalho de Melo 		if (map->start > pos->start) {
24812245509SArnaldo Carvalho de Melo 			struct map *before = map__clone(pos);
24912245509SArnaldo Carvalho de Melo 
25012245509SArnaldo Carvalho de Melo 			if (before == NULL)
25112245509SArnaldo Carvalho de Melo 				return -ENOMEM;
25212245509SArnaldo Carvalho de Melo 
25312245509SArnaldo Carvalho de Melo 			before->end = map->start - 1;
25412245509SArnaldo Carvalho de Melo 			map_groups__insert(self, before);
25512245509SArnaldo Carvalho de Melo 			if (verbose >= 2)
25612245509SArnaldo Carvalho de Melo 				map__fprintf(before, stderr);
2576baa0a5aSFrederic Weisbecker 		}
25812245509SArnaldo Carvalho de Melo 
25912245509SArnaldo Carvalho de Melo 		if (map->end < pos->end) {
26012245509SArnaldo Carvalho de Melo 			struct map *after = map__clone(pos);
26112245509SArnaldo Carvalho de Melo 
26212245509SArnaldo Carvalho de Melo 			if (after == NULL)
26312245509SArnaldo Carvalho de Melo 				return -ENOMEM;
26412245509SArnaldo Carvalho de Melo 
26512245509SArnaldo Carvalho de Melo 			after->start = map->end + 1;
26612245509SArnaldo Carvalho de Melo 			map_groups__insert(self, after);
26712245509SArnaldo Carvalho de Melo 			if (verbose >= 2)
26812245509SArnaldo Carvalho de Melo 				map__fprintf(after, stderr);
26912245509SArnaldo Carvalho de Melo 		}
27012245509SArnaldo Carvalho de Melo 	}
27112245509SArnaldo Carvalho de Melo 
27212245509SArnaldo Carvalho de Melo 	return 0;
2736e086437SFrederic Weisbecker }
2746baa0a5aSFrederic Weisbecker 
2751b46cddfSArnaldo Carvalho de Melo void maps__insert(struct rb_root *maps, struct map *map)
2761b46cddfSArnaldo Carvalho de Melo {
2771b46cddfSArnaldo Carvalho de Melo 	struct rb_node **p = &maps->rb_node;
2781b46cddfSArnaldo Carvalho de Melo 	struct rb_node *parent = NULL;
2791b46cddfSArnaldo Carvalho de Melo 	const u64 ip = map->start;
2801b46cddfSArnaldo Carvalho de Melo 	struct map *m;
2811b46cddfSArnaldo Carvalho de Melo 
2821b46cddfSArnaldo Carvalho de Melo 	while (*p != NULL) {
2831b46cddfSArnaldo Carvalho de Melo 		parent = *p;
2841b46cddfSArnaldo Carvalho de Melo 		m = rb_entry(parent, struct map, rb_node);
2851b46cddfSArnaldo Carvalho de Melo 		if (ip < m->start)
2861b46cddfSArnaldo Carvalho de Melo 			p = &(*p)->rb_left;
2871b46cddfSArnaldo Carvalho de Melo 		else
2881b46cddfSArnaldo Carvalho de Melo 			p = &(*p)->rb_right;
2891b46cddfSArnaldo Carvalho de Melo 	}
2901b46cddfSArnaldo Carvalho de Melo 
2911b46cddfSArnaldo Carvalho de Melo 	rb_link_node(&map->rb_node, parent, p);
2921b46cddfSArnaldo Carvalho de Melo 	rb_insert_color(&map->rb_node, maps);
2931b46cddfSArnaldo Carvalho de Melo }
2941b46cddfSArnaldo Carvalho de Melo 
2951b46cddfSArnaldo Carvalho de Melo struct map *maps__find(struct rb_root *maps, u64 ip)
2961b46cddfSArnaldo Carvalho de Melo {
2971b46cddfSArnaldo Carvalho de Melo 	struct rb_node **p = &maps->rb_node;
2981b46cddfSArnaldo Carvalho de Melo 	struct rb_node *parent = NULL;
2991b46cddfSArnaldo Carvalho de Melo 	struct map *m;
3001b46cddfSArnaldo Carvalho de Melo 
3011b46cddfSArnaldo Carvalho de Melo 	while (*p != NULL) {
3021b46cddfSArnaldo Carvalho de Melo 		parent = *p;
3031b46cddfSArnaldo Carvalho de Melo 		m = rb_entry(parent, struct map, rb_node);
3041b46cddfSArnaldo Carvalho de Melo 		if (ip < m->start)
3051b46cddfSArnaldo Carvalho de Melo 			p = &(*p)->rb_left;
3061b46cddfSArnaldo Carvalho de Melo 		else if (ip > m->end)
3071b46cddfSArnaldo Carvalho de Melo 			p = &(*p)->rb_right;
3081b46cddfSArnaldo Carvalho de Melo 		else
3091b46cddfSArnaldo Carvalho de Melo 			return m;
3101b46cddfSArnaldo Carvalho de Melo 	}
3111b46cddfSArnaldo Carvalho de Melo 
3121b46cddfSArnaldo Carvalho de Melo 	return NULL;
3131b46cddfSArnaldo Carvalho de Melo }
3141b46cddfSArnaldo Carvalho de Melo 
3151b46cddfSArnaldo Carvalho de Melo void thread__insert_map(struct thread *self, struct map *map)
3161b46cddfSArnaldo Carvalho de Melo {
31712245509SArnaldo Carvalho de Melo 	map_groups__fixup_overlappings(&self->mg, map);
3189958e1f0SArnaldo Carvalho de Melo 	map_groups__insert(&self->mg, map);
31995011c60SArnaldo Carvalho de Melo }
32095011c60SArnaldo Carvalho de Melo 
3219958e1f0SArnaldo Carvalho de Melo /*
3229958e1f0SArnaldo Carvalho de Melo  * XXX This should not really _copy_ te maps, but refcount them.
3239958e1f0SArnaldo Carvalho de Melo  */
3249958e1f0SArnaldo Carvalho de Melo static int map_groups__clone(struct map_groups *self,
3259958e1f0SArnaldo Carvalho de Melo 			     struct map_groups *parent, enum map_type type)
32695011c60SArnaldo Carvalho de Melo {
32795011c60SArnaldo Carvalho de Melo 	struct rb_node *nd;
32895011c60SArnaldo Carvalho de Melo 	for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) {
32995011c60SArnaldo Carvalho de Melo 		struct map *map = rb_entry(nd, struct map, rb_node);
33095011c60SArnaldo Carvalho de Melo 		struct map *new = map__clone(map);
33195011c60SArnaldo Carvalho de Melo 		if (new == NULL)
33295011c60SArnaldo Carvalho de Melo 			return -ENOMEM;
3339958e1f0SArnaldo Carvalho de Melo 		map_groups__insert(self, new);
33495011c60SArnaldo Carvalho de Melo 	}
33595011c60SArnaldo Carvalho de Melo 	return 0;
3366baa0a5aSFrederic Weisbecker }
3376baa0a5aSFrederic Weisbecker 
3386baa0a5aSFrederic Weisbecker int thread__fork(struct thread *self, struct thread *parent)
3396baa0a5aSFrederic Weisbecker {
34095011c60SArnaldo Carvalho de Melo 	int i;
3416baa0a5aSFrederic Weisbecker 
342faa5c5c3SArnaldo Carvalho de Melo 	if (parent->comm_set) {
3436baa0a5aSFrederic Weisbecker 		if (self->comm)
3446baa0a5aSFrederic Weisbecker 			free(self->comm);
3456baa0a5aSFrederic Weisbecker 		self->comm = strdup(parent->comm);
3466baa0a5aSFrederic Weisbecker 		if (!self->comm)
3476baa0a5aSFrederic Weisbecker 			return -ENOMEM;
348faa5c5c3SArnaldo Carvalho de Melo 		self->comm_set = true;
349faa5c5c3SArnaldo Carvalho de Melo 	}
3506baa0a5aSFrederic Weisbecker 
35195011c60SArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
3529958e1f0SArnaldo Carvalho de Melo 		if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
3536baa0a5aSFrederic Weisbecker 			return -ENOMEM;
3546baa0a5aSFrederic Weisbecker 	return 0;
3556baa0a5aSFrederic Weisbecker }
3566baa0a5aSFrederic Weisbecker 
357b3165f41SArnaldo Carvalho de Melo size_t perf_session__fprintf(struct perf_session *self, FILE *fp)
3586baa0a5aSFrederic Weisbecker {
3596baa0a5aSFrederic Weisbecker 	size_t ret = 0;
3606baa0a5aSFrederic Weisbecker 	struct rb_node *nd;
3616baa0a5aSFrederic Weisbecker 
362b3165f41SArnaldo Carvalho de Melo 	for (nd = rb_first(&self->threads); nd; nd = rb_next(nd)) {
3636baa0a5aSFrederic Weisbecker 		struct thread *pos = rb_entry(nd, struct thread, rb_node);
3646baa0a5aSFrederic Weisbecker 
3656baa0a5aSFrederic Weisbecker 		ret += thread__fprintf(pos, fp);
3666baa0a5aSFrederic Weisbecker 	}
3676baa0a5aSFrederic Weisbecker 
3686baa0a5aSFrederic Weisbecker 	return ret;
3696baa0a5aSFrederic Weisbecker }
3701ed091c4SArnaldo Carvalho de Melo 
3719958e1f0SArnaldo Carvalho de Melo struct symbol *map_groups__find_symbol(struct map_groups *self,
3721ed091c4SArnaldo Carvalho de Melo 				       enum map_type type, u64 addr,
3731ed091c4SArnaldo Carvalho de Melo 				       symbol_filter_t filter)
3741ed091c4SArnaldo Carvalho de Melo {
3759958e1f0SArnaldo Carvalho de Melo 	struct map *map = map_groups__find(self, type, addr);
3761ed091c4SArnaldo Carvalho de Melo 
3771ed091c4SArnaldo Carvalho de Melo 	if (map != NULL)
3789de89fe7SArnaldo Carvalho de Melo 		return map__find_symbol(map, map->map_ip(map, addr), filter);
3791ed091c4SArnaldo Carvalho de Melo 
3801ed091c4SArnaldo Carvalho de Melo 	return NULL;
3811ed091c4SArnaldo Carvalho de Melo }
382*d6d901c2SZhang, Yanmin 
383