opd_anon.c

Go to the documentation of this file.
00001 
00020 #include "opd_anon.h"
00021 #include "opd_trans.h"
00022 #include "opd_sfile.h"
00023 #include "opd_printf.h"
00024 #include "op_libiberty.h"
00025 
00026 #include <limits.h>
00027 #include <stdlib.h>
00028 #include <stdio.h>
00029 #include <string.h>
00030 
00031 #define HASH_SIZE 1024
00032 #define HASH_BITS (HASH_SIZE - 1)
00033 
00034 /*
00035  * Note that this value is tempered by the fact that when we miss in the
00036  * anon cache, we'll tear down all the mappings for that tgid. Thus, LRU
00037  * of a mapping can potentially clear out a much larger number of
00038  * mappings.
00039  */
00040 #define LRU_SIZE 8192
00041 #define LRU_AMOUNT (LRU_SIZE/8)
00042 
00043 static struct list_head hashes[HASH_SIZE];
00044 static struct list_head lru;
00045 static size_t nr_lru;
00046 
00047 static void do_lru(struct transient * trans)
00048 {
00049     size_t nr_to_kill = LRU_AMOUNT;
00050     struct list_head * pos;
00051     struct list_head * pos2;
00052     struct anon_mapping * entry;
00053 
00054     list_for_each_safe(pos, pos2, &lru) {
00055         entry = list_entry(pos, struct anon_mapping, lru_list);
00056         if (trans->anon == entry)
00057             clear_trans_current(trans);
00058         if (trans->last_anon == entry)
00059             clear_trans_last(trans);
00060         sfile_clear_anon(entry);
00061         list_del(&entry->list);
00062         list_del(&entry->lru_list);
00063         --nr_lru;
00064         free(entry);
00065         if (nr_to_kill-- == 0)
00066             break;
00067     }
00068 }
00069 
00070 
00071 static unsigned long hash_anon(pid_t tgid, cookie_t app)
00072 {
00073     return ((app >> DCOOKIE_SHIFT) ^ (tgid >> 2)) & (HASH_SIZE - 1);
00074 }
00075  
00076 
00077 static void clear_anon_maps(struct transient * trans)
00078 {
00079     unsigned long hash = hash_anon(trans->tgid, trans->app_cookie);
00080     pid_t tgid = trans->tgid;
00081     cookie_t app = trans->app_cookie;
00082     struct list_head * pos;
00083     struct list_head * pos2;
00084     struct anon_mapping * entry;
00085 
00086     clear_trans_current(trans);
00087 
00088     list_for_each_safe(pos, pos2, &hashes[hash]) {
00089         entry = list_entry(pos, struct anon_mapping, list);
00090         if (entry->tgid == tgid && entry->app_cookie == app) {
00091             if (trans->last_anon == entry)
00092                 clear_trans_last(trans);
00093             sfile_clear_anon(entry);
00094             list_del(&entry->list);
00095             list_del(&entry->lru_list);
00096             --nr_lru;
00097             free(entry);
00098         }
00099     }
00100 
00101     if (vmisc) {
00102         char const * name = verbose_cookie(app);
00103         printf("Cleared anon maps for tgid %u (%s).\n", tgid, name);
00104     }
00105 }
00106 
00107 
00108 static void
00109 add_anon_mapping(struct transient * trans, vma_t start, vma_t end, char * name)
00110 {
00111     unsigned long hash = hash_anon(trans->tgid, trans->app_cookie);
00112     struct anon_mapping * m = xmalloc(sizeof(struct anon_mapping));
00113     m->tgid = trans->tgid;
00114     m->app_cookie = trans->app_cookie;
00115     m->start = start;
00116     m->end = end;
00117     strncpy(m->name, name, MAX_IMAGE_NAME_SIZE + 1);
00118     list_add_tail(&m->list, &hashes[hash]);
00119     list_add_tail(&m->lru_list, &lru);
00120     if (++nr_lru == LRU_SIZE)
00121         do_lru(trans);
00122     if (vmisc) {
00123         char const * name = verbose_cookie(m->app_cookie);
00124         printf("Added anon map 0x%llx-0x%llx for tgid %u (%s).\n",
00125                start, end, m->tgid, name);
00126     }
00127 }
00128 
00129 
00130 /* 42000000-4212f000 r-xp 00000000 16:03 424334 /lib/tls/libc-2.3.2.so */
00131 static void get_anon_maps(struct transient * trans)
00132 {
00133     FILE * fp = NULL;
00134     char buf[PATH_MAX];
00135     vma_t start, end;
00136     int ret;
00137 
00138     snprintf(buf, PATH_MAX, "/proc/%d/maps", trans->tgid);
00139     fp = fopen(buf, "r");
00140     if (!fp)
00141         return;
00142 
00143     while (fgets(buf, PATH_MAX, fp) != NULL) {
00144         char tmp[MAX_IMAGE_NAME_SIZE + 1];
00145         char name[MAX_IMAGE_NAME_SIZE + 1];
00146         /* Some anon maps have labels like
00147          * [heap], [stack], [vdso], [vsyscall] ...
00148          * Keep track of these labels. If a map has no name, call it "anon".
00149          * Ignore all mappings starting with "/" (file or shared memory object)
00150          */
00151         strcpy(name, "anon");
00152         ret = sscanf(buf, "%llx-%llx %20s %20s %20s %20s %20s",
00153                      &start, &end, tmp, tmp, tmp, tmp, name);
00154         if (ret < 6 || name[0] == '/')
00155             continue;
00156 
00157         add_anon_mapping(trans, start, end, name);
00158     }
00159 
00160     fclose(fp);
00161 }
00162 
00163 
00164 static int
00165 anon_match(struct transient const * trans, struct anon_mapping const * anon)
00166 {
00167     if (!anon)
00168         return 0;
00169     if (trans->tgid != anon->tgid)
00170         return 0;
00171     if (trans->app_cookie != anon->app_cookie)
00172         return 0;
00173     if (trans->pc < anon->start)
00174         return 0;
00175     return (trans->pc < anon->end);
00176 }
00177 
00178 
00179 struct anon_mapping * find_anon_mapping(struct transient * trans)
00180 {
00181     unsigned long hash = hash_anon(trans->tgid, trans->app_cookie);
00182     struct list_head * pos;
00183     struct anon_mapping * entry;
00184     int tried = 0;
00185 
00186     if (anon_match(trans, trans->anon))
00187         return (trans->anon);
00188 
00189 retry:
00190     list_for_each(pos, &hashes[hash]) {
00191         entry = list_entry(pos, struct anon_mapping, list);
00192         if (anon_match(trans, entry))
00193             goto success;
00194     }
00195 
00196     if (!tried) {
00197         clear_anon_maps(trans);
00198         get_anon_maps(trans);
00199         tried = 1;
00200         goto retry;
00201     }
00202 
00203     return NULL;
00204 
00205 success:
00206     /*
00207      * Typically, there's one big mapping that matches. Let's go
00208      * faster.
00209      */
00210     list_del(&entry->list);
00211     list_add(&entry->list, &hashes[hash]);
00212 
00213     verbprintf(vmisc, "Found range 0x%llx-0x%llx for tgid %u, pc %llx.\n",
00214                entry->start, entry->end, (unsigned int)entry->tgid,
00215            trans->pc);
00216     return entry;
00217 }
00218 
00219 
00220 void anon_init(void)
00221 {
00222     size_t i;
00223 
00224     for (i = 0; i < HASH_SIZE; ++i)
00225         list_init(&hashes[i]);
00226 
00227     list_init(&lru);
00228 }

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1