00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #if defined(BUILD_OS_DARWIN)
00041 #include <darwin_elf.h>
00042 #else
00043 #include <elf.h>
00044 #endif
00045 #include <sys/types.h>
00046 #include <sys/stat.h>
00047 #include <sys/mman.h>
00048 #include <fcntl.h>
00049
00050 #include <stdio.h>
00051 #include <string.h>
00052 #include <vector>
00053 #include <algorithm>
00054 #include <stack>
00055 #include <map>
00056 #include <tree.h>
00057 #include "obj_info.h"
00058 #include "lib_phase_dir.h"
00059
00060 #define PAGESIZE 65536
00061 int debug = 0;
00062 const int LEN = 1000;
00063 const int MIN_FREQ = 15;
00064
00065
00066
00067 struct ltstr
00068 {
00069 bool operator()(const char* s1, const char* s2) const {
00070 return strcmp(s1, s2) < 0;
00071 }
00072 };
00073
00074
00075
00076 struct PROC {
00077 char *name;
00078 int size;
00079 int size_cluster;
00080 PROC *base;
00081 int offset;
00082 bool emit;
00083 int src_order;
00084 PROC(char *n) {
00085 name = strdup(n); size = 0; size_cluster = 0;
00086 base = NULL; offset = 0; emit = false; src_order = 0;
00087 }
00088 };
00089
00090
00091
00092 struct less<PROC> {
00093 bool operator()(const PROC *p1, const PROC *p2) {
00094 char *name1 = p1->base == NULL ? p1->name : p1->base->name;
00095 char *name2 = p2->base == NULL ? p2->name : p2->base->name;
00096 if (p1->base != p2->base) {
00097 int cmp = strcmp(name1, name2);
00098 if (cmp < 0)
00099 return true;
00100 else if (cmp >= 0)
00101 return false;
00102 }
00103 return p1->offset < p2->offset;
00104 }
00105 };
00106
00107
00108
00109 template <class PROC>
00110 struct less_src_order {
00111 bool operator()(const PROC *p1, const PROC *p2) {
00112 return (p1->src_order < p2->src_order);
00113 }
00114 };
00115
00116
00117 struct CALL {
00118 PROC *caller;
00119 PROC *callee;
00120 int freq;
00121 int retry_count;
00122 CALL(PROC *f1, PROC *f2, int f):caller(f1),callee(f2),freq(f),retry_count(0) {};
00123 };
00124
00125
00126
00127 struct less<CALL> {
00128 bool operator()(const CALL &c1, const CALL &c2) {
00129 return (c1.freq < c2.freq);
00130 }
00131 };
00132
00133
00134 typedef pair<PROC *, PROC *> map_key;
00135 typedef map< map_key, int> CG;
00136 typedef map<const char *, PROC *, ltstr> PROCTAB;
00137
00138
00139 bool file_exists(const char* path)
00140 {
00141 if (!path || strlen(path) == 0)
00142 return false;
00143
00144 struct stat buf;
00145 return stat(path, &buf) == 0 && S_ISREG(buf.st_mode);
00146 }
00147
00148
00149 struct compress_path : public unary_function<PROC *, void>
00150 {
00151 void operator() (PROC *x) {
00152 PROC *base = x;
00153 int offset = x->offset;
00154 while (base->base != NULL) {
00155 base = base->base;
00156 offset += base->offset;
00157 }
00158 if (x != base) {
00159 x->base = base;
00160 x->offset = offset;
00161 }
00162 }
00163 };
00164
00165
00166
00167
00168 void read_call_graph(const char *cgraph,
00169 PROCTAB &procedures,
00170 CG &cg)
00171 {
00172 FILE *in1 = fopen(cgraph, "r");
00173 if (in1 == NULL) {
00174 perror(cgraph);
00175 exit(1);
00176 }
00177
00178 char buffer[LEN];
00179 char *callee, *caller;
00180
00181 while (fgets(buffer, LEN, in1)) {
00182 caller = strdup(strtok(buffer, " \t"));
00183 callee = strdup(strtok(NULL, " \t"));
00184 int freq = atoi(strtok(NULL, " \t"));
00185 if (debug)
00186 printf("input call graph: %s %s %d\n", caller, callee, freq);
00187
00188 PROC *p1 = new PROC(caller);
00189 PROC *p2 = new PROC(callee);
00190 procedures.insert(pair<const char *, PROC *>(p1->name, p1));
00191 procedures.insert(pair<const char *, PROC *>(p2->name, p2));
00192
00193 map_key key(procedures[caller], procedures[callee]);
00194 CG::iterator it = cg.find(key);
00195 if (it != cg.end()) {
00196 (*it).second += freq;
00197 } else
00198 cg.insert(pair<map_key,int>(key, freq));
00199 }
00200 fclose(in1);
00201 }
00202
00203
00204
00205 int src_order = 0;
00206
00207
00208
00209 template <class Shdr>
00210 void process_object_file (File_Info &fi, Shdr *tag, PROCTAB &procedures)
00211 {
00212 Proc_Iter<Shdr> it(fi.begin(tag));
00213
00214 for (it = fi.begin(tag); it != fi.end(tag); ++it) {
00215 char *p = (*it).first;
00216 int size = (*it).second;
00217 bool updated = false;
00218 if (strncmp(p, ".text.", 6) == 0) {
00219 char *procname = p+6;
00220 PROCTAB::iterator ip = procedures.find(procname);
00221 if (ip != procedures.end()) {
00222 if (size % 16 != 0)
00223 size = size + (16 - size % 16);
00224 if (debug)
00225 printf("update %s size to %d\n", (*ip).second->name, size);
00226 (*ip).second->size = size;
00227 (*ip).second->size_cluster = size;
00228 updated = true;
00229 (*ip).second->src_order = src_order++;
00230 }
00231 }
00232 if (!updated && strcmp(p,".text.") != 0)
00233 if (debug)
00234 printf("cannot find %s in call-graph\n", p);
00235 }
00236 }
00237
00238
00239
00240 void read_obj_list(const char *objlist, PROCTAB &procedures)
00241 {
00242 FILE *in = fopen(objlist, "r");
00243 if (in == NULL) {
00244 perror(objlist);
00245 exit(1);
00246 }
00247
00248 char buffer[LEN];
00249 while (fgets(buffer, LEN, in)) {
00250 char *obj_file = strtok(buffer, " \t\n");
00251 if (debug)
00252 printf("process object %s\n", obj_file);
00253 File_Info fi (obj_file);
00254 if (fi.Get_obj_class () == ELFCLASS32)
00255 process_object_file (fi, Shdr32_tag (), procedures);
00256 else
00257 process_object_file (fi, Shdr64_tag (), procedures);
00258 }
00259 fclose(in);
00260 }
00261
00262
00263
00264
00265 bool layout(PROC *p1, PROC *p2, int freq, int retry_count)
00266 {
00267 if (p1 == p2) return true;
00268
00269 if (debug) {
00270 if (p1->size == 0)
00271 printf("warning: %s has 0 size.\n", p1->name);
00272 if (p2->size == 0)
00273 printf("warning: %s has 0 size.\n", p2->name);
00274 }
00275
00276 compress_path()(p1);
00277 compress_path()(p2);
00278
00279 PROC *base1 = p1->base ? p1->base : p1;
00280 PROC *base2 = p2->base ? p2->base : p2;
00281
00282 int loc1 = p1->offset % PAGESIZE;
00283 int loc2 = (p2->offset + base1->size_cluster) % PAGESIZE;
00284 if (base1 == base2)
00285 loc2 = p2->offset % PAGESIZE;
00286
00287 if (loc2 < loc1) loc2 += PAGESIZE;
00288 int overlap;
00289 if (loc2 >= loc1+p1->size)
00290 overlap = 0;
00291 else
00292 overlap = loc1 + p1->size - loc2;
00293 if (overlap == 0) {
00294 if (loc1 <= loc2) loc1 += PAGESIZE;
00295 if (loc1 >= loc2 + p2->size)
00296 overlap = 0;
00297 else
00298 overlap = loc2 + p2->size - loc1;
00299 }
00300
00301 if (overlap > 0) {
00302 if (debug) {
00303 printf("layout: detected overlap %d between %s (%d) <%s,%d> and %s (%d) <%s,%d> with freq %d\n",
00304 overlap,
00305 p1->name, p1->size, base1->name, p1->offset,
00306 p2->name, p2->size, base2->name, p2->offset,
00307 freq);
00308 }
00309 if (base1 != base2) {
00310 if (debug)
00311 printf("layout: delay layout\n");
00312 return false;
00313 } else {
00314 if (debug)
00315 printf("too late to change layout\n");
00316 return true;
00317 }
00318 }
00319
00320 if (base1 != base2) {
00321 if (debug)
00322 printf("layout: %s <%s,%d,%d> at %s <%s,%d,%d> with offset %d freq=%d retry=%d\n",
00323 p2->name, base2->name, p2->offset, p2->size,
00324 p1->name, base1->name, p1->offset, p1->size,
00325 base1->size_cluster, freq, retry_count);
00326
00327 base2->base = base1;
00328 base2->offset = base1->size_cluster;
00329 base1->size_cluster += base2->size_cluster;
00330 base2->size_cluster = 0;
00331 }
00332
00333 p1->emit = true;
00334 p2->emit = true;
00335 return true;
00336 }
00337
00338
00339
00340
00341 void emit_lkcord(const char *outfile, vector<PROC*> &proc_layout, vector<PROC*> &src_order_layout)
00342 {
00343 FILE *out;
00344 FILE *previous;
00345 FILE *bottom;
00346 char buffer[LEN];
00347 char* toolroot = getenv("TOOLROOT");
00348 char* previous_script= BINPATH "/" "cord_prologue";
00349 char* bottom_script= BINPATH "/cord_epilogue";
00350 char* previous_file;
00351 char* bottom_file;
00352 int len;
00353
00354
00355 if (toolroot) {
00356 len = strlen(toolroot) + strlen(previous_script);
00357 previous_file = (char *)malloc(len + 1);
00358 len = strlen(toolroot) + strlen(bottom_script);
00359 bottom_file = (char *)malloc(len + 1);
00360 sprintf(previous_file,"%s%s", toolroot, previous_script);
00361 sprintf(bottom_file,"%s%s", toolroot, bottom_script);
00362 } else {
00363 previous_file = previous_script;
00364 bottom_file = bottom_script;
00365 }
00366 if (outfile != NULL) {
00367 out = fopen(outfile, "w");
00368 if (out == NULL) {
00369 perror(outfile);
00370 exit(1);
00371 }
00372 } else
00373 out = stdout;
00374
00375 previous = fopen(previous_file, "r");
00376 if (previous == NULL ) {
00377 printf("Can't open cord-prologue script file\n");
00378 perror("previous");
00379 exit(1);
00380 }
00381
00382 bottom = fopen(bottom_file, "r");
00383 if (bottom == NULL ) {
00384 printf("Can't open cord-epilogue script file\n");
00385 perror("bottom");
00386 exit(1);
00387 }
00388
00389 while (fgets(buffer, LEN, previous))
00390 fputs(buffer, out);
00391
00392 vector<PROC *>::iterator q;
00393 for (q = proc_layout.begin(); q != proc_layout.end(); q++) {
00394 PROC *proc = *q;
00395 if (debug)
00396 printf("sorted: %s at %s + %d\n",
00397 proc->name,
00398 proc->base ? proc->base->name : "null" ,
00399 proc->offset);
00400 fprintf(out, " *(.text.%s)\n", proc->name);
00401 }
00402
00403 for (q = src_order_layout.begin(); q != src_order_layout.end(); q++) {
00404 PROC *proc = *q;
00405 if (debug)
00406 printf("src_order: %s\n", proc->name);
00407 fprintf(out, " *(.text.%s)\n", proc->name);
00408 }
00409
00410 while (fgets(buffer, LEN, bottom))
00411 fputs(buffer, out);
00412
00413 fclose(previous);
00414 fclose(bottom);
00415 }
00416
00417
00418 main(int argc, char *argv[])
00419 {
00420 char *outfile = NULL;
00421
00422 if (argc < 3) {
00423 fprintf(stderr, "usage: gen_cord -o orderspec call-graph objfilelist\n");
00424 exit(1);
00425 }
00426
00427 while (argv[1][0] == '-') {
00428 char *option = &argv[1][1];
00429 if (strcmp(option, "d") == 0)
00430 debug = 1;
00431 if (strcmp(option, "o") == 0) {
00432 ++argv;
00433 --argc;
00434 outfile = argv[1];
00435 }
00436 ++argv;
00437 --argc;
00438 }
00439 char *cgraph = argv[1];
00440 char *objfilelist = argv[2];
00441
00442 CG cg;
00443 PROCTAB procedures;
00444 priority_queue<CALL> Q;
00445
00446 read_call_graph(cgraph, procedures, cg);
00447
00448
00449 CG::iterator it;
00450 for (it = cg.begin(); it != cg.end(); it++) {
00451 PROC *p1 = (*it).first.first;
00452 PROC *p2 = (*it).first.second;
00453 int freq = (*it).second;
00454 if (debug)
00455 printf("summed call graph: %s %s %d\n", p1->name, p2->name, freq);
00456 Q.push(*(new CALL(p1, p2, freq)));
00457 }
00458
00459
00460 read_obj_list(objfilelist, procedures);
00461
00462
00463 while (!Q.empty()) {
00464 PROC *callee = Q.top().caller;
00465 PROC *caller = Q.top().callee;
00466 int freq = Q.top().freq;
00467 int retry = Q.top().retry_count;
00468
00469
00470 if (freq <= MIN_FREQ) break;
00471
00472 if (!layout(caller, callee, freq, retry)) {
00473 CALL edge = Q.top();
00474 edge.freq /= 2;
00475 edge.retry_count++;
00476 Q.pop();
00477 Q.push(edge);
00478 } else
00479 Q.pop();
00480 }
00481
00482
00483
00484 vector<PROC *> proc_layout, src_order_layout;
00485 PROCTAB::iterator p;
00486 for (p = procedures.begin(); p != procedures.end(); p++) {
00487 PROC *proc = (*p).second;
00488 if (proc->emit) {
00489 compress_path()(proc);
00490 proc_layout.push_back(proc);
00491 } else {
00492 src_order_layout.push_back(proc);
00493 }
00494 }
00495 sort(proc_layout.begin(), proc_layout.end(), less<PROC>());
00496 sort(src_order_layout.begin(), src_order_layout.end(), less_src_order<PROC>());
00497
00498
00499 emit_lkcord(outfile, proc_layout, src_order_layout);
00500 }
00501
00502