opd_image.c

Go to the documentation of this file.
00001 
00012 #include "opd_image.h"
00013 #include "opd_printf.h"
00014 #include "opd_sample_files.h"
00015 #include "opd_24_stats.h"
00016 #include "oprofiled.h"
00017 
00018 #include "op_file.h"
00019 #include "op_config_24.h"
00020 #include "op_libiberty.h"
00021 #include "op_string.h"
00022 
00023 #include <string.h>
00024 #include <stdlib.h>
00025 #include <stdio.h>
00026 
00027 /* maintained for statistics purpose only */
00028 static int nr_images;
00029 
00030 /* list of images */
00031 #define OPD_IMAGE_HASH_SIZE 2048
00032 static struct list_head opd_images[OPD_IMAGE_HASH_SIZE];
00033 
00034 
00035 void opd_init_images(void)
00036 {
00037     int i;
00038     for (i = 0; i < OPD_IMAGE_HASH_SIZE; ++i)
00039         list_init(&opd_images[i]);
00040 }
00041 
00042 
00043 int opd_get_nr_images(void)
00044 {
00045     return nr_images;
00046 }
00047 
00048 
00049 void opd_delete_image(struct opd_image * image)
00050 {
00051     verbprintf(vmisc, "Deleting image: name %s app_name %s, kernel %d, "
00052                "tid %d, tgid %d ref count %u\n",
00053                image->name, image->app_name, image->kernel,
00054                image->tid, image->tgid, (int)image->ref_count);
00055 
00056     if (image->ref_count <= 0) {
00057         printf("image->ref_count < 0 for image: name %s app_name %s, "
00058                "kernel %d, tid %d, tgid %d ref count %u\n",
00059                image->name, image->app_name, image->kernel,
00060                image->tid, image->tgid, image->ref_count);
00061         abort();
00062     }
00063 
00064     if (--image->ref_count != 0)
00065         return;
00066 
00067     if (image->name)
00068         free(image->name);
00069     if (image->app_name)
00070         free(image->app_name);
00071     list_del(&image->hash_next);
00072     opd_close_image_samples_files(image);
00073     free(image);
00074 
00075     nr_images--;
00076 }
00077 
00078 
00079 void opd_for_each_image(opd_image_cb image_cb)
00080 {
00081     struct list_head * pos;
00082     struct list_head * pos2;
00083     int i;
00084 
00085     for (i = 0; i < OPD_IMAGE_HASH_SIZE; ++i) {
00086         list_for_each_safe(pos, pos2, &opd_images[i]) {
00087             struct opd_image * image =
00088                 list_entry(pos, struct opd_image, hash_next);
00089             image_cb(image);
00090         }
00091     }
00092 }
00093  
00094 
00103 static size_t opd_hash_image(char const * name, pid_t tid, pid_t tgid)
00104 {
00105     size_t hash = op_hash_string(name);
00106     if (separate_thread)
00107         hash += tid + tgid;
00108     return  hash % OPD_IMAGE_HASH_SIZE;
00109 }
00110 
00111 
00128 static struct opd_image *
00129 opd_new_image(char const * name, char const * app_name, int kernel,
00130               pid_t tid, pid_t tgid)
00131 {
00132     size_t hash_image;
00133     struct opd_image * image;
00134 
00135     verbprintf(vmisc, "Creating image: %s %s, kernel %d, tid %d, "
00136                "tgid %d\n", name, app_name, kernel, tid, tgid);
00137 
00138     image = xmalloc(sizeof(struct opd_image));
00139 
00140     list_init(&image->hash_next);
00141     image->name = xstrdup(name);
00142     image->kernel = kernel;
00143     image->tid = tid;
00144     image->tgid = tgid;
00145     image->ref_count = 0;
00146     image->app_name = app_name ? xstrdup(app_name) : NULL;
00147     image->mtime = op_get_mtime(image->name);
00148 
00149     image->ignored = 1;
00150     if (separate_lib && app_name)
00151         image->ignored = is_image_ignored(app_name);
00152     if (image->ignored)
00153         image->ignored = is_image_ignored(name);
00154 
00155     memset(image->sfiles, '\0', NR_CPUS * sizeof(struct opd_24_sfile **));
00156 
00157     hash_image = opd_hash_image(name, tid, tgid);
00158     list_add(&image->hash_next, &opd_images[hash_image]);
00159 
00160     nr_images++;
00161 
00162     return image;
00163 }
00164 
00165 
00177 static int is_same_image(struct opd_image const * image, char const * app_name,
00178                          pid_t tid, pid_t tgid)
00179 {
00180     /* correctness is really important here, if we fail to recognize
00181      * identical image we will open/mmap multiple time the same samples
00182      * files which is not supported by the kernel, strange assertion
00183      * failure in libfd is a typical symptom of that */
00184 
00185     if (separate_thread) {
00186         if (image->tid != tid || image->tgid != tgid)
00187             return 1;
00188     }
00189 
00190     /* if !separate_lib, the comparison made by caller is enough */
00191     if (!separate_lib)
00192         return 0;
00193 
00194     if (image->app_name == NULL && app_name == NULL)
00195         return 0;
00196 
00197     if (image->app_name != NULL && app_name != NULL &&
00198         !strcmp(image->app_name, app_name))
00199         return 0;
00200 
00201     /* /proc parsed image come with a non null app_name but notification
00202      * for application itself come with a null app_name, in this case
00203      * the test above fail so check for this case. */
00204     if (image->app_name && !app_name && !strcmp(image->app_name, image->name))
00205         return 0;
00206 
00207     return 1;
00208 }
00209 
00210 
00221 static struct opd_image * opd_find_image(char const * name, 
00222                                 char const * app_name, pid_t tid, pid_t tgid)
00223 {
00224     /* suppress uninitialized use warning */
00225     struct opd_image * image = 0;
00226     struct list_head * pos;
00227     size_t bucket;
00228 
00229     opd_24_stats[OPD_IMAGE_HASH_ACCESS]++;
00230     bucket = opd_hash_image(name, tid, tgid);
00231     list_for_each(pos, &opd_images[bucket]) {
00232         opd_24_stats[OPD_IMAGE_HASH_DEPTH]++;
00233         image = list_entry(pos, struct opd_image, hash_next);
00234 
00235         if (!strcmp(image->name, name)) {
00236             if (!is_same_image(image, app_name, tid, tgid))
00237                 break;
00238         }
00239     }
00240 
00241     if (pos == &opd_images[bucket])
00242         return NULL;
00243 
00244     /* The app_name field is always valid */
00245     return image;
00246 }
00247 
00248  
00249 struct opd_image * opd_get_image(char const * name, char const * app_name,
00250                                  int kernel, pid_t tid, pid_t tgid)
00251 {
00252     struct opd_image * image;
00253     if ((image = opd_find_image(name, app_name, tid, tgid)) == NULL)
00254         image = opd_new_image(name, app_name, kernel, tid, tgid);
00255 
00256     return image;
00257 }
00258 
00259 
00260 struct opd_image * opd_get_kernel_image(char const * name,
00261                                char const * app_name, pid_t tid, pid_t tgid)
00262 {
00263     return opd_get_image(name, app_name, 1, tid, tgid);
00264 }

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1