• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * @file opd_image.c
3  * Management of binary images
4  *
5  * @remark Copyright 2002 OProfile authors
6  * @remark Read the file COPYING
7  *
8  * @author John Levon
9  * @author Philippe Elie
10  */
11 
12 #include "opd_image.h"
13 #include "opd_printf.h"
14 #include "opd_sample_files.h"
15 #include "opd_24_stats.h"
16 #include "oprofiled.h"
17 
18 #include "op_file.h"
19 #include "op_config_24.h"
20 #include "op_libiberty.h"
21 #include "op_string.h"
22 
23 #include <string.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 
27 /* maintained for statistics purpose only */
28 static int nr_images;
29 
30 /* list of images */
31 #define OPD_IMAGE_HASH_SIZE 2048
32 static struct list_head opd_images[OPD_IMAGE_HASH_SIZE];
33 
34 
opd_init_images(void)35 void opd_init_images(void)
36 {
37 	int i;
38 	for (i = 0; i < OPD_IMAGE_HASH_SIZE; ++i)
39 		list_init(&opd_images[i]);
40 }
41 
42 
opd_get_nr_images(void)43 int opd_get_nr_images(void)
44 {
45 	return nr_images;
46 }
47 
48 
opd_delete_image(struct opd_image * image)49 void opd_delete_image(struct opd_image * image)
50 {
51 	verbprintf(vmisc, "Deleting image: name %s app_name %s, kernel %d, "
52 	           "tid %d, tgid %d ref count %u\n",
53 	           image->name, image->app_name, image->kernel,
54 	           image->tid, image->tgid, (int)image->ref_count);
55 
56 	if (image->ref_count <= 0) {
57 		printf("image->ref_count < 0 for image: name %s app_name %s, "
58 		       "kernel %d, tid %d, tgid %d ref count %u\n",
59 		       image->name, image->app_name, image->kernel,
60 		       image->tid, image->tgid, image->ref_count);
61 		abort();
62 	}
63 
64 	if (--image->ref_count != 0)
65 		return;
66 
67 	if (image->name)
68 		free(image->name);
69 	if (image->app_name)
70 		free(image->app_name);
71 	list_del(&image->hash_next);
72 	opd_close_image_samples_files(image);
73 	free(image);
74 
75 	nr_images--;
76 }
77 
78 
opd_for_each_image(opd_image_cb image_cb)79 void opd_for_each_image(opd_image_cb image_cb)
80 {
81 	struct list_head * pos;
82 	struct list_head * pos2;
83 	int i;
84 
85 	for (i = 0; i < OPD_IMAGE_HASH_SIZE; ++i) {
86 		list_for_each_safe(pos, pos2, &opd_images[i]) {
87 			struct opd_image * image =
88 				list_entry(pos, struct opd_image, hash_next);
89 			image_cb(image);
90 		}
91 	}
92 }
93 
94 
95 /**
96  * opd_hash_image - hash an image
97  * @param hash  hash of image name
98  * @param tid  thread id
99  * @param tgid  thread group id
100  *
101  * return the hash code for the passed parameters
102  */
opd_hash_image(char const * name,pid_t tid,pid_t tgid)103 static size_t opd_hash_image(char const * name, pid_t tid, pid_t tgid)
104 {
105 	size_t hash = op_hash_string(name);
106 	if (separate_thread)
107 		hash += tid + tgid;
108 	return  hash % OPD_IMAGE_HASH_SIZE;
109 }
110 
111 
112 /**
113  * opd_new_image - create an image sample file
114  * @param app_name  the application name where belongs this image
115  * @param name  name of the image to add
116  * @param kernel  is the image a kernel/module image
117  * @param tid  thread id
118  * @param tgid  thread group id
119  *
120  * image at funtion entry is uninitialised
121  * name is copied i.e. should be GC'd separately from the
122  * image structure if appropriate.
123  *
124  * Initialise an opd_image struct for the image image
125  * without opening the associated samples files. At return
126  * the image is fully initialized.
127  */
128 static struct opd_image *
opd_new_image(char const * name,char const * app_name,int kernel,pid_t tid,pid_t tgid)129 opd_new_image(char const * name, char const * app_name, int kernel,
130               pid_t tid, pid_t tgid)
131 {
132 	size_t hash_image;
133 	struct opd_image * image;
134 
135 	verbprintf(vmisc, "Creating image: %s %s, kernel %d, tid %d, "
136 	           "tgid %d\n", name, app_name, kernel, tid, tgid);
137 
138 	image = xmalloc(sizeof(struct opd_image));
139 
140 	list_init(&image->hash_next);
141 	image->name = xstrdup(name);
142 	image->kernel = kernel;
143 	image->tid = tid;
144 	image->tgid = tgid;
145 	image->ref_count = 0;
146 	image->app_name = app_name ? xstrdup(app_name) : NULL;
147 	image->mtime = op_get_mtime(image->name);
148 
149 	image->ignored = 1;
150 	if (separate_lib && app_name)
151 		image->ignored = is_image_ignored(app_name);
152 	if (image->ignored)
153 		image->ignored = is_image_ignored(name);
154 
155 	memset(image->sfiles, '\0', NR_CPUS * sizeof(struct opd_24_sfile **));
156 
157 	hash_image = opd_hash_image(name, tid, tgid);
158 	list_add(&image->hash_next, &opd_images[hash_image]);
159 
160 	nr_images++;
161 
162 	return image;
163 }
164 
165 
166 /**
167  * is_same_image - check for identical image
168  * @param image  image to compare
169  * @param name  name of image
170  * @param app_name image must belong to this application name
171  * @param tid  thread id
172  * @param tgid  thread group id
173  *
174  * on entry caller have checked than strcmp(image->name, name) == 0
175  * return 0 if the couple (name, app_name) refers to same image
176  */
is_same_image(struct opd_image const * image,char const * app_name,pid_t tid,pid_t tgid)177 static int is_same_image(struct opd_image const * image, char const * app_name,
178                          pid_t tid, pid_t tgid)
179 {
180 	/* correctness is really important here, if we fail to recognize
181 	 * identical image we will open/mmap multiple time the same samples
182 	 * files which is not supported by the kernel, strange assertion
183 	 * failure in libfd is a typical symptom of that */
184 
185 	if (separate_thread) {
186 		if (image->tid != tid || image->tgid != tgid)
187 			return 1;
188 	}
189 
190 	/* if !separate_lib, the comparison made by caller is enough */
191 	if (!separate_lib)
192 		return 0;
193 
194 	if (image->app_name == NULL && app_name == NULL)
195 		return 0;
196 
197 	if (image->app_name != NULL && app_name != NULL &&
198 	    !strcmp(image->app_name, app_name))
199 		return 0;
200 
201 	/* /proc parsed image come with a non null app_name but notification
202 	 * for application itself come with a null app_name, in this case
203 	 * the test above fail so check for this case. */
204 	if (image->app_name && !app_name && !strcmp(image->app_name, image->name))
205 		return 0;
206 
207 	return 1;
208 }
209 
210 
211 /**
212  * opd_find_image - find an image
213  * @param name  name of image to find
214  * @param hash  hash of image to find
215  * @param app_name  the application name where belongs this image
216  * @param tid  thread id
217  * @param tgid  thread group id
218  *
219  * Returns the image pointer for the file specified by name, or %NULL.
220  */
opd_find_image(char const * name,char const * app_name,pid_t tid,pid_t tgid)221 static struct opd_image * opd_find_image(char const * name,
222                                 char const * app_name, pid_t tid, pid_t tgid)
223 {
224 	/* suppress uninitialized use warning */
225 	struct opd_image * image = 0;
226 	struct list_head * pos;
227 	size_t bucket;
228 
229 	opd_24_stats[OPD_IMAGE_HASH_ACCESS]++;
230 	bucket = opd_hash_image(name, tid, tgid);
231 	list_for_each(pos, &opd_images[bucket]) {
232 		opd_24_stats[OPD_IMAGE_HASH_DEPTH]++;
233 		image = list_entry(pos, struct opd_image, hash_next);
234 
235 		if (!strcmp(image->name, name)) {
236 			if (!is_same_image(image, app_name, tid, tgid))
237 				break;
238 		}
239 	}
240 
241 	if (pos == &opd_images[bucket])
242 		return NULL;
243 
244 	/* The app_name field is always valid */
245 	return image;
246 }
247 
248 
opd_get_image(char const * name,char const * app_name,int kernel,pid_t tid,pid_t tgid)249 struct opd_image * opd_get_image(char const * name, char const * app_name,
250                                  int kernel, pid_t tid, pid_t tgid)
251 {
252 	struct opd_image * image;
253 	if ((image = opd_find_image(name, app_name, tid, tgid)) == NULL)
254 		image = opd_new_image(name, app_name, kernel, tid, tgid);
255 
256 	return image;
257 }
258 
259 
opd_get_kernel_image(char const * name,char const * app_name,pid_t tid,pid_t tgid)260 struct opd_image * opd_get_kernel_image(char const * name,
261                                char const * app_name, pid_t tid, pid_t tgid)
262 {
263 	return opd_get_image(name, app_name, 1, tid, tgid);
264 }
265