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 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 43 int opd_get_nr_images(void) 44 { 45 return nr_images; 46 } 47 48 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 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 */ 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 * 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 */ 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 */ 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 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 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