Home | History | Annotate | Download | only in callgrind
      1 /*--------------------------------------------------------------------*/
      2 /*--- Callgrind                                                    ---*/
      3 /*---                                                       dump.c ---*/
      4 /*--------------------------------------------------------------------*/
      5 
      6 /*
      7    This file is part of Callgrind, a Valgrind tool for call tracing.
      8 
      9    Copyright (C) 2002-2013, Josef Weidendorfer (Josef.Weidendorfer (at) gmx.de)
     10 
     11    This program is free software; you can redistribute it and/or
     12    modify it under the terms of the GNU General Public License as
     13    published by the Free Software Foundation; either version 2 of the
     14    License, or (at your option) any later version.
     15 
     16    This program is distributed in the hope that it will be useful, but
     17    WITHOUT ANY WARRANTY; without even the implied warranty of
     18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     19    General Public License for more details.
     20 
     21    You should have received a copy of the GNU General Public License
     22    along with this program; if not, write to the Free Software
     23    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     24    02111-1307, USA.
     25 
     26    The GNU General Public License is contained in the file COPYING.
     27 */
     28 
     29 #include "config.h"
     30 #include "global.h"
     31 
     32 #include "pub_tool_threadstate.h"
     33 #include "pub_tool_libcfile.h"
     34 
     35 
     36 /* Dump Part Counter */
     37 static Int out_counter = 0;
     38 
     39 static HChar* out_file = 0;
     40 static Bool dumps_initialized = False;
     41 
     42 /* Command */
     43 static HChar *cmdbuf;
     44 
     45 /* Total reads/writes/misses sum over all dumps and threads.
     46  * Updated during CC traversal at dump time.
     47  */
     48 FullCost CLG_(total_cost) = 0;
     49 static FullCost dump_total_cost = 0;
     50 
     51 EventMapping* CLG_(dumpmap) = 0;
     52 
     53 Int CLG_(get_dump_counter)(void)
     54 {
     55   return out_counter;
     56 }
     57 
     58 /*------------------------------------------------------------*/
     59 /*--- Output file related stuff                            ---*/
     60 /*------------------------------------------------------------*/
     61 
     62 /* Boolean dumping array */
     63 static Bool* dump_array = 0;
     64 static Int   dump_array_size = 0;
     65 static Bool* obj_dumped = 0;
     66 static Bool* file_dumped = 0;
     67 static Bool* fn_dumped = 0;
     68 static Bool* cxt_dumped = 0;
     69 
     70 static
     71 void reset_dump_array(void)
     72 {
     73     int i;
     74 
     75     CLG_ASSERT(dump_array != 0);
     76 
     77     for(i=0;i<dump_array_size;i++)
     78 	dump_array[i] = False;
     79 }
     80 
     81 static
     82 void init_dump_array(void)
     83 {
     84     dump_array_size = CLG_(stat).distinct_objs +
     85       CLG_(stat).distinct_files +
     86       CLG_(stat).distinct_fns +
     87       CLG_(stat).context_counter;
     88     CLG_ASSERT(dump_array == 0);
     89     dump_array = (Bool*) CLG_MALLOC("cl.dump.ida.1",
     90                                     dump_array_size * sizeof(Bool));
     91     obj_dumped  = dump_array;
     92     file_dumped = obj_dumped + CLG_(stat).distinct_objs;
     93     fn_dumped   = file_dumped + CLG_(stat).distinct_files;
     94     cxt_dumped  = fn_dumped + CLG_(stat).distinct_fns;
     95 
     96     reset_dump_array();
     97 
     98     CLG_DEBUG(1, "  init_dump_array: size %d\n", dump_array_size);
     99 }
    100 
    101 static __inline__
    102 void free_dump_array(void)
    103 {
    104     CLG_ASSERT(dump_array != 0);
    105     VG_(free)(dump_array);
    106 
    107     dump_array = 0;
    108     obj_dumped = 0;
    109     file_dumped = 0;
    110     fn_dumped = 0;
    111     cxt_dumped = 0;
    112 }
    113 
    114 
    115 /* Initialize to an invalid position */
    116 static __inline__
    117 void init_fpos(FnPos* p)
    118  {
    119     p->file = 0;
    120     p->fn = 0;
    121     p->obj = 0;
    122     p->cxt = 0;
    123     p->rec_index = 0;
    124 }
    125 
    126 
    127 static void print_obj(VgFile *fp, const HChar* prefix, obj_node* obj)
    128 {
    129     if (CLG_(clo).compress_strings) {
    130 	CLG_ASSERT(obj_dumped != 0);
    131 	if (obj_dumped[obj->number])
    132             VG_(fprintf)(fp, "%s(%d)\n", prefix, obj->number);
    133 	else {
    134             VG_(fprintf)(fp, "%s(%d) %s\n", prefix, obj->number, obj->name);
    135 	}
    136     }
    137     else
    138         VG_(fprintf)(fp, "%s%s\n", prefix, obj->name);
    139 
    140 #if 0
    141     /* add mapping parameters the first time a object is dumped
    142      * format: mp=0xSTART SIZE 0xOFFSET */
    143     if (!obj_dumped[obj->number]) {
    144 	obj_dumped[obj->number];
    145 	VG_(fprintf)(fp, "mp=%p %p %p\n",
    146 		     pos->obj->start, pos->obj->size, pos->obj->offset);
    147     }
    148 #else
    149     obj_dumped[obj->number] = True;
    150 #endif
    151 }
    152 
    153 static void print_file(VgFile *fp, const char *prefix, const file_node* file)
    154 {
    155     if (CLG_(clo).compress_strings) {
    156 	CLG_ASSERT(file_dumped != 0);
    157 	if (file_dumped[file->number])
    158             VG_(fprintf)(fp, "%s(%d)\n", prefix, file->number);
    159 	else {
    160             VG_(fprintf)(fp, "%s(%d) %s\n", prefix, file->number, file->name);
    161 	    file_dumped[file->number] = True;
    162 	}
    163     }
    164     else
    165         VG_(fprintf)(fp, "%s%s\n", prefix, file->name);
    166 }
    167 
    168 /*
    169  * tag can be "fn", "cfn", "jfn"
    170  */
    171 static void print_fn(VgFile *fp, const HChar* tag, const fn_node* fn)
    172 {
    173     VG_(fprintf)(fp, "%s=",tag);
    174     if (CLG_(clo).compress_strings) {
    175 	CLG_ASSERT(fn_dumped != 0);
    176 	if (fn_dumped[fn->number])
    177 	    VG_(fprintf)(fp, "(%d)\n", fn->number);
    178 	else {
    179 	    VG_(fprintf)(fp, "(%d) %s\n", fn->number, fn->name);
    180 	    fn_dumped[fn->number] = True;
    181 	}
    182     }
    183     else
    184         VG_(fprintf)(fp, "%s\n", fn->name);
    185 }
    186 
    187 static void print_mangled_fn(VgFile *fp, const HChar* tag,
    188 			     Context* cxt, int rec_index)
    189 {
    190     int i;
    191 
    192     if (CLG_(clo).compress_strings && CLG_(clo).compress_mangled) {
    193 
    194 	int n;
    195 	Context* last;
    196 
    197 	CLG_ASSERT(cxt_dumped != 0);
    198 	if (cxt_dumped[cxt->base_number+rec_index]) {
    199             VG_(fprintf)(fp, "%s=(%d)\n",
    200 			     tag, cxt->base_number + rec_index);
    201 	    return;
    202 	}
    203 
    204 	last = 0;
    205 	/* make sure that for all context parts compressed data is written */
    206 	for(i=cxt->size;i>0;i--) {
    207 	    CLG_ASSERT(cxt->fn[i-1]->pure_cxt != 0);
    208 	    n = cxt->fn[i-1]->pure_cxt->base_number;
    209 	    if (cxt_dumped[n]) continue;
    210 	    VG_(fprintf)(fp, "%s=(%d) %s\n",
    211 			     tag, n, cxt->fn[i-1]->name);
    212 
    213 	    cxt_dumped[n] = True;
    214 	    last = cxt->fn[i-1]->pure_cxt;
    215 	}
    216 	/* If the last context was the context to print, we are finished */
    217 	if ((last == cxt) && (rec_index == 0)) return;
    218 
    219 	VG_(fprintf)(fp, "%s=(%d) (%d)", tag,
    220 			 cxt->base_number + rec_index,
    221 			 cxt->fn[0]->pure_cxt->base_number);
    222 	if (rec_index >0)
    223 	    VG_(fprintf)(fp, "'%d", rec_index +1);
    224 	for(i=1;i<cxt->size;i++)
    225 	    VG_(fprintf)(fp, "'(%d)",
    226 			      cxt->fn[i]->pure_cxt->base_number);
    227 	VG_(fprintf)(fp, "\n");
    228 
    229 	cxt_dumped[cxt->base_number+rec_index] = True;
    230 	return;
    231     }
    232 
    233 
    234     VG_(fprintf)(fp, "%s=", tag);
    235     if (CLG_(clo).compress_strings) {
    236 	CLG_ASSERT(cxt_dumped != 0);
    237 	if (cxt_dumped[cxt->base_number+rec_index]) {
    238 	    VG_(fprintf)(fp, "(%d)\n", cxt->base_number + rec_index);
    239 	    return;
    240 	}
    241 	else {
    242 	    VG_(fprintf)(fp, "(%d) ", cxt->base_number + rec_index);
    243 	    cxt_dumped[cxt->base_number+rec_index] = True;
    244 	}
    245     }
    246 
    247     VG_(fprintf)(fp, "%s", cxt->fn[0]->name);
    248     if (rec_index >0)
    249 	VG_(fprintf)(fp, "'%d", rec_index +1);
    250     for(i=1;i<cxt->size;i++)
    251 	VG_(fprintf)(fp, "'%s", cxt->fn[i]->name);
    252 
    253     VG_(fprintf)(fp, "\n");
    254 }
    255 
    256 
    257 
    258 /**
    259  * Print function position of the BBCC, but only print info differing to
    260  * the <last> position, update <last>
    261  * Return True if something changes.
    262  */
    263 static Bool print_fn_pos(VgFile *fp, FnPos* last, BBCC* bbcc)
    264 {
    265     Bool res = False;
    266 
    267     CLG_ASSERT(bbcc && bbcc->cxt);
    268 
    269     CLG_DEBUGIF(3) {
    270 	CLG_DEBUG(2, "+ print_fn_pos: ");
    271 	CLG_(print_cxt)(16, bbcc->cxt, bbcc->rec_index);
    272     }
    273 
    274     if (!CLG_(clo).mangle_names) {
    275 	if (last->rec_index != bbcc->rec_index) {
    276 	    VG_(fprintf)(fp, "rec=%d\n\n", bbcc->rec_index);
    277 	    last->rec_index = bbcc->rec_index;
    278 	    last->cxt = 0; /* reprint context */
    279 	    res = True;
    280 	}
    281 
    282 	if (last->cxt != bbcc->cxt) {
    283 	    fn_node* last_from = (last->cxt && last->cxt->size >1) ?
    284 				 last->cxt->fn[1] : 0;
    285 	    fn_node* curr_from = (bbcc->cxt->size >1) ?
    286 				 bbcc->cxt->fn[1] : 0;
    287 	    if (curr_from == 0) {
    288 		if (last_from != 0) {
    289 		    /* switch back to no context */
    290 		    VG_(fprintf)(fp, "frfn=(spontaneous)\n");
    291 		    res = True;
    292 		}
    293 	    }
    294 	    else if (last_from != curr_from) {
    295 		print_fn(fp, "frfn", curr_from);
    296 		res = True;
    297 	    }
    298 	    last->cxt = bbcc->cxt;
    299 	}
    300     }
    301 
    302     if (last->obj != bbcc->cxt->fn[0]->file->obj) {
    303 	print_obj(fp, "ob=", bbcc->cxt->fn[0]->file->obj);
    304 	last->obj = bbcc->cxt->fn[0]->file->obj;
    305 	res = True;
    306     }
    307 
    308     if (last->file != bbcc->cxt->fn[0]->file) {
    309         print_file(fp, "fl=", bbcc->cxt->fn[0]->file);
    310 	last->file = bbcc->cxt->fn[0]->file;
    311 	res = True;
    312     }
    313 
    314     if (!CLG_(clo).mangle_names) {
    315 	if (last->fn != bbcc->cxt->fn[0]) {
    316 	    print_fn(fp, "fn", bbcc->cxt->fn[0]);
    317 	    last->fn = bbcc->cxt->fn[0];
    318 	    res = True;
    319 	}
    320     }
    321     else {
    322 	/* Print mangled name if context or rec_index changes */
    323 	if ((last->rec_index != bbcc->rec_index) ||
    324 	    (last->cxt != bbcc->cxt)) {
    325 
    326 	    print_mangled_fn(fp, "fn", bbcc->cxt, bbcc->rec_index);
    327 	    last->fn = bbcc->cxt->fn[0];
    328 	    last->rec_index = bbcc->rec_index;
    329 	    res = True;
    330 	}
    331     }
    332 
    333     last->cxt = bbcc->cxt;
    334 
    335     CLG_DEBUG(2, "- print_fn_pos: %s\n", res ? "changed" : "");
    336 
    337     return res;
    338 }
    339 
    340 /* the debug lookup cache is useful if BBCC for same BB are
    341  * dumped directly in a row. This is a direct mapped cache.
    342  */
    343 #define DEBUG_CACHE_SIZE 1777
    344 
    345 static Addr       debug_cache_addr[DEBUG_CACHE_SIZE];
    346 static file_node* debug_cache_file[DEBUG_CACHE_SIZE];
    347 static int        debug_cache_line[DEBUG_CACHE_SIZE];
    348 static Bool       debug_cache_info[DEBUG_CACHE_SIZE];
    349 
    350 static __inline__
    351 void init_debug_cache(void)
    352 {
    353     int i;
    354     for(i=0;i<DEBUG_CACHE_SIZE;i++) {
    355 	debug_cache_addr[i] = 0;
    356 	debug_cache_file[i] = 0;
    357 	debug_cache_line[i] = 0;
    358 	debug_cache_info[i] = 0;
    359     }
    360 }
    361 
    362 static /* __inline__ */
    363 Bool get_debug_pos(BBCC* bbcc, Addr addr, AddrPos* p)
    364 {
    365     const HChar *file, *dir;
    366     Bool found_file_line;
    367 
    368     int cachepos = addr % DEBUG_CACHE_SIZE;
    369 
    370     if (debug_cache_addr[cachepos] == addr) {
    371 	p->line = debug_cache_line[cachepos];
    372 	p->file = debug_cache_file[cachepos];
    373 	found_file_line = debug_cache_info[cachepos];
    374     }
    375     else {
    376 	found_file_line = VG_(get_filename_linenum)(addr,
    377 						    &file,
    378 						    &dir,
    379 						    &(p->line));
    380 	if (!found_file_line) {
    381             file = "???";
    382 	    p->line = 0;
    383 	}
    384 	p->file    = CLG_(get_file_node)(bbcc->bb->obj, dir, file);
    385 
    386 	debug_cache_info[cachepos] = found_file_line;
    387 	debug_cache_addr[cachepos] = addr;
    388 	debug_cache_line[cachepos] = p->line;
    389 	debug_cache_file[cachepos] = p->file;
    390     }
    391 
    392     /* Address offset from bbcc start address */
    393     p->addr = addr - bbcc->bb->obj->offset;
    394     p->bb_addr = bbcc->bb->offset;
    395 
    396     CLG_DEBUG(3, "  get_debug_pos(%#lx): BB %#lx, fn '%s', file '%s', line %u\n",
    397 	     addr, bb_addr(bbcc->bb), bbcc->cxt->fn[0]->name,
    398 	     p->file->name, p->line);
    399 
    400     return found_file_line;
    401 }
    402 
    403 
    404 /* copy file position and init cost */
    405 static void init_apos(AddrPos* p, Addr addr, Addr bbaddr, file_node* file)
    406 {
    407     p->addr    = addr;
    408     p->bb_addr = bbaddr;
    409     p->file    = file;
    410     p->line    = 0;
    411 }
    412 
    413 static void copy_apos(AddrPos* dst, AddrPos* src)
    414 {
    415     dst->addr    = src->addr;
    416     dst->bb_addr = src->bb_addr;
    417     dst->file    = src->file;
    418     dst->line    = src->line;
    419 }
    420 
    421 /* copy file position and init cost */
    422 static void init_fcost(AddrCost* c, Addr addr, Addr bbaddr, file_node* file)
    423 {
    424     init_apos( &(c->p), addr, bbaddr, file);
    425     /* FIXME: This is a memory leak as a AddrCost is inited multiple times */
    426     c->cost = CLG_(get_eventset_cost)( CLG_(sets).full );
    427     CLG_(init_cost)( CLG_(sets).full, c->cost );
    428 }
    429 
    430 
    431 /**
    432  * print position change inside of a BB (last -> curr)
    433  * this doesn't update last to curr!
    434  */
    435 static void fprint_apos(VgFile *fp, AddrPos* curr, AddrPos* last,
    436                         file_node* func_file)
    437 {
    438     CLG_ASSERT(curr->file != 0);
    439     CLG_DEBUG(2, "    print_apos(file '%s', line %d, bb %#lx, addr %#lx) fnFile '%s'\n",
    440 	     curr->file->name, curr->line, curr->bb_addr, curr->addr,
    441 	     func_file->name);
    442 
    443     if (curr->file != last->file) {
    444 
    445 	/* if we switch back to orig file, use fe=... */
    446 	if (curr->file == func_file)
    447             print_file(fp, "fe=", curr->file);
    448 	else
    449             print_file(fp, "fi=", curr->file);
    450     }
    451 
    452     if (CLG_(clo).dump_bbs) {
    453 	if (curr->line != last->line) {
    454 	    VG_(fprintf)(fp, "ln=%d\n", curr->line);
    455 	}
    456     }
    457 }
    458 
    459 
    460 
    461 /**
    462  * Print a position.
    463  * This prints out differences if allowed
    464  *
    465  * This doesn't set last to curr afterwards!
    466  */
    467 static
    468 void fprint_pos(VgFile *fp, const AddrPos* curr, const AddrPos* last)
    469 {
    470     if (0) //CLG_(clo).dump_bbs)
    471 	VG_(fprintf)(fp, "%lu ", curr->addr - curr->bb_addr);
    472     else {
    473 	if (CLG_(clo).dump_instr) {
    474 	    int diff = curr->addr - last->addr;
    475 	    if ( CLG_(clo).compress_pos && (last->addr >0) &&
    476 		 (diff > -100) && (diff < 100)) {
    477 		if (diff >0)
    478 		    VG_(fprintf)(fp, "+%d ", diff);
    479 		else if (diff==0)
    480 		    VG_(fprintf)(fp, "* ");
    481 	        else
    482 		    VG_(fprintf)(fp, "%d ", diff);
    483 	    }
    484 	    else
    485 		VG_(fprintf)(fp, "%#lx ", curr->addr);
    486 	}
    487 
    488 	if (CLG_(clo).dump_bb) {
    489 	    int diff = curr->bb_addr - last->bb_addr;
    490 	    if ( CLG_(clo).compress_pos && (last->bb_addr >0) &&
    491 		 (diff > -100) && (diff < 100)) {
    492 		if (diff >0)
    493 		    VG_(fprintf)(fp, "+%d ", diff);
    494 		else if (diff==0)
    495 		    VG_(fprintf)(fp, "* ");
    496 	        else
    497 		    VG_(fprintf)(fp, "%d ", diff);
    498 	    }
    499 	    else
    500 		VG_(fprintf)(fp, "%#lx ", curr->bb_addr);
    501 	}
    502 
    503 	if (CLG_(clo).dump_line) {
    504 	    int diff = curr->line - last->line;
    505 	    if ( CLG_(clo).compress_pos && (last->line >0) &&
    506 		 (diff > -100) && (diff < 100)) {
    507 
    508 		if (diff >0)
    509 		    VG_(fprintf)(fp, "+%d ", diff);
    510 		else if (diff==0)
    511 		    VG_(fprintf)(fp, "* ");
    512 	        else
    513 		    VG_(fprintf)(fp, "%d ", diff);
    514 	    }
    515 	    else
    516 		VG_(fprintf)(fp, "%u ", curr->line);
    517 	}
    518     }
    519 }
    520 
    521 
    522 /**
    523  * Print events.
    524  */
    525 
    526 static
    527 void fprint_cost(VgFile *fp, const EventMapping* es, const ULong* cost)
    528 {
    529   HChar *mcost = CLG_(mappingcost_as_string)(es, cost);
    530   VG_(fprintf)(fp, "%s\n", mcost);
    531   CLG_FREE(mcost);
    532 }
    533 
    534 
    535 
    536 /* Write the cost of a source line; only that parts of the source
    537  * position are written that changed relative to last written position.
    538  * funcPos is the source position of the first line of actual function.
    539  * Something is written only if cost != 0; returns True in this case.
    540  */
    541 static void fprint_fcost(VgFile *fp, AddrCost* c, AddrPos* last)
    542 {
    543   CLG_DEBUGIF(3) {
    544     CLG_DEBUG(2, "   print_fcost(file '%s', line %d, bb %#lx, addr %#lx):\n",
    545 	     c->p.file->name, c->p.line, c->p.bb_addr, c->p.addr);
    546     CLG_(print_cost)(-5, CLG_(sets).full, c->cost);
    547   }
    548 
    549   fprint_pos(fp, &(c->p), last);
    550   copy_apos( last, &(c->p) ); /* update last to current position */
    551 
    552   fprint_cost(fp, CLG_(dumpmap), c->cost);
    553 
    554   /* add cost to total */
    555   CLG_(add_and_zero_cost)( CLG_(sets).full, dump_total_cost, c->cost );
    556 }
    557 
    558 
    559 /* Write out the calls from jcc (at pos)
    560  */
    561 static void fprint_jcc(VgFile *fp, jCC* jcc, AddrPos* curr, AddrPos* last,
    562                        ULong ecounter)
    563 {
    564     static AddrPos target;
    565     file_node* file;
    566     obj_node*  obj;
    567 
    568     CLG_DEBUGIF(2) {
    569       CLG_DEBUG(2, "   fprint_jcc (jkind %d)\n", jcc->jmpkind);
    570       CLG_(print_jcc)(-10, jcc);
    571     }
    572 
    573     CLG_ASSERT(jcc->to !=0);
    574     CLG_ASSERT(jcc->from !=0);
    575 
    576     if (!get_debug_pos(jcc->to, bb_addr(jcc->to->bb), &target)) {
    577 	/* if we don't have debug info, don't switch to file "???" */
    578 	target.file = last->file;
    579     }
    580 
    581     if ((jcc->jmpkind == jk_CondJump) || (jcc->jmpkind == jk_Jump)) {
    582 
    583       /* this is a JCC for a followed conditional or boring jump. */
    584       CLG_ASSERT(CLG_(is_zero_cost)( CLG_(sets).full, jcc->cost));
    585 
    586       /* objects among jumps should be the same.
    587        * Otherwise this jump would have been changed to a call
    588        *  (see setup_bbcc)
    589        */
    590       CLG_ASSERT(jcc->from->bb->obj == jcc->to->bb->obj);
    591 
    592 	/* only print if target position info is usefull */
    593 	if (!CLG_(clo).dump_instr && !CLG_(clo).dump_bb && target.line==0) {
    594 	  jcc->call_counter = 0;
    595 	  return;
    596 	}
    597 
    598 	/* Different files/functions are possible e.g. with longjmp's
    599 	 * which change the stack, and thus context
    600 	 */
    601 	if (last->file != target.file) {
    602             print_file(fp, "jfi=", target.file);
    603 	}
    604 
    605 	if (jcc->from->cxt != jcc->to->cxt) {
    606 	    if (CLG_(clo).mangle_names)
    607 		print_mangled_fn(fp, "jfn",
    608 				 jcc->to->cxt, jcc->to->rec_index);
    609 	    else
    610 		print_fn(fp, "jfn", jcc->to->cxt->fn[0]);
    611 	}
    612 
    613 	if (jcc->jmpkind == jk_CondJump) {
    614 	    /* format: jcnd=<followed>/<executions> <target> */
    615 	    VG_(fprintf)(fp, "jcnd=%llu/%llu ",
    616 			 jcc->call_counter, ecounter);
    617 	}
    618 	else {
    619 	    /* format: jump=<jump count> <target> */
    620 	    VG_(fprintf)(fp, "jump=%llu ",
    621 			 jcc->call_counter);
    622 	}
    623 
    624 	fprint_pos(fp, &target, last);
    625 	VG_(fprintf)(fp, "\n");
    626 	fprint_pos(fp, curr, last);
    627 	VG_(fprintf)(fp, "\n");
    628 
    629 	jcc->call_counter = 0;
    630 	return;
    631     }
    632 
    633     file = jcc->to->cxt->fn[0]->file;
    634     obj  = jcc->to->bb->obj;
    635 
    636     /* object of called position different to object of this function?*/
    637     if (jcc->from->cxt->fn[0]->file->obj != obj) {
    638 	print_obj(fp, "cob=", obj);
    639     }
    640 
    641     /* file of called position different to current file? */
    642     if (last->file != file) {
    643         print_file(fp, "cfi=", file);
    644     }
    645 
    646     if (CLG_(clo).mangle_names)
    647 	print_mangled_fn(fp, "cfn", jcc->to->cxt, jcc->to->rec_index);
    648     else
    649 	print_fn(fp, "cfn", jcc->to->cxt->fn[0]);
    650 
    651     if (!CLG_(is_zero_cost)( CLG_(sets).full, jcc->cost)) {
    652         VG_(fprintf)(fp, "calls=%llu ",
    653 		   jcc->call_counter);
    654 
    655 	fprint_pos(fp, &target, last);
    656         VG_(fprintf)(fp, "\n");
    657 	fprint_pos(fp, curr, last);
    658 	fprint_cost(fp, CLG_(dumpmap), jcc->cost);
    659 
    660 	CLG_(init_cost)( CLG_(sets).full, jcc->cost );
    661 
    662 	jcc->call_counter = 0;
    663     }
    664 }
    665 
    666 
    667 
    668 /* Cost summation of functions.We use alternately ccSum[0/1], thus
    669  * ssSum[currSum] for recently read lines with same line number.
    670  */
    671 static AddrCost ccSum[2];
    672 static int currSum;
    673 
    674 /*
    675  * Print all costs of a BBCC:
    676  * - FCCs of instructions
    677  * - JCCs of the unique jump of this BB
    678  * returns True if something was written
    679  */
    680 static Bool fprint_bbcc(VgFile *fp, BBCC* bbcc, AddrPos* last)
    681 {
    682   InstrInfo* instr_info;
    683   ULong ecounter;
    684   Bool something_written = False;
    685   jCC* jcc;
    686   AddrCost *currCost, *newCost;
    687   Int jcc_count = 0, instr, i, jmp;
    688   BB* bb = bbcc->bb;
    689 
    690   CLG_ASSERT(bbcc->cxt != 0);
    691   CLG_DEBUGIF(1) {
    692     VG_(printf)("+ fprint_bbcc (Instr %d): ", bb->instr_count);
    693     CLG_(print_bbcc)(15, bbcc);
    694   }
    695 
    696   CLG_ASSERT(currSum == 0 || currSum == 1);
    697   currCost = &(ccSum[currSum]);
    698   newCost  = &(ccSum[1-currSum]);
    699 
    700   ecounter = bbcc->ecounter_sum;
    701   jmp = 0;
    702   instr_info = &(bb->instr[0]);
    703   for(instr=0; instr<bb->instr_count; instr++, instr_info++) {
    704 
    705     /* get debug info of current instruction address and dump cost
    706      * if CLG_(clo).dump_bbs or file/line has changed
    707      */
    708     if (!get_debug_pos(bbcc, bb_addr(bb) + instr_info->instr_offset,
    709 		       &(newCost->p))) {
    710       /* if we don't have debug info, don't switch to file "???" */
    711       newCost->p.file = bbcc->cxt->fn[0]->file;
    712     }
    713 
    714     if (CLG_(clo).dump_bbs || CLG_(clo).dump_instr ||
    715 	(newCost->p.line != currCost->p.line) ||
    716 	(newCost->p.file != currCost->p.file)) {
    717 
    718       if (!CLG_(is_zero_cost)( CLG_(sets).full, currCost->cost )) {
    719 	something_written = True;
    720 
    721 	fprint_apos(fp, &(currCost->p), last, bbcc->cxt->fn[0]->file);
    722 	fprint_fcost(fp, currCost, last);
    723       }
    724 
    725       /* switch buffers */
    726       currSum = 1 - currSum;
    727       currCost = &(ccSum[currSum]);
    728       newCost  = &(ccSum[1-currSum]);
    729     }
    730 
    731     /* add line cost to current cost sum */
    732     (*CLG_(cachesim).add_icost)(currCost->cost, bbcc, instr_info, ecounter);
    733 
    734     /* print jcc's if there are: only jumps */
    735     if (bb->jmp[jmp].instr == instr) {
    736 	jcc_count=0;
    737 	for(jcc=bbcc->jmp[jmp].jcc_list; jcc; jcc=jcc->next_from)
    738 	    if (((jcc->jmpkind != jk_Call) && (jcc->call_counter >0)) ||
    739 		(!CLG_(is_zero_cost)( CLG_(sets).full, jcc->cost )))
    740 	      jcc_count++;
    741 
    742 	if (jcc_count>0) {
    743 	    if (!CLG_(is_zero_cost)( CLG_(sets).full, currCost->cost )) {
    744 		/* no need to switch buffers, as position is the same */
    745 		fprint_apos(fp, &(currCost->p), last, bbcc->cxt->fn[0]->file);
    746 		fprint_fcost(fp, currCost, last);
    747 	    }
    748 	    get_debug_pos(bbcc, bb_addr(bb)+instr_info->instr_offset, &(currCost->p));
    749 	    fprint_apos(fp, &(currCost->p), last, bbcc->cxt->fn[0]->file);
    750 	    something_written = True;
    751 	    for(jcc=bbcc->jmp[jmp].jcc_list; jcc; jcc=jcc->next_from) {
    752 		if (((jcc->jmpkind != jk_Call) && (jcc->call_counter >0)) ||
    753 		    (!CLG_(is_zero_cost)( CLG_(sets).full, jcc->cost )))
    754 		    fprint_jcc(fp, jcc, &(currCost->p), last, ecounter);
    755 	    }
    756 	}
    757     }
    758 
    759     /* update execution counter */
    760     if (jmp < bb->cjmp_count)
    761 	if (bb->jmp[jmp].instr == instr) {
    762 	    ecounter -= bbcc->jmp[jmp].ecounter;
    763 	    jmp++;
    764 	}
    765   }
    766 
    767   /* jCCs at end? If yes, dump cumulated line info first */
    768   jcc_count = 0;
    769   for(jcc=bbcc->jmp[jmp].jcc_list; jcc; jcc=jcc->next_from) {
    770       /* yes, if JCC only counts jmp arcs or cost >0 */
    771       if ( ((jcc->jmpkind != jk_Call) && (jcc->call_counter >0)) ||
    772 	   (!CLG_(is_zero_cost)( CLG_(sets).full, jcc->cost )))
    773 	  jcc_count++;
    774   }
    775 
    776   if ( (bbcc->skipped &&
    777 	!CLG_(is_zero_cost)(CLG_(sets).full, bbcc->skipped)) ||
    778        (jcc_count>0) ) {
    779 
    780     if (!CLG_(is_zero_cost)( CLG_(sets).full, currCost->cost )) {
    781       /* no need to switch buffers, as position is the same */
    782       fprint_apos(fp, &(currCost->p), last, bbcc->cxt->fn[0]->file);
    783       fprint_fcost(fp, currCost, last);
    784     }
    785 
    786     get_debug_pos(bbcc, bb_jmpaddr(bb), &(currCost->p));
    787     fprint_apos(fp, &(currCost->p), last, bbcc->cxt->fn[0]->file);
    788     something_written = True;
    789 
    790     /* first, print skipped costs for calls */
    791     if (bbcc->skipped && !CLG_(is_zero_cost)( CLG_(sets).full,
    792 					     bbcc->skipped )) {
    793       CLG_(add_and_zero_cost)( CLG_(sets).full,
    794 			      currCost->cost, bbcc->skipped );
    795 #if 0
    796       VG_(fprintf)(fp, "# Skipped\n");
    797 #endif
    798       fprint_fcost(fp, currCost, last);
    799     }
    800 
    801     if (jcc_count > 0)
    802 	for(jcc=bbcc->jmp[jmp].jcc_list; jcc; jcc=jcc->next_from) {
    803 	    CLG_ASSERT(jcc->jmp == jmp);
    804 	    if ( ((jcc->jmpkind != jk_Call) && (jcc->call_counter >0)) ||
    805 		 (!CLG_(is_zero_cost)( CLG_(sets).full, jcc->cost )))
    806 
    807 		fprint_jcc(fp, jcc, &(currCost->p), last, ecounter);
    808 	}
    809   }
    810 
    811   if (CLG_(clo).dump_bbs || CLG_(clo).dump_bb) {
    812     if (!CLG_(is_zero_cost)( CLG_(sets).full, currCost->cost )) {
    813       something_written = True;
    814 
    815       fprint_apos(fp, &(currCost->p), last, bbcc->cxt->fn[0]->file);
    816       fprint_fcost(fp, currCost, last);
    817     }
    818     if (CLG_(clo).dump_bbs) VG_(fprintf)(fp, "\n");
    819 
    820     /* when every cost was immediatly written, we must have done so,
    821      * as this function is only called when there's cost in a BBCC
    822      */
    823     CLG_ASSERT(something_written);
    824   }
    825 
    826   bbcc->ecounter_sum = 0;
    827   for(i=0; i<=bbcc->bb->cjmp_count; i++)
    828     bbcc->jmp[i].ecounter = 0;
    829   bbcc->ret_counter = 0;
    830 
    831   CLG_DEBUG(1, "- fprint_bbcc: JCCs %d\n", jcc_count);
    832 
    833   return something_written;
    834 }
    835 
    836 /* order by
    837  *  recursion,
    838  *  from->bb->obj, from->bb->fn
    839  *  obj, fn[0]->file, fn
    840  *  address
    841  */
    842 static int my_cmp(BBCC** pbbcc1, BBCC** pbbcc2)
    843 {
    844 #if 0
    845     return (*pbbcc1)->bb->offset - (*pbbcc2)->bb->offset;
    846 #else
    847     BBCC *bbcc1 = *pbbcc1;
    848     BBCC *bbcc2 = *pbbcc2;
    849     Context* cxt1 = bbcc1->cxt;
    850     Context* cxt2 = bbcc2->cxt;
    851     int off = 1;
    852 
    853     if (cxt1->fn[0]->file->obj != cxt2->fn[0]->file->obj)
    854 	return cxt1->fn[0]->file->obj - cxt2->fn[0]->file->obj;
    855 
    856     if (cxt1->fn[0]->file != cxt2->fn[0]->file)
    857 	return cxt1->fn[0]->file - cxt2->fn[0]->file;
    858 
    859     if (cxt1->fn[0] != cxt2->fn[0])
    860 	return cxt1->fn[0] - cxt2->fn[0];
    861 
    862     if (bbcc1->rec_index != bbcc2->rec_index)
    863 	return bbcc1->rec_index - bbcc2->rec_index;
    864 
    865     while((off < cxt1->size) && (off < cxt2->size)) {
    866 	fn_node* ffn1 = cxt1->fn[off];
    867 	fn_node* ffn2 = cxt2->fn[off];
    868 	if (ffn1->file->obj != ffn2->file->obj)
    869 	    return ffn1->file->obj - ffn2->file->obj;
    870 	if (ffn1 != ffn2)
    871 	    return ffn1 - ffn2;
    872 	off++;
    873     }
    874     if      (cxt1->size > cxt2->size) return 1;
    875     else if (cxt1->size < cxt2->size) return -1;
    876 
    877     return bbcc1->bb->offset - bbcc2->bb->offset;
    878 #endif
    879 }
    880 
    881 
    882 
    883 
    884 
    885 /* modified version of:
    886  *
    887  * qsort -- qsort interface implemented by faster quicksort.
    888  * J. L. Bentley and M. D. McIlroy, SPE 23 (1993) 1249-1265.
    889  * Copyright 1993, John Wiley.
    890 */
    891 
    892 static __inline__
    893 void swap(BBCC** a, BBCC** b)
    894 {
    895     BBCC* t;
    896     t = *a; *a = *b; *b = t;
    897 }
    898 
    899 #define min(x, y) ((x)<=(y) ? (x) : (y))
    900 
    901 static
    902 BBCC** med3(BBCC **a, BBCC **b, BBCC **c, int (*cmp)(BBCC**,BBCC**))
    903 {	return cmp(a, b) < 0 ?
    904 		  (cmp(b, c) < 0 ? b : cmp(a, c) < 0 ? c : a)
    905 		: (cmp(b, c) > 0 ? b : cmp(a, c) > 0 ? c : a);
    906 }
    907 
    908 static BBCC** qsort_start = 0;
    909 
    910 static void qsort(BBCC **a, int n, int (*cmp)(BBCC**,BBCC**))
    911 {
    912 	BBCC **pa, **pb, **pc, **pd, **pl, **pm, **pn, **pv;
    913 	int s, r;
    914 	BBCC* v;
    915 
    916 	CLG_DEBUG(8, "  qsort(%ld,%ld)\n", a-qsort_start + 0L, n + 0L);
    917 
    918 	if (n < 7) {	 /* Insertion sort on smallest arrays */
    919 		for (pm = a+1; pm < a+n; pm++)
    920 			for (pl = pm; pl > a && cmp(pl-1, pl) > 0; pl --)
    921 				swap(pl, pl-1);
    922 
    923 		CLG_DEBUGIF(8) {
    924 		    for (pm = a; pm < a+n; pm++) {
    925 			VG_(printf)("   %3ld BB %#lx, ",
    926                                     pm - qsort_start + 0L,
    927 				    bb_addr((*pm)->bb));
    928 			CLG_(print_cxt)(9, (*pm)->cxt, (*pm)->rec_index);
    929 		    }
    930 		}
    931 		return;
    932 	}
    933 	pm = a + n/2;    /* Small arrays, middle element */
    934 	if (n > 7) {
    935 		pl = a;
    936 		pn = a + (n-1);
    937 		if (n > 40) {    /* Big arrays, pseudomedian of 9 */
    938 			s = n/8;
    939 			pl = med3(pl, pl+s, pl+2*s, cmp);
    940 			pm = med3(pm-s, pm, pm+s, cmp);
    941 			pn = med3(pn-2*s, pn-s, pn, cmp);
    942 		}
    943 		pm = med3(pl, pm, pn, cmp); /* Mid-size, med of 3 */
    944 	}
    945 
    946 
    947 	v = *pm;
    948 	pv = &v;
    949 	pa = pb = a;
    950 	pc = pd = a + (n-1);
    951 	for (;;) {
    952 		while ((pb <= pc) && ((r=cmp(pb, pv)) <= 0)) {
    953 		    if (r==0) {
    954 			/* same as pivot, to start */
    955 			swap(pa,pb); pa++;
    956 		    }
    957 		    pb ++;
    958 		}
    959 		while ((pb <= pc) && ((r=cmp(pc, pv)) >= 0)) {
    960 		    if (r==0) {
    961 			/* same as pivot, to end */
    962 			swap(pc,pd); pd--;
    963 		    }
    964 		    pc --;
    965 		}
    966 		if (pb > pc) { break; }
    967 		swap(pb, pc);
    968 		pb ++;
    969 		pc --;
    970 	}
    971 	pb--;
    972 	pc++;
    973 
    974 	/* put pivot from start into middle */
    975 	if ((s = pa-a)>0) { for(r=0;r<s;r++) swap(a+r, pb+1-s+r); }
    976 	/* put pivot from end into middle */
    977 	if ((s = a+n-1-pd)>0) { for(r=0;r<s;r++) swap(pc+r, a+n-s+r); }
    978 
    979 	CLG_DEBUGIF(8) {
    980 	  VG_(printf)("   PV BB %#lx, ", bb_addr((*pv)->bb));
    981 	    CLG_(print_cxt)(9, (*pv)->cxt, (*pv)->rec_index);
    982 
    983 	    s = pb-pa+1;
    984 	    VG_(printf)("    Lower %ld - %ld:\n",
    985                         a-qsort_start + 0L,
    986                         a+s-1-qsort_start + 0L);
    987 	    for (r=0;r<s;r++) {
    988 		pm = a+r;
    989 		VG_(printf)("     %3ld BB %#lx, ",
    990 			    pm-qsort_start + 0L,
    991                             bb_addr((*pm)->bb));
    992 		CLG_(print_cxt)(9, (*pm)->cxt, (*pm)->rec_index);
    993 	    }
    994 
    995 	    s = pd-pc+1;
    996 	    VG_(printf)("    Upper %ld - %ld:\n",
    997 			a+n-s-qsort_start + 0L,
    998                         a+n-1-qsort_start + 0L);
    999 	    for (r=0;r<s;r++) {
   1000 		pm = a+n-s+r;
   1001 		VG_(printf)("     %3ld BB %#lx, ",
   1002 			    pm-qsort_start + 0L,
   1003                             bb_addr((*pm)->bb));
   1004 		CLG_(print_cxt)(9, (*pm)->cxt, (*pm)->rec_index);
   1005 	    }
   1006 	}
   1007 
   1008 	if ((s = pb+1-pa) > 1) qsort(a,     s, cmp);
   1009 	if ((s = pd+1-pc) > 1) qsort(a+n-s, s, cmp);
   1010 }
   1011 
   1012 
   1013 /* Helpers for prepare_dump */
   1014 
   1015 static Int    prepare_count;
   1016 static BBCC** prepare_ptr;
   1017 
   1018 
   1019 static void hash_addCount(BBCC* bbcc)
   1020 {
   1021   if ((bbcc->ecounter_sum > 0) || (bbcc->ret_counter>0))
   1022     prepare_count++;
   1023 }
   1024 
   1025 static void hash_addPtr(BBCC* bbcc)
   1026 {
   1027   if ((bbcc->ecounter_sum == 0) &&
   1028       (bbcc->ret_counter == 0)) return;
   1029 
   1030   *prepare_ptr = bbcc;
   1031   prepare_ptr++;
   1032 }
   1033 
   1034 
   1035 static void cs_addCount(thread_info* ti)
   1036 {
   1037   Int i;
   1038   BBCC* bbcc;
   1039 
   1040   /* add BBCCs with active call in call stack of current thread.
   1041    * update cost sums for active calls
   1042    */
   1043 
   1044   for(i = 0; i < CLG_(current_call_stack).sp; i++) {
   1045     call_entry* e = &(CLG_(current_call_stack).entry[i]);
   1046     if (e->jcc == 0) continue;
   1047 
   1048     CLG_(add_diff_cost_lz)( CLG_(sets).full, &(e->jcc->cost),
   1049 			   e->enter_cost, CLG_(current_state).cost);
   1050     bbcc = e->jcc->from;
   1051 
   1052     CLG_DEBUG(1, " [%2d] (tid %d), added active: %s\n",
   1053 	     i,CLG_(current_tid),bbcc->cxt->fn[0]->name);
   1054 
   1055     if (bbcc->ecounter_sum>0 || bbcc->ret_counter>0) {
   1056       /* already counted */
   1057       continue;
   1058     }
   1059     prepare_count++;
   1060   }
   1061 }
   1062 
   1063 static void cs_addPtr(thread_info* ti)
   1064 {
   1065   Int i;
   1066   BBCC* bbcc;
   1067 
   1068   /* add BBCCs with active call in call stack of current thread.
   1069    * update cost sums for active calls
   1070    */
   1071 
   1072   for(i = 0; i < CLG_(current_call_stack).sp; i++) {
   1073     call_entry* e = &(CLG_(current_call_stack).entry[i]);
   1074     if (e->jcc == 0) continue;
   1075 
   1076     bbcc = e->jcc->from;
   1077 
   1078     if (bbcc->ecounter_sum>0 || bbcc->ret_counter>0) {
   1079       /* already counted */
   1080       continue;
   1081     }
   1082 
   1083     *prepare_ptr = bbcc;
   1084     prepare_ptr++;
   1085   }
   1086 }
   1087 
   1088 
   1089 /**
   1090  * Put all BBCCs with costs into a sorted array.
   1091  * The returned arrays ends with a null pointer.
   1092  * Must be freed after dumping.
   1093  */
   1094 static
   1095 BBCC** prepare_dump(void)
   1096 {
   1097     BBCC **array;
   1098 
   1099     prepare_count = 0;
   1100 
   1101     /* if we do not separate among threads, this gives all */
   1102     /* count number of BBCCs with >0 executions */
   1103     CLG_(forall_bbccs)(hash_addCount);
   1104 
   1105     /* even if we do not separate among threads,
   1106      * call stacks are separated */
   1107     if (CLG_(clo).separate_threads)
   1108       cs_addCount(0);
   1109     else
   1110       CLG_(forall_threads)(cs_addCount);
   1111 
   1112     CLG_DEBUG(0, "prepare_dump: %d BBCCs\n", prepare_count);
   1113 
   1114     /* allocate bbcc array, insert BBCCs and sort */
   1115     prepare_ptr = array =
   1116       (BBCC**) CLG_MALLOC("cl.dump.pd.1",
   1117                           (prepare_count+1) * sizeof(BBCC*));
   1118 
   1119     CLG_(forall_bbccs)(hash_addPtr);
   1120 
   1121     if (CLG_(clo).separate_threads)
   1122       cs_addPtr(0);
   1123     else
   1124       CLG_(forall_threads)(cs_addPtr);
   1125 
   1126     CLG_ASSERT(array + prepare_count == prepare_ptr);
   1127 
   1128     /* end mark */
   1129     *prepare_ptr = 0;
   1130 
   1131     CLG_DEBUG(0,"             BBCCs inserted\n");
   1132 
   1133     qsort_start = array;
   1134     qsort(array, prepare_count, my_cmp);
   1135 
   1136     CLG_DEBUG(0,"             BBCCs sorted\n");
   1137 
   1138     return array;
   1139 }
   1140 
   1141 
   1142 
   1143 
   1144 static void fprint_cost_ln(VgFile *fp, const HChar* prefix,
   1145 			   const EventMapping* em, const ULong* cost)
   1146 {
   1147     HChar *mcost = CLG_(mappingcost_as_string)(em, cost);
   1148     VG_(fprintf)(fp, "%s%s\n", prefix, mcost);
   1149     CLG_FREE(mcost);
   1150 }
   1151 
   1152 static ULong bbs_done = 0;
   1153 static HChar* filename = 0;
   1154 
   1155 static
   1156 void file_err(void)
   1157 {
   1158    VG_(message)(Vg_UserMsg,
   1159                 "Error: can not open cache simulation output file `%s'\n",
   1160                 filename );
   1161    VG_(exit)(1);
   1162 }
   1163 
   1164 /**
   1165  * Create a new dump file and write header.
   1166  *
   1167  * Naming: <CLG_(clo).filename_base>.<pid>[.<part>][-<tid>]
   1168  *         <part> is skipped for final dump (trigger==0)
   1169  *         <tid>  is skipped for thread 1 with CLG_(clo).separate_threads=no
   1170  *
   1171  * Returns the file descriptor, and -1 on error (no write permission)
   1172  */
   1173 static VgFile *new_dumpfile(int tid, const HChar* trigger)
   1174 {
   1175     Bool appending = False;
   1176     int i;
   1177     FullCost sum = 0;
   1178     VgFile *fp;
   1179 
   1180     CLG_ASSERT(dumps_initialized);
   1181     CLG_ASSERT(filename != 0);
   1182 
   1183     if (!CLG_(clo).combine_dumps) {
   1184 	i = VG_(sprintf)(filename, "%s", out_file);
   1185 
   1186 	if (trigger)
   1187 	    i += VG_(sprintf)(filename+i, ".%d", out_counter);
   1188 
   1189 	if (CLG_(clo).separate_threads)
   1190 	    VG_(sprintf)(filename+i, "-%02d", tid);
   1191 
   1192 	fp = VG_(fopen)(filename, VKI_O_WRONLY|VKI_O_TRUNC, 0);
   1193     }
   1194     else {
   1195 	VG_(sprintf)(filename, "%s", out_file);
   1196         fp = VG_(fopen)(filename, VKI_O_WRONLY|VKI_O_APPEND, 0);
   1197 	if (fp && out_counter>1)
   1198 	    appending = True;
   1199     }
   1200 
   1201     if (fp == NULL) {
   1202 	fp = VG_(fopen)(filename, VKI_O_CREAT|VKI_O_WRONLY,
   1203                         VKI_S_IRUSR|VKI_S_IWUSR);
   1204 	if (fp == NULL) {
   1205 	    /* If the file can not be opened for whatever reason (conflict
   1206 	       between multiple supervised processes?), give up now. */
   1207 	    file_err();
   1208 	}
   1209     }
   1210 
   1211     CLG_DEBUG(2, "  new_dumpfile '%s'\n", filename);
   1212 
   1213     if (!appending)
   1214 	reset_dump_array();
   1215 
   1216 
   1217     if (!appending) {
   1218 	/* version */
   1219 	VG_(fprintf)(fp, "version: 1\n");
   1220 
   1221 	/* creator */
   1222 	VG_(fprintf)(fp, "creator: callgrind-" VERSION "\n");
   1223 
   1224 	/* "pid:" line */
   1225 	VG_(fprintf)(fp, "pid: %d\n", VG_(getpid)());
   1226 
   1227 	/* "cmd:" line */
   1228 	VG_(fprintf)(fp, "cmd: %s", cmdbuf);
   1229     }
   1230 
   1231     VG_(fprintf)(fp, "\npart: %d\n", out_counter);
   1232     if (CLG_(clo).separate_threads) {
   1233 	VG_(fprintf)(fp, "thread: %d\n", tid);
   1234     }
   1235 
   1236     /* "desc:" lines */
   1237     if (!appending) {
   1238         VG_(fprintf)(fp, "\n");
   1239 
   1240 #if 0
   1241 	/* Global options changing the tracing behaviour */
   1242 	VG_(fprintf)(fp, "\ndesc: Option: --skip-plt=%s\n",
   1243 		     CLG_(clo).skip_plt ? "yes" : "no");
   1244 	VG_(fprintf)(fp, "desc: Option: --collect-jumps=%s\n",
   1245 		     CLG_(clo).collect_jumps ? "yes" : "no");
   1246 	VG_(fprintf)(fp, "desc: Option: --separate-recs=%d\n",
   1247 		     CLG_(clo).separate_recursions);
   1248 	VG_(fprintf)(fp, "desc: Option: --separate-callers=%d\n",
   1249 		     CLG_(clo).separate_callers);
   1250 
   1251 	VG_(fprintf)(fp, "desc: Option: --dump-bbs=%s\n",
   1252 		     CLG_(clo).dump_bbs ? "yes" : "no");
   1253 	VG_(fprintf)(fp, "desc: Option: --separate-threads=%s\n",
   1254 		     CLG_(clo).separate_threads ? "yes" : "no");
   1255 #endif
   1256 
   1257 	(*CLG_(cachesim).dump_desc)(fp);
   1258     }
   1259 
   1260     VG_(fprintf)(fp, "\ndesc: Timerange: Basic block %llu - %llu\n",
   1261 		 bbs_done, CLG_(stat).bb_executions);
   1262 
   1263     VG_(fprintf)(fp, "desc: Trigger: %s\n",
   1264 		 trigger ? trigger : "Program termination");
   1265 
   1266 #if 0
   1267    /* Output function specific config
   1268     * FIXME */
   1269    for (i = 0; i < N_FNCONFIG_ENTRIES; i++) {
   1270        fnc = fnc_table[i];
   1271        while (fnc) {
   1272 	   if (fnc->skip) {
   1273 	       VG_(fprintf)(fp, "desc: Option: --fn-skip=%s\n", fnc->name);
   1274 	   }
   1275 	   if (fnc->dump_at_enter) {
   1276 	       VG_(fprintf)(fp, "desc: Option: --fn-dump-at-enter=%s\n",
   1277 			    fnc->name);
   1278 	   }
   1279 	   if (fnc->dump_at_leave) {
   1280 	       VG_(fprintf)(fp, "desc: Option: --fn-dump-at-leave=%s\n",
   1281 			    fnc->name);
   1282 	   }
   1283 	   if (fnc->separate_callers != CLG_(clo).separate_callers) {
   1284 	       VG_(fprintf)(fp, "desc: Option: --separate-callers%d=%s\n",
   1285 			    fnc->separate_callers, fnc->name);
   1286 	   }
   1287 	   if (fnc->separate_recursions != CLG_(clo).separate_recursions) {
   1288 	       VG_(fprintf)(fp, "desc: Option: --separate-recs%d=%s\n",
   1289 			    fnc->separate_recursions, fnc->name);
   1290 	   }
   1291 	   fnc = fnc->next;
   1292        }
   1293    }
   1294 #endif
   1295 
   1296    /* "positions:" line */
   1297    VG_(fprintf)(fp, "\npositions:%s%s%s\n",
   1298 		CLG_(clo).dump_instr ? " instr" : "",
   1299 		CLG_(clo).dump_bb    ? " bb" : "",
   1300 		CLG_(clo).dump_line  ? " line" : "");
   1301 
   1302    /* "events:" line */
   1303    HChar *evmap = CLG_(eventmapping_as_string)(CLG_(dumpmap));
   1304    VG_(fprintf)(fp, "events: %s\n", evmap);
   1305    VG_(free)(evmap);
   1306 
   1307    /* summary lines */
   1308    sum = CLG_(get_eventset_cost)( CLG_(sets).full );
   1309    CLG_(zero_cost)(CLG_(sets).full, sum);
   1310    if (CLG_(clo).separate_threads) {
   1311      thread_info* ti = CLG_(get_current_thread)();
   1312      CLG_(add_diff_cost)(CLG_(sets).full, sum, ti->lastdump_cost,
   1313 			   ti->states.entry[0]->cost);
   1314    }
   1315    else {
   1316      /* This function is called once for thread 1, where
   1317       * all costs are summed up when not dumping separate per thread.
   1318       * But this is not true for summary: we need to add all threads.
   1319       */
   1320      int t;
   1321      thread_info** thr = CLG_(get_threads)();
   1322      for(t=1;t<VG_N_THREADS;t++) {
   1323        if (!thr[t]) continue;
   1324        CLG_(add_diff_cost)(CLG_(sets).full, sum,
   1325 			  thr[t]->lastdump_cost,
   1326 			  thr[t]->states.entry[0]->cost);
   1327      }
   1328    }
   1329    fprint_cost_ln(fp, "summary: ", CLG_(dumpmap), sum);
   1330 
   1331    /* all dumped cost will be added to total_fcc */
   1332    CLG_(init_cost_lz)( CLG_(sets).full, &dump_total_cost );
   1333 
   1334    VG_(fprintf)(fp, "\n\n");
   1335 
   1336    if (VG_(clo_verbosity) > 1)
   1337        VG_(message)(Vg_DebugMsg, "Dump to %s\n", filename);
   1338 
   1339    return fp;
   1340 }
   1341 
   1342 
   1343 static void close_dumpfile(VgFile *fp)
   1344 {
   1345     if (fp == NULL) return;
   1346 
   1347     fprint_cost_ln(fp, "totals: ", CLG_(dumpmap),
   1348 		   dump_total_cost);
   1349     //fprint_fcc_ln(fp, "summary: ", &dump_total_fcc);
   1350     CLG_(add_cost_lz)(CLG_(sets).full,
   1351 		     &CLG_(total_cost), dump_total_cost);
   1352 
   1353     VG_(fclose)(fp);
   1354 
   1355     if (filename[0] == '.') {
   1356 	if (-1 == VG_(rename) (filename, filename+1)) {
   1357 	    /* Can not rename to correct file name: give out warning */
   1358 	    VG_(message)(Vg_DebugMsg, "Warning: Can not rename .%s to %s\n",
   1359 			 filename, filename);
   1360        }
   1361    }
   1362 }
   1363 
   1364 
   1365 /* Helper for print_bbccs */
   1366 
   1367 static const HChar* print_trigger;
   1368 
   1369 static void print_bbccs_of_thread(thread_info* ti)
   1370 {
   1371   BBCC **p, **array;
   1372   FnPos lastFnPos;
   1373   AddrPos lastAPos;
   1374 
   1375   CLG_DEBUG(1, "+ print_bbccs(tid %d)\n", CLG_(current_tid));
   1376 
   1377   VgFile *print_fp = new_dumpfile(CLG_(current_tid), print_trigger);
   1378   if (print_fp == NULL) {
   1379     CLG_DEBUG(1, "- print_bbccs(tid %d): No output...\n", CLG_(current_tid));
   1380     return;
   1381   }
   1382 
   1383   p = array = prepare_dump();
   1384   init_fpos(&lastFnPos);
   1385   init_apos(&lastAPos, 0, 0, 0);
   1386 
   1387   while(1) {
   1388 
   1389     /* on context/function change, print old cost buffer before */
   1390     if (lastFnPos.cxt && ((*p==0) ||
   1391 			 (lastFnPos.cxt != (*p)->cxt) ||
   1392 			 (lastFnPos.rec_index != (*p)->rec_index))) {
   1393       if (!CLG_(is_zero_cost)( CLG_(sets).full, ccSum[currSum].cost )) {
   1394 	/* no need to switch buffers, as position is the same */
   1395 	fprint_apos(print_fp, &(ccSum[currSum].p), &lastAPos,
   1396 		    lastFnPos.cxt->fn[0]->file);
   1397 	fprint_fcost(print_fp, &ccSum[currSum], &lastAPos);
   1398       }
   1399 
   1400       if (ccSum[currSum].p.file != lastFnPos.cxt->fn[0]->file) {
   1401 	/* switch back to file of function */
   1402 	print_file(print_fp, "fe=", lastFnPos.cxt->fn[0]->file);
   1403       }
   1404       VG_(fprintf)(print_fp, "\n");
   1405     }
   1406 
   1407     if (*p == 0) break;
   1408 
   1409     if (print_fn_pos(print_fp, &lastFnPos, *p)) {
   1410 
   1411       /* new function */
   1412       init_apos(&lastAPos, 0, 0, (*p)->cxt->fn[0]->file);
   1413       init_fcost(&ccSum[0], 0, 0, 0);
   1414       init_fcost(&ccSum[1], 0, 0, 0);
   1415       currSum = 0;
   1416     }
   1417 
   1418     if (CLG_(clo).dump_bbs) {
   1419 	/* FIXME: Specify Object of BB if different to object of fn */
   1420         int i;
   1421 	ULong ecounter = (*p)->ecounter_sum;
   1422         VG_(fprintf)(print_fp, "bb=%#lx ", (*p)->bb->offset);
   1423 	for(i = 0; i<(*p)->bb->cjmp_count;i++) {
   1424 	    VG_(fprintf)(print_fp, "%d %llu ",
   1425 				(*p)->bb->jmp[i].instr,
   1426 				ecounter);
   1427 	    ecounter -= (*p)->jmp[i].ecounter;
   1428 	}
   1429 	VG_(fprintf)(print_fp, "%d %llu\n",
   1430 		     (*p)->bb->instr_count,
   1431 		     ecounter);
   1432     }
   1433 
   1434     fprint_bbcc(print_fp, *p, &lastAPos);
   1435 
   1436     p++;
   1437   }
   1438 
   1439   close_dumpfile(print_fp);
   1440   VG_(free)(array);
   1441 
   1442   /* set counters of last dump */
   1443   CLG_(copy_cost)( CLG_(sets).full, ti->lastdump_cost,
   1444 		  CLG_(current_state).cost );
   1445 
   1446   CLG_DEBUG(1, "- print_bbccs(tid %d)\n", CLG_(current_tid));
   1447 }
   1448 
   1449 
   1450 static void print_bbccs(const HChar* trigger, Bool only_current_thread)
   1451 {
   1452   init_dump_array();
   1453   init_debug_cache();
   1454 
   1455   print_trigger = trigger;
   1456 
   1457   if (!CLG_(clo).separate_threads) {
   1458     /* All BBCC/JCC costs is stored for thread 1 */
   1459     Int orig_tid = CLG_(current_tid);
   1460 
   1461     CLG_(switch_thread)(1);
   1462     print_bbccs_of_thread( CLG_(get_current_thread)() );
   1463     CLG_(switch_thread)(orig_tid);
   1464   }
   1465   else if (only_current_thread)
   1466     print_bbccs_of_thread( CLG_(get_current_thread)() );
   1467   else
   1468     CLG_(forall_threads)(print_bbccs_of_thread);
   1469 
   1470   free_dump_array();
   1471 }
   1472 
   1473 
   1474 void CLG_(dump_profile)(const HChar* trigger, Bool only_current_thread)
   1475 {
   1476    CLG_DEBUG(2, "+ dump_profile(Trigger '%s')\n",
   1477 	    trigger ? trigger : "Prg.Term.");
   1478 
   1479    CLG_(init_dumps)();
   1480 
   1481    if (VG_(clo_verbosity) > 1)
   1482        VG_(message)(Vg_DebugMsg, "Start dumping at BB %llu (%s)...\n",
   1483 		    CLG_(stat).bb_executions,
   1484 		    trigger ? trigger : "Prg.Term.");
   1485 
   1486    out_counter++;
   1487 
   1488    print_bbccs(trigger, only_current_thread);
   1489 
   1490    bbs_done = CLG_(stat).bb_executions++;
   1491 
   1492    if (VG_(clo_verbosity) > 1)
   1493      VG_(message)(Vg_DebugMsg, "Dumping done.\n");
   1494 }
   1495 
   1496 /* Copy command to cmd buffer. We want to original command line
   1497  * (can change at runtime)
   1498  */
   1499 static
   1500 void init_cmdbuf(void)
   1501 {
   1502   SizeT size;
   1503   Int i,j;
   1504 
   1505   /* Pass #1: How many bytes do we need? */
   1506   size  = 1;  // leading ' '
   1507   size += VG_(strlen)( VG_(args_the_exename) );
   1508   for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
   1509      const HChar *arg = *(HChar**)VG_(indexXA)( VG_(args_for_client), i );
   1510      size += 1;   // separator ' '
   1511      // escape NL in arguments to not break dump format
   1512      for(j=0; arg[j]; j++)
   1513        switch(arg[j]) {
   1514        case '\n':
   1515        case '\\':
   1516 	 size++; // fall through
   1517        default:
   1518 	 size++;
   1519        }
   1520   }
   1521 
   1522   cmdbuf = CLG_MALLOC("cl.dump.ic.1", size + 1);  // +1 for '\0'
   1523 
   1524   /* Pass #2: Build up the string */
   1525   size = VG_(sprintf)(cmdbuf, " %s", VG_(args_the_exename));
   1526 
   1527   for(i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
   1528      const HChar *arg = * (HChar**) VG_(indexXA)( VG_(args_for_client), i );
   1529      cmdbuf[size++] = ' ';
   1530      for(j=0; arg[j]; j++)
   1531        switch(arg[j]) {
   1532        case '\n':
   1533 	 cmdbuf[size++] = '\\';
   1534 	 cmdbuf[size++] = 'n';
   1535 	 break;
   1536        case '\\':
   1537 	 cmdbuf[size++] = '\\';
   1538 	 cmdbuf[size++] = '\\';
   1539 	 break;
   1540        default:
   1541 	 cmdbuf[size++] = arg[j];
   1542 	 break;
   1543        }
   1544   }
   1545   cmdbuf[size] = '\0';
   1546 }
   1547 
   1548 /*
   1549  * Set up file names for dump output: <out_file>.
   1550  * <out_file> is derived from the output format string, which defaults
   1551  * to "callgrind.out.%p", where %p is replaced with the PID.
   1552  * For the final file name, on intermediate dumps a counter is appended,
   1553  * and further, if separate dumps per thread are requested, the thread ID.
   1554  *
   1555  * <out_file> always starts with a full absolute path.
   1556  * If the output format string represents a relative path, the current
   1557  * working directory at program start is used.
   1558  *
   1559  * This function has to be called every time a profile dump is generated
   1560  * to be able to react on PID changes.
   1561  */
   1562 void CLG_(init_dumps)()
   1563 {
   1564    SysRes res;
   1565 
   1566    static int thisPID = 0;
   1567    int currentPID = VG_(getpid)();
   1568    if (currentPID == thisPID) {
   1569        /* already initialized, and no PID change */
   1570        CLG_ASSERT(out_file != 0);
   1571        return;
   1572    }
   1573    thisPID = currentPID;
   1574 
   1575    if (!CLG_(clo).out_format)
   1576      CLG_(clo).out_format = DEFAULT_OUTFORMAT;
   1577 
   1578    /* If a file name was already set, clean up before */
   1579    if (out_file) {
   1580        VG_(free)(out_file);
   1581        VG_(free)(filename);
   1582        out_counter = 0;
   1583    }
   1584 
   1585    // Setup output filename.
   1586    out_file =
   1587        VG_(expand_file_name)("--callgrind-out-file", CLG_(clo).out_format);
   1588 
   1589    /* allocate space big enough for final filenames */
   1590    filename = (HChar*) CLG_MALLOC("cl.dump.init_dumps.2",
   1591                                  VG_(strlen)(out_file)+32);
   1592 
   1593    /* Make sure the output base file can be written.
   1594     * This is used for the dump at program termination.
   1595     * We stop with an error here if we can not create the
   1596     * file: This is probably because of missing rights,
   1597     * and trace parts wouldn't be allowed to be written, too.
   1598     */
   1599     VG_(strcpy)(filename, out_file);
   1600     res = VG_(open)(filename, VKI_O_WRONLY|VKI_O_TRUNC, 0);
   1601     if (sr_isError(res)) {
   1602 	res = VG_(open)(filename, VKI_O_CREAT|VKI_O_WRONLY,
   1603 		       VKI_S_IRUSR|VKI_S_IWUSR);
   1604 	if (sr_isError(res)) {
   1605 	    file_err();
   1606 	}
   1607     }
   1608     if (!sr_isError(res)) VG_(close)( (Int)sr_Res(res) );
   1609 
   1610     if (!dumps_initialized)
   1611 	init_cmdbuf();
   1612 
   1613     dumps_initialized = True;
   1614 }
   1615