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