jitsymbol.c

Go to the documentation of this file.
00001 
00017 #include "opjitconv.h"
00018 #include "opd_printf.h"
00019 #include "op_libiberty.h"
00020 #include "op_types.h"
00021 
00022 #include <stddef.h>
00023 #include <stdlib.h>
00024 #include <stdint.h>
00025 #include <stdio.h>
00026 #include <string.h>
00027 #include <unistd.h>
00028 #include <limits.h>
00029 
00030 typedef int (*compare_symbol)(void const *, void const *);
00031 
00032 
00033 /* count the entries in the jitentry_list */
00034 static u32 count_entries(void)
00035 {
00036     struct jitentry const * entry;
00037     u32 cnt = 0;
00038     for (entry = jitentry_list; entry; entry = entry->next)
00039         cnt++;
00040     return cnt;
00041 }
00042 
00043 
00044 static void fill_entry_array(struct jitentry * entries[])
00045 {
00046     int i = 0;
00047     struct jitentry * entry;
00048     for (entry = jitentry_list; entry; entry = entry->next)
00049         entries[i++] = entry;
00050 }
00051 
00052 
00053 /* create an array pointing to the jitentry structures which is sorted
00054  * according to the comparator rule given by parameter compar
00055  */
00056 static struct jitentry ** create_sorted_array(compare_symbol compare)
00057 {
00058     struct jitentry ** array =
00059         xmalloc(sizeof(struct jitentry *) * entry_count);
00060     fill_entry_array(array);
00061     qsort(array, entry_count, sizeof(struct jitentry *), compare);
00062     return array;
00063 }
00064 
00065 
00066 /* comparator method for qsort which sorts jitentries by symbol_name */
00067 static int cmp_symbolname(void const * a, void const * b)
00068 {
00069     struct jitentry * a0 = *(struct jitentry **) a;
00070     struct jitentry * b0 = *(struct jitentry **) b;
00071     return strcmp(a0->symbol_name, b0->symbol_name);
00072 }
00073 
00074 
00075 /* comparator method for qsort which sorts jitentries by address */
00076 static int cmp_address(void const * a, void const * b)
00077 {
00078     struct jitentry * a0 = *(struct jitentry **) a;
00079     struct jitentry * b0 = *(struct jitentry **) b;
00080     if (a0->vma < b0->vma)
00081         return -1;
00082     if (a0->vma == b0->vma)
00083         return 0;
00084     return 1;
00085 }
00086 
00087 
00088 /* resort address_ascending array */
00089 static void resort_address(void)
00090 {
00091     u32 i;
00092 
00093     qsort(entries_address_ascending, entry_count,
00094           sizeof(struct jitentry *), cmp_address);
00095 
00096     // lower entry_count if entries are invalidated
00097     for (i = 0; i < entry_count; ++i) {
00098         if (entries_address_ascending[i]->vma)
00099             break;
00100     }
00101 
00102     if (i) {
00103         entry_count -= i;
00104         memmove(&entries_address_ascending[0],
00105             &entries_address_ascending[i],
00106             sizeof(struct jitentry *) * entry_count);
00107     }
00108 }
00109 
00110 
00111 /* Copy address_ascending array to entries_symbols_ascending and resort it.  */
00112 static void resort_symbol(void)
00113 {
00114     memcpy(entries_symbols_ascending, entries_address_ascending,
00115            sizeof(struct jitentry *) * entry_count);
00116     qsort(entries_symbols_ascending, entry_count,
00117           sizeof(struct jitentry *), cmp_symbolname);
00118 }
00119 
00120 /* allocate, populate and sort the jitentry arrays */
00121 void create_arrays(void)
00122 {
00123     max_entry_count = entry_count = count_entries();
00124     entries_symbols_ascending = create_sorted_array(cmp_symbolname);
00125     entries_address_ascending = create_sorted_array(cmp_address);
00126 }
00127 
00128 
00129 /* add a new create jitentry to the array. mallocs new arrays if space is
00130  * needed */
00131 static void insert_entry(struct jitentry * entry)
00132 {
00133     if (entry_count == max_entry_count) {
00134         if (max_entry_count < UINT32_MAX - 18)
00135             max_entry_count += 18;
00136         else if (max_entry_count < UINT32_MAX)
00137             max_entry_count += 1;
00138         else {
00139             fprintf(stderr, "Amount of JIT dump file entries is too large.\n");
00140             exit(EXIT_FAILURE);
00141         }
00142         entries_symbols_ascending = (struct jitentry **)
00143             xrealloc(entries_symbols_ascending,
00144                  sizeof(struct jitentry *) * max_entry_count);
00145         entries_address_ascending = (struct jitentry **)
00146             xrealloc(entries_address_ascending,
00147                  sizeof(struct jitentry *) * max_entry_count);
00148     }
00149     entries_address_ascending[entry_count++] = entry;
00150 }
00151 
00152 
00153 /* add a suffix to the name to differenciate it */
00154 static char * replacement_name(char * s, int i)
00155 {
00156     int cnt = 1;
00157     int j = i;
00158     char * res;
00159 
00160     while ((j = j/10))
00161         cnt++;
00162     cnt += 2 + strlen(s);
00163     res = xmalloc(cnt);
00164     snprintf(res, cnt, "%s~%i", s, i);
00165     return res;
00166 }
00167 
00168 
00169 /*
00170  * Mark the entry so it is not included in the ELF file. We do this by
00171  * writing a 0 address as magic vma and sorting
00172  * it out later
00173  */
00174 static void invalidate_entry(struct jitentry * e)
00175 {
00176     verbprintf(debug, "invalidate_entry: addr=%llx, name=%s\n",
00177            e->vma, e->symbol_name);
00178     e->vma = 0;
00179 }
00180 
00181 
00182 /*
00183  * Invalidate all symbols that are not alive at sampling start time.
00184  */
00185 static void invalidate_earlybirds(unsigned long long start_time)
00186 {
00187     u32 i;
00188     int flag;
00189     struct jitentry * a;
00190 
00191     flag = 0;
00192     for (i = 0; i < entry_count; i++) {
00193         a = entries_address_ascending[i];
00194         if (a->life_end < start_time) {
00195             invalidate_entry(a);
00196             flag = 1;
00197         }
00198     }
00199     if (flag) {
00200         resort_address();
00201         resort_symbol();
00202     }
00203 }
00204 
00205 
00206 /* select the symbol with the longest life time in the index range */
00207 static int select_one(int start_idx, int end_idx)
00208 {
00209     int i;
00210     int candidate = OP_JIT_CONV_FAIL;
00211     unsigned long long lifetime = 0;
00212     unsigned long long x;
00213     struct jitentry const * e;
00214 
00215     for (i = start_idx; i <= end_idx; i++) {
00216         e = entries_address_ascending[i];
00217         x = e->life_end - e->life_start;
00218         if (candidate == -1 || x > lifetime) {
00219             candidate = i;
00220             lifetime = x;
00221         }
00222     }
00223     return candidate;
00224 }
00225 
00226 
00227 /*
00228  * We decided to keep one entry in favor of the other. Instead of dropping
00229  * the overlapping entry we split or truncate it to not overlap any more.
00230  *
00231  * Looking on the address regions, we may have the following situation:
00232  *
00233  *  split:     |------------|
00234  *  keep:          |---|
00235  *
00236  * The split entry may be splitted in a left part and a right part. E.g.:
00237  *
00238  *  split0/1:  |--|     |---|
00239  *  keep:          |---|
00240  *
00241  * However, both parts may or may not exist.
00242  */
00243 static void split_entry(struct jitentry * split, struct jitentry const * keep)
00244 {
00245     unsigned long long start_addr_keep = keep->vma;
00246     unsigned long long end_addr_keep = keep->vma + keep->code_size;
00247     unsigned long long end_addr_split = split->vma + split->code_size;
00248     unsigned long long start_addr_split = split->vma;
00249 
00250     // do we need a right part?
00251     if (end_addr_split > end_addr_keep) {
00252         struct jitentry * new_entry =
00253             xcalloc(1, sizeof(struct jitentry));
00254         char * s = NULL;
00255         
00256         /* Check for max. length to avoid possible integer overflow. */
00257         if (strlen(split->symbol_name) > SIZE_MAX - 3) {
00258             fprintf(stderr, "Length of symbol name is too large.\n");
00259             exit(EXIT_FAILURE);
00260         } else {
00261             s = xmalloc(strlen(split->symbol_name) + 3);
00262             strcpy(s, split->symbol_name);
00263             strcat(s, "#1");
00264         }
00265         
00266         new_entry->vma = end_addr_keep;
00267         new_entry->code_size = end_addr_split - end_addr_keep;
00268         new_entry->symbol_name = s;
00269         new_entry->sym_name_malloced = 1;
00270         new_entry->life_start = split->life_start;
00271         new_entry->life_end = split->life_end;
00272         // the right part does not have an associated code, because we
00273         // don't know whether the split part begins at an opcode
00274         new_entry->code = NULL;
00275         verbprintf(debug, "split right (new) name=%s, start=%llx,"
00276                " end=%llx\n", new_entry->symbol_name,
00277                new_entry->vma,
00278                new_entry->vma + new_entry->code_size);
00279         insert_entry(new_entry);
00280     }
00281     // do we need a left part?
00282     if (start_addr_split < start_addr_keep) {
00283         char * s = NULL;
00284         
00285         /* Check for max. length to avoid possible integer overflow. */
00286         if (strlen(split->symbol_name) > SIZE_MAX - 3) {
00287             fprintf(stderr, "Length of symbol name is too large.\n");
00288             exit(EXIT_FAILURE);
00289         } else {
00290             s = xmalloc(strlen(split->symbol_name) + 3);
00291             strcpy(s, split->symbol_name);
00292             strcat(s, "#0");
00293         }
00294         
00295         split->code_size = start_addr_keep - start_addr_split;
00296         if (split->sym_name_malloced)
00297             free(split->symbol_name);
00298         split->symbol_name = s;
00299         split->sym_name_malloced = 1;
00300         verbprintf(debug, "split left name=%s, start=%llx, end=%llx\n",
00301                split->symbol_name, split->vma,
00302                split->vma + split->code_size);
00303     } else {
00304         invalidate_entry(split);
00305     }
00306 }
00307 
00308 
00309 /*
00310  * Scans through the index range and splits/truncates entries that overlap
00311  * with the one indexed by keep_idx. Returns the total lifetime of the symbols
00312  * found to overlap.
00313  * Returns ULONG_MAX on error.
00314  */
00315 static unsigned long long eliminate_overlaps(int start_idx, int end_idx,
00316                      int keep_idx)
00317 {
00318     unsigned long long retval;
00319     struct jitentry const * keep = entries_address_ascending[keep_idx];
00320     struct jitentry * e;
00321     unsigned long long start_addr_keep = keep->vma;
00322     unsigned long long end_addr_keep = keep->vma + keep->code_size;
00323     unsigned long long start_addr_entry, end_addr_entry;
00324     int i;
00325     unsigned long long min_start = keep->life_start;
00326     unsigned long long max_end = keep->life_end;
00327 
00328     for (i = start_idx; i <= end_idx; i++) {
00329         if (i == keep_idx)
00330             continue;
00331         e = entries_address_ascending[i];
00332         start_addr_entry = e->vma;
00333         end_addr_entry = e->vma + e->code_size;
00334         if (debug) {
00335             if (!(start_addr_entry <= end_addr_entry)) {
00336                 verbprintf(debug, "assert failed:"
00337                        " start_addr_entry <="
00338                        " end_addr_entry\n");
00339                 retval = ULONG_MAX;
00340                 goto out;
00341             }
00342             if (!(start_addr_keep <= end_addr_keep)) {
00343                 verbprintf(debug, "assert failed: "
00344                        "start_addr_keep <="
00345                        " end_addr_keep\n");
00346                 retval = ULONG_MAX;
00347                 goto out;
00348             }
00349         }
00350         if (start_addr_entry < end_addr_keep &&
00351             end_addr_entry > start_addr_keep) {
00352             if (e->life_start < min_start)
00353                 min_start = e->life_start;
00354             if (e->life_end > max_end)
00355                 max_end = e->life_end;
00356             split_entry(e, keep);
00357         }
00358     }
00359     retval = max_end - min_start;
00360 out:
00361     return retval;
00362 }
00363 
00364 
00365 /*
00366  * Within the index range (into the array entries_address_ascending), find the
00367  * symbol with the maximal lifetime and split/truncate all symbols that overlap
00368  * with it (i.e. that there won't be any overlaps anymore).
00369  */
00370 static int handle_overlap_region(int start_idx, int end_idx)
00371 {
00372     int rc = OP_JIT_CONV_OK;
00373     int idx;
00374     struct jitentry * e;
00375     int cnt;
00376     char * name;
00377     int i, j;
00378     unsigned long long totaltime;
00379 
00380     if (debug) {
00381         for (i = start_idx; i <= end_idx; i++) {
00382             e = entries_address_ascending[i];
00383             verbprintf(debug, "overlap idx=%i, name=%s, "
00384                    "start=%llx, end=%llx, life_start=%lli, "
00385                    "life_end=%lli, lifetime=%lli\n",
00386                    i, e->symbol_name, e->vma,
00387                    e->vma + e->code_size, e->life_start,
00388                    e->life_end, e->life_end - e->life_start);
00389         }
00390     }
00391     idx = select_one(start_idx, end_idx);
00392     totaltime = eliminate_overlaps(start_idx, end_idx, idx);
00393     if (totaltime == ULONG_MAX) {
00394         rc = OP_JIT_CONV_FAIL;
00395         goto out;
00396     }
00397     e = entries_address_ascending[idx];
00398 
00399     cnt = 1;
00400     j = (e->life_end - e->life_start) * 100 / totaltime;
00401     while ((j = j/10))
00402         cnt++;
00403 
00404     // Mark symbol name with a %% to indicate the overlap.
00405     cnt += strlen(e->symbol_name) + 2 + 1;
00406     name = xmalloc(cnt);
00407     snprintf(name, cnt, "%s%%%llu", e->symbol_name,
00408          (e->life_end - e->life_start) * 100 / totaltime);
00409     if (e->sym_name_malloced)
00410         free(e->symbol_name);
00411     e->symbol_name = name;
00412     e->sym_name_malloced = 1;
00413     verbprintf(debug, "selected idx=%i, name=%s\n", idx, e->symbol_name);
00414 out:
00415     return rc;
00416 }
00417 
00418 
00419 /*
00420  * one scan through the symbols to find overlaps.
00421  * return 1 if an overlap is found. this is repeated until no more overlap 
00422  * is there.
00423  * Process: There may be more than two overlapping symbols with each other.
00424  * The index range of symbols found to overlap are passed to
00425  * handle_overlap_region.
00426  */
00427 static int scan_overlaps(void)
00428 {
00429     int i, j;
00430     unsigned long long end_addr, end_addr2;
00431     struct jitentry const * a;
00432     int flag = 0;
00433     // entry_count can be incremented by split_entry() during the loop,
00434     // save the inital value as loop count
00435     int loop_count = entry_count;
00436 
00437     verbprintf(debug,"count=%i, scan overlaps...\n", entry_count);
00438     i = 0;
00439     end_addr = 0;
00440     for (j = 1; j < loop_count; j++) {
00468         a = entries_address_ascending[j - 1];
00469         end_addr2 = a->vma + a->code_size;
00470         if (end_addr2 > end_addr)
00471             end_addr = end_addr2;
00472         a = entries_address_ascending[j];
00473         if (end_addr <= a->vma) {
00474             if (i != j - 1) {
00475                 if (handle_overlap_region(i, j - 1) ==
00476                     OP_JIT_CONV_FAIL) {
00477                     flag = OP_JIT_CONV_FAIL;
00478                     goto out;
00479                 }
00480                 flag = 1;
00481             }
00482             i = j;
00483         }
00484     }
00485     if (i != j - 1) {
00486         if (handle_overlap_region(i, j - 1) == OP_JIT_CONV_FAIL)
00487             flag = OP_JIT_CONV_FAIL;
00488         else
00489             flag = 1;
00490     }
00491 out:
00492     return flag;
00493 }
00494 
00495 
00496 /* search for symbols that have overlapping address ranges and decide for
00497  * one */
00498 int resolve_overlaps(unsigned long long start_time)
00499 {
00500     int rc = OP_JIT_CONV_OK;
00501     int cnt = 0;
00502 
00503     invalidate_earlybirds(start_time);
00504     while ((rc = scan_overlaps()) && rc != OP_JIT_CONV_FAIL) {
00505         resort_address();
00506         if (cnt == 0) {
00507             verbprintf(debug, "WARNING: overlaps detected. "
00508                    "Removing overlapping JIT methods\n");
00509         }
00510         cnt++;
00511     }
00512     if (cnt > 0 && rc != OP_JIT_CONV_FAIL)
00513         resort_symbol();
00514     return rc;
00515 }
00516 
00517 
00518 /*
00519  * scan through the sorted array and replace identical symbol names by unique
00520  * ones by adding a counter value.
00521  */
00522 void disambiguate_symbol_names(void)
00523 {
00524     u32 j;
00525     int cnt, rep_cnt;
00526     struct jitentry * a;
00527     struct jitentry * b;
00528 
00529     rep_cnt = 0;
00530     for (j = 1; j < entry_count; j++) {
00531         a = entries_symbols_ascending[j - 1];
00532         cnt = 1;
00533         do {
00534             b = entries_symbols_ascending[j];
00535             if (strcmp(a->symbol_name, b->symbol_name) == 0) {
00536                 if (b->sym_name_malloced)
00537                     free(b->symbol_name);
00538                 b->symbol_name =
00539                     replacement_name(a->symbol_name, cnt);
00540                 b->sym_name_malloced = 1;
00541                 j++;
00542                 cnt++;
00543                 rep_cnt++;
00544             } else {
00545                 break;
00546             }
00547         } while (j < entry_count);
00548     }
00549     /* recurse to avoid that the added suffix also creates a collision */
00550     if (rep_cnt) {
00551         qsort(entries_symbols_ascending, entry_count,
00552               sizeof(struct jitentry *), cmp_symbolname);
00553         disambiguate_symbol_names();
00554     }
00555 }

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1