filter_shell_output: filter out "Exec format error" added by newer bash.
[valgrind.git] / callgrind / dump.c
blob5cc1d27296026dade33408c2913c91f983b6f3e1
1 /*--------------------------------------------------------------------*/
2 /*--- Callgrind ---*/
3 /*--- dump.c ---*/
4 /*--------------------------------------------------------------------*/
6 /*
7 This file is part of Callgrind, a Valgrind tool for call tracing.
9 Copyright (C) 2002-2013, Josef Weidendorfer (Josef.Weidendorfer@gmx.de)
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.
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.
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.
26 The GNU General Public License is contained in the file COPYING.
29 #include "config.h"
30 #include "global.h"
32 #include "pub_tool_threadstate.h"
33 #include "pub_tool_libcfile.h"
36 /* Dump Part Counter */
37 static Int out_counter = 0;
39 static HChar* out_file = 0;
40 static Bool dumps_initialized = False;
42 /* Command */
43 static HChar cmdbuf[BUF_LEN];
45 /* Total reads/writes/misses sum over all dumps and threads.
46 * Updated during CC traversal at dump time.
48 FullCost CLG_(total_cost) = 0;
49 static FullCost dump_total_cost = 0;
51 EventMapping* CLG_(dumpmap) = 0;
53 /* Temporary output buffer for
54 * print_fn_pos, fprint_apos, fprint_fcost, fprint_jcc,
55 * fprint_fcc_ln, dump_run_info, dump_state_info
57 static HChar outbuf[FILENAME_LEN + FN_NAME_LEN + OBJ_NAME_LEN + COSTS_LEN];
59 Int CLG_(get_dump_counter)(void)
61 return out_counter;
64 /*------------------------------------------------------------*/
65 /*--- Output file related stuff ---*/
66 /*------------------------------------------------------------*/
68 /* Boolean dumping array */
69 static Bool* dump_array = 0;
70 static Int dump_array_size = 0;
71 static Bool* obj_dumped = 0;
72 static Bool* file_dumped = 0;
73 static Bool* fn_dumped = 0;
74 static Bool* cxt_dumped = 0;
76 static
77 void reset_dump_array(void)
79 int i;
81 CLG_ASSERT(dump_array != 0);
83 for(i=0;i<dump_array_size;i++)
84 dump_array[i] = False;
87 static
88 void init_dump_array(void)
90 dump_array_size = CLG_(stat).distinct_objs +
91 CLG_(stat).distinct_files +
92 CLG_(stat).distinct_fns +
93 CLG_(stat).context_counter;
94 CLG_ASSERT(dump_array == 0);
95 dump_array = (Bool*) CLG_MALLOC("cl.dump.ida.1",
96 dump_array_size * sizeof(Bool));
97 obj_dumped = dump_array;
98 file_dumped = obj_dumped + CLG_(stat).distinct_objs;
99 fn_dumped = file_dumped + CLG_(stat).distinct_files;
100 cxt_dumped = fn_dumped + CLG_(stat).distinct_fns;
102 reset_dump_array();
104 CLG_DEBUG(1, " init_dump_array: size %d\n", dump_array_size);
107 static __inline__
108 void free_dump_array(void)
110 CLG_ASSERT(dump_array != 0);
111 VG_(free)(dump_array);
113 dump_array = 0;
114 obj_dumped = 0;
115 file_dumped = 0;
116 fn_dumped = 0;
117 cxt_dumped = 0;
121 /* Initialize to an invalid position */
122 static __inline__
123 void init_fpos(FnPos* p)
125 p->file = 0;
126 p->fn = 0;
127 p->obj = 0;
128 p->cxt = 0;
129 p->rec_index = 0;
133 #if 0
134 static __inline__
135 static void my_fwrite(Int fd, const HChar* buf, Int len)
137 VG_(write)(fd, buf, len);
139 #else
141 #define FWRITE_BUFSIZE 32000
142 #define FWRITE_THROUGH 10000
143 static HChar fwrite_buf[FWRITE_BUFSIZE];
144 static Int fwrite_pos;
145 static Int fwrite_fd = -1;
147 static __inline__
148 void fwrite_flush(void)
150 if ((fwrite_fd>=0) && (fwrite_pos>0))
151 VG_(write)(fwrite_fd, fwrite_buf, fwrite_pos);
152 fwrite_pos = 0;
155 static void my_fwrite(Int fd, const HChar* buf, Int len)
157 if (fwrite_fd != fd) {
158 fwrite_flush();
159 fwrite_fd = fd;
161 if (len > FWRITE_THROUGH) {
162 fwrite_flush();
163 VG_(write)(fd, buf, len);
164 return;
166 if (FWRITE_BUFSIZE - fwrite_pos <= len) fwrite_flush();
167 VG_(strncpy)(fwrite_buf + fwrite_pos, buf, len);
168 fwrite_pos += len;
170 #endif
173 static void print_obj(HChar* buf, obj_node* obj)
175 //int n;
177 if (CLG_(clo).compress_strings) {
178 CLG_ASSERT(obj_dumped != 0);
179 if (obj_dumped[obj->number])
180 /*n =*/ VG_(sprintf)(buf, "(%d)\n", obj->number);
181 else {
182 /*n =*/ VG_(sprintf)(buf, "(%d) %s\n",
183 obj->number, obj->name);
186 else
187 /*n =*/ VG_(sprintf)(buf, "%s\n", obj->name);
189 #if 0
190 /* add mapping parameters the first time a object is dumped
191 * format: mp=0xSTART SIZE 0xOFFSET */
192 if (!obj_dumped[obj->number]) {
193 obj_dumped[obj->number];
194 VG_(sprintf)(buf+n, "mp=%p %p %p\n",
195 pos->obj->start, pos->obj->size, pos->obj->offset);
197 #else
198 obj_dumped[obj->number] = True;
199 #endif
202 static void print_file(HChar* buf, file_node* file)
204 if (CLG_(clo).compress_strings) {
205 CLG_ASSERT(file_dumped != 0);
206 if (file_dumped[file->number])
207 VG_(sprintf)(buf, "(%d)\n", file->number);
208 else {
209 VG_(sprintf)(buf, "(%d) %s\n",
210 file->number, file->name);
211 file_dumped[file->number] = True;
214 else
215 VG_(sprintf)(buf, "%s\n", file->name);
219 * tag can be "fn", "cfn", "jfn"
221 static void print_fn(Int fd, HChar* buf, const HChar* tag, fn_node* fn)
223 int p;
224 p = VG_(sprintf)(buf, "%s=",tag);
225 if (CLG_(clo).compress_strings) {
226 CLG_ASSERT(fn_dumped != 0);
227 if (fn_dumped[fn->number])
228 p += VG_(sprintf)(buf+p, "(%d)\n", fn->number);
229 else {
230 p += VG_(sprintf)(buf+p, "(%d) %s\n",
231 fn->number, fn->name);
232 fn_dumped[fn->number] = True;
235 else
236 p += VG_(sprintf)(buf+p, "%s\n", fn->name);
238 my_fwrite(fd, buf, p);
241 static void print_mangled_fn(Int fd, HChar* buf, const HChar* tag,
242 Context* cxt, int rec_index)
244 int p, i;
246 if (CLG_(clo).compress_strings && CLG_(clo).compress_mangled) {
248 int n;
249 Context* last;
251 CLG_ASSERT(cxt_dumped != 0);
252 if (cxt_dumped[cxt->base_number+rec_index]) {
253 p = VG_(sprintf)(buf, "%s=(%d)\n",
254 tag, cxt->base_number + rec_index);
255 my_fwrite(fd, buf, p);
256 return;
259 last = 0;
260 /* make sure that for all context parts compressed data is written */
261 for(i=cxt->size;i>0;i--) {
262 CLG_ASSERT(cxt->fn[i-1]->pure_cxt != 0);
263 n = cxt->fn[i-1]->pure_cxt->base_number;
264 if (cxt_dumped[n]) continue;
265 p = VG_(sprintf)(buf, "%s=(%d) %s\n",
266 tag, n, cxt->fn[i-1]->name);
267 my_fwrite(fd, buf, p);
269 cxt_dumped[n] = True;
270 last = cxt->fn[i-1]->pure_cxt;
272 /* If the last context was the context to print, we are finished */
273 if ((last == cxt) && (rec_index == 0)) return;
275 p = VG_(sprintf)(buf, "%s=(%d) (%d)", tag,
276 cxt->base_number + rec_index,
277 cxt->fn[0]->pure_cxt->base_number);
278 if (rec_index >0)
279 p += VG_(sprintf)(buf+p, "'%d", rec_index +1);
280 for(i=1;i<cxt->size;i++)
281 p += VG_(sprintf)(buf+p, "'(%d)",
282 cxt->fn[i]->pure_cxt->base_number);
283 p += VG_(sprintf)(buf+p, "\n");
284 my_fwrite(fd, buf, p);
286 cxt_dumped[cxt->base_number+rec_index] = True;
287 return;
291 p = VG_(sprintf)(buf, "%s=", tag);
292 if (CLG_(clo).compress_strings) {
293 CLG_ASSERT(cxt_dumped != 0);
294 if (cxt_dumped[cxt->base_number+rec_index]) {
295 p += VG_(sprintf)(buf+p, "(%d)\n", cxt->base_number + rec_index);
296 my_fwrite(fd, buf, p);
297 return;
299 else {
300 p += VG_(sprintf)(buf+p, "(%d) ", cxt->base_number + rec_index);
301 cxt_dumped[cxt->base_number+rec_index] = True;
305 p += VG_(sprintf)(buf+p, "%s", cxt->fn[0]->name);
306 if (rec_index >0)
307 p += VG_(sprintf)(buf+p, "'%d", rec_index +1);
308 for(i=1;i<cxt->size;i++)
309 p += VG_(sprintf)(buf+p, "'%s", cxt->fn[i]->name);
311 p += VG_(sprintf)(buf+p, "\n");
312 my_fwrite(fd, buf, p);
318 * Print function position of the BBCC, but only print info differing to
319 * the <last> position, update <last>
320 * Return True if something changes.
322 static Bool print_fn_pos(int fd, FnPos* last, BBCC* bbcc)
324 Bool res = False;
326 CLG_ASSERT(bbcc && bbcc->cxt);
328 CLG_DEBUGIF(3) {
329 CLG_DEBUG(2, "+ print_fn_pos: ");
330 CLG_(print_cxt)(16, bbcc->cxt, bbcc->rec_index);
333 if (!CLG_(clo).mangle_names) {
334 if (last->rec_index != bbcc->rec_index) {
335 VG_(sprintf)(outbuf, "rec=%d\n\n", bbcc->rec_index);
336 my_fwrite(fd, outbuf, VG_(strlen)(outbuf));
337 last->rec_index = bbcc->rec_index;
338 last->cxt = 0; /* reprint context */
339 res = True;
342 if (last->cxt != bbcc->cxt) {
343 fn_node* last_from = (last->cxt && last->cxt->size >1) ?
344 last->cxt->fn[1] : 0;
345 fn_node* curr_from = (bbcc->cxt->size >1) ?
346 bbcc->cxt->fn[1] : 0;
347 if (curr_from == 0) {
348 if (last_from != 0) {
349 /* switch back to no context */
350 VG_(sprintf)(outbuf, "frfn=(spontaneous)\n");
351 my_fwrite(fd, outbuf, VG_(strlen)(outbuf));
352 res = True;
355 else if (last_from != curr_from) {
356 print_fn(fd,outbuf,"frfn", curr_from);
357 res = True;
359 last->cxt = bbcc->cxt;
363 if (last->obj != bbcc->cxt->fn[0]->file->obj) {
364 VG_(sprintf)(outbuf, "ob=");
365 print_obj(outbuf+3, bbcc->cxt->fn[0]->file->obj);
366 my_fwrite(fd, outbuf, VG_(strlen)(outbuf));
367 last->obj = bbcc->cxt->fn[0]->file->obj;
368 res = True;
371 if (last->file != bbcc->cxt->fn[0]->file) {
372 VG_(sprintf)(outbuf, "fl=");
373 print_file(outbuf+3, bbcc->cxt->fn[0]->file);
374 my_fwrite(fd, outbuf, VG_(strlen)(outbuf));
375 last->file = bbcc->cxt->fn[0]->file;
376 res = True;
379 if (!CLG_(clo).mangle_names) {
380 if (last->fn != bbcc->cxt->fn[0]) {
381 print_fn(fd,outbuf, "fn", bbcc->cxt->fn[0]);
382 last->fn = bbcc->cxt->fn[0];
383 res = True;
386 else {
387 /* Print mangled name if context or rec_index changes */
388 if ((last->rec_index != bbcc->rec_index) ||
389 (last->cxt != bbcc->cxt)) {
391 print_mangled_fn(fd, outbuf, "fn", bbcc->cxt, bbcc->rec_index);
392 last->fn = bbcc->cxt->fn[0];
393 last->rec_index = bbcc->rec_index;
394 res = True;
398 last->cxt = bbcc->cxt;
400 CLG_DEBUG(2, "- print_fn_pos: %s\n", res ? "changed" : "");
402 return res;
405 /* the debug lookup cache is useful if BBCC for same BB are
406 * dumped directly in a row. This is a direct mapped cache.
408 #define DEBUG_CACHE_SIZE 1777
410 static Addr debug_cache_addr[DEBUG_CACHE_SIZE];
411 static file_node* debug_cache_file[DEBUG_CACHE_SIZE];
412 static int debug_cache_line[DEBUG_CACHE_SIZE];
413 static Bool debug_cache_info[DEBUG_CACHE_SIZE];
415 static __inline__
416 void init_debug_cache(void)
418 int i;
419 for(i=0;i<DEBUG_CACHE_SIZE;i++) {
420 debug_cache_addr[i] = 0;
421 debug_cache_file[i] = 0;
422 debug_cache_line[i] = 0;
423 debug_cache_info[i] = 0;
427 static /* __inline__ */
428 Bool get_debug_pos(BBCC* bbcc, Addr addr, AddrPos* p)
430 HChar file[FILENAME_LEN];
431 HChar dir[FILENAME_LEN];
432 Bool found_file_line, found_dirname;
434 int cachepos = addr % DEBUG_CACHE_SIZE;
436 if (debug_cache_addr[cachepos] == addr) {
437 p->line = debug_cache_line[cachepos];
438 p->file = debug_cache_file[cachepos];
439 found_file_line = debug_cache_info[cachepos];
441 else {
442 found_file_line = VG_(get_filename_linenum)(addr,
443 file, FILENAME_LEN,
444 dir, FILENAME_LEN,
445 &found_dirname,
446 &(p->line));
447 if (!found_file_line) {
448 VG_(strcpy)(file, "???");
449 p->line = 0;
451 if (found_dirname) {
452 // +1 for the '/'.
453 CLG_ASSERT(VG_(strlen)(dir) + VG_(strlen)(file) + 1 < FILENAME_LEN);
454 VG_(strcat)(dir, "/"); // Append '/'
455 VG_(strcat)(dir, file); // Append file to dir
456 VG_(strcpy)(file, dir); // Move dir+file to file
458 p->file = CLG_(get_file_node)(bbcc->bb->obj, file);
460 debug_cache_info[cachepos] = found_file_line;
461 debug_cache_addr[cachepos] = addr;
462 debug_cache_line[cachepos] = p->line;
463 debug_cache_file[cachepos] = p->file;
466 /* Address offset from bbcc start address */
467 p->addr = addr - bbcc->bb->obj->offset;
468 p->bb_addr = bbcc->bb->offset;
470 CLG_DEBUG(3, " get_debug_pos(%#lx): BB %#lx, fn '%s', file '%s', line %u\n",
471 addr, bb_addr(bbcc->bb), bbcc->cxt->fn[0]->name,
472 p->file->name, p->line);
474 return found_file_line;
478 /* copy file position and init cost */
479 static void init_apos(AddrPos* p, Addr addr, Addr bbaddr, file_node* file)
481 p->addr = addr;
482 p->bb_addr = bbaddr;
483 p->file = file;
484 p->line = 0;
487 static void copy_apos(AddrPos* dst, AddrPos* src)
489 dst->addr = src->addr;
490 dst->bb_addr = src->bb_addr;
491 dst->file = src->file;
492 dst->line = src->line;
495 /* copy file position and init cost */
496 static void init_fcost(AddrCost* c, Addr addr, Addr bbaddr, file_node* file)
498 init_apos( &(c->p), addr, bbaddr, file);
499 /* FIXME: This is a memory leak as a AddrCost is inited multiple times */
500 c->cost = CLG_(get_eventset_cost)( CLG_(sets).full );
501 CLG_(init_cost)( CLG_(sets).full, c->cost );
506 * print position change inside of a BB (last -> curr)
507 * this doesn't update last to curr!
509 static void fprint_apos(Int fd, AddrPos* curr, AddrPos* last, file_node* func_file)
511 CLG_ASSERT(curr->file != 0);
512 CLG_DEBUG(2, " print_apos(file '%s', line %d, bb %#lx, addr %#lx) fnFile '%s'\n",
513 curr->file->name, curr->line, curr->bb_addr, curr->addr,
514 func_file->name);
516 if (curr->file != last->file) {
518 /* if we switch back to orig file, use fe=... */
519 if (curr->file == func_file)
520 VG_(sprintf)(outbuf, "fe=");
521 else
522 VG_(sprintf)(outbuf, "fi=");
523 print_file(outbuf+3, curr->file);
524 my_fwrite(fd, outbuf, VG_(strlen)(outbuf));
527 if (CLG_(clo).dump_bbs) {
528 if (curr->line != last->line) {
529 VG_(sprintf)(outbuf, "ln=%d\n", curr->line);
530 my_fwrite(fd, outbuf, VG_(strlen)(outbuf));
538 * Print a position.
539 * This prints out differences if allowed
541 * This doesn't set last to curr afterwards!
543 static
544 void fprint_pos(Int fd, AddrPos* curr, AddrPos* last)
546 if (0) //CLG_(clo).dump_bbs)
547 VG_(sprintf)(outbuf, "%lu ", curr->addr - curr->bb_addr);
548 else {
549 int p = 0;
550 if (CLG_(clo).dump_instr) {
551 int diff = curr->addr - last->addr;
552 if ( CLG_(clo).compress_pos && (last->addr >0) &&
553 (diff > -100) && (diff < 100)) {
554 if (diff >0)
555 p = VG_(sprintf)(outbuf, "+%d ", diff);
556 else if (diff==0)
557 p = VG_(sprintf)(outbuf, "* ");
558 else
559 p = VG_(sprintf)(outbuf, "%d ", diff);
561 else
562 p = VG_(sprintf)(outbuf, "%#lx ", curr->addr);
565 if (CLG_(clo).dump_bb) {
566 int diff = curr->bb_addr - last->bb_addr;
567 if ( CLG_(clo).compress_pos && (last->bb_addr >0) &&
568 (diff > -100) && (diff < 100)) {
569 if (diff >0)
570 p += VG_(sprintf)(outbuf+p, "+%d ", diff);
571 else if (diff==0)
572 p += VG_(sprintf)(outbuf+p, "* ");
573 else
574 p += VG_(sprintf)(outbuf+p, "%d ", diff);
576 else
577 p += VG_(sprintf)(outbuf+p, "%#lx ", curr->bb_addr);
580 if (CLG_(clo).dump_line) {
581 int diff = curr->line - last->line;
582 if ( CLG_(clo).compress_pos && (last->line >0) &&
583 (diff > -100) && (diff < 100)) {
585 if (diff >0)
586 VG_(sprintf)(outbuf+p, "+%d ", diff);
587 else if (diff==0)
588 VG_(sprintf)(outbuf+p, "* ");
589 else
590 VG_(sprintf)(outbuf+p, "%d ", diff);
592 else
593 VG_(sprintf)(outbuf+p, "%u ", curr->line);
596 my_fwrite(fd, outbuf, VG_(strlen)(outbuf));
601 * Print events.
604 static
605 void fprint_cost(int fd, EventMapping* es, ULong* cost)
607 int p = CLG_(sprint_mappingcost)(outbuf, es, cost);
608 VG_(sprintf)(outbuf+p, "\n");
609 my_fwrite(fd, outbuf, VG_(strlen)(outbuf));
610 return;
615 /* Write the cost of a source line; only that parts of the source
616 * position are written that changed relative to last written position.
617 * funcPos is the source position of the first line of actual function.
618 * Something is written only if cost != 0; returns True in this case.
620 static void fprint_fcost(Int fd, AddrCost* c, AddrPos* last)
622 CLG_DEBUGIF(3) {
623 CLG_DEBUG(2, " print_fcost(file '%s', line %d, bb %#lx, addr %#lx):\n",
624 c->p.file->name, c->p.line, c->p.bb_addr, c->p.addr);
625 CLG_(print_cost)(-5, CLG_(sets).full, c->cost);
628 fprint_pos(fd, &(c->p), last);
629 copy_apos( last, &(c->p) ); /* update last to current position */
631 fprint_cost(fd, CLG_(dumpmap), c->cost);
633 /* add cost to total */
634 CLG_(add_and_zero_cost)( CLG_(sets).full, dump_total_cost, c->cost );
638 /* Write out the calls from jcc (at pos)
640 static void fprint_jcc(Int fd, jCC* jcc, AddrPos* curr, AddrPos* last, ULong ecounter)
642 static AddrPos target;
643 file_node* file;
644 obj_node* obj;
646 CLG_DEBUGIF(2) {
647 CLG_DEBUG(2, " fprint_jcc (jkind %d)\n", jcc->jmpkind);
648 CLG_(print_jcc)(-10, jcc);
651 CLG_ASSERT(jcc->to !=0);
652 CLG_ASSERT(jcc->from !=0);
654 if (!get_debug_pos(jcc->to, bb_addr(jcc->to->bb), &target)) {
655 /* if we don't have debug info, don't switch to file "???" */
656 target.file = last->file;
659 if ((jcc->jmpkind == jk_CondJump) || (jcc->jmpkind == jk_Jump)) {
661 /* this is a JCC for a followed conditional or boring jump. */
662 CLG_ASSERT(CLG_(is_zero_cost)( CLG_(sets).full, jcc->cost));
664 /* objects among jumps should be the same.
665 * Otherwise this jump would have been changed to a call
666 * (see setup_bbcc)
668 CLG_ASSERT(jcc->from->bb->obj == jcc->to->bb->obj);
670 /* only print if target position info is usefull */
671 if (!CLG_(clo).dump_instr && !CLG_(clo).dump_bb && target.line==0) {
672 jcc->call_counter = 0;
673 return;
676 /* Different files/functions are possible e.g. with longjmp's
677 * which change the stack, and thus context
679 if (last->file != target.file) {
680 VG_(sprintf)(outbuf, "jfi=");
681 print_file(outbuf+4, target.file);
682 my_fwrite(fd, outbuf, VG_(strlen)(outbuf));
685 if (jcc->from->cxt != jcc->to->cxt) {
686 if (CLG_(clo).mangle_names)
687 print_mangled_fn(fd, outbuf, "jfn",
688 jcc->to->cxt, jcc->to->rec_index);
689 else
690 print_fn(fd, outbuf, "jfn", jcc->to->cxt->fn[0]);
693 if (jcc->jmpkind == jk_CondJump) {
694 /* format: jcnd=<followed>/<executions> <target> */
695 VG_(sprintf)(outbuf, "jcnd=%llu/%llu ",
696 jcc->call_counter, ecounter);
698 else {
699 /* format: jump=<jump count> <target> */
700 VG_(sprintf)(outbuf, "jump=%llu ",
701 jcc->call_counter);
703 my_fwrite(fd, outbuf, VG_(strlen)(outbuf));
705 fprint_pos(fd, &target, last);
706 my_fwrite(fd, "\n", 1);
707 fprint_pos(fd, curr, last);
708 my_fwrite(fd, "\n", 1);
710 jcc->call_counter = 0;
711 return;
714 file = jcc->to->cxt->fn[0]->file;
715 obj = jcc->to->bb->obj;
717 /* object of called position different to object of this function?*/
718 if (jcc->from->cxt->fn[0]->file->obj != obj) {
719 VG_(sprintf)(outbuf, "cob=");
720 print_obj(outbuf+4, obj);
721 my_fwrite(fd, outbuf, VG_(strlen)(outbuf));
724 /* file of called position different to current file? */
725 if (last->file != file) {
726 VG_(sprintf)(outbuf, "cfi=");
727 print_file(outbuf+4, file);
728 my_fwrite(fd, outbuf, VG_(strlen)(outbuf));
731 if (CLG_(clo).mangle_names)
732 print_mangled_fn(fd, outbuf, "cfn", jcc->to->cxt, jcc->to->rec_index);
733 else
734 print_fn(fd, outbuf, "cfn", jcc->to->cxt->fn[0]);
736 if (!CLG_(is_zero_cost)( CLG_(sets).full, jcc->cost)) {
737 VG_(sprintf)(outbuf, "calls=%llu ",
738 jcc->call_counter);
739 my_fwrite(fd, outbuf, VG_(strlen)(outbuf));
741 fprint_pos(fd, &target, last);
742 my_fwrite(fd, "\n", 1);
743 fprint_pos(fd, curr, last);
744 fprint_cost(fd, CLG_(dumpmap), jcc->cost);
746 CLG_(init_cost)( CLG_(sets).full, jcc->cost );
748 jcc->call_counter = 0;
754 /* Cost summation of functions.We use alternately ccSum[0/1], thus
755 * ssSum[currSum] for recently read lines with same line number.
757 static AddrCost ccSum[2];
758 static int currSum;
761 * Print all costs of a BBCC:
762 * - FCCs of instructions
763 * - JCCs of the unique jump of this BB
764 * returns True if something was written
766 static Bool fprint_bbcc(Int fd, BBCC* bbcc, AddrPos* last)
768 InstrInfo* instr_info;
769 ULong ecounter;
770 Bool something_written = False;
771 jCC* jcc;
772 AddrCost *currCost, *newCost;
773 Int jcc_count = 0, instr, i, jmp;
774 BB* bb = bbcc->bb;
776 CLG_ASSERT(bbcc->cxt != 0);
777 CLG_DEBUGIF(1) {
778 VG_(printf)("+ fprint_bbcc (Instr %d): ", bb->instr_count);
779 CLG_(print_bbcc)(15, bbcc);
782 CLG_ASSERT(currSum == 0 || currSum == 1);
783 currCost = &(ccSum[currSum]);
784 newCost = &(ccSum[1-currSum]);
786 ecounter = bbcc->ecounter_sum;
787 jmp = 0;
788 instr_info = &(bb->instr[0]);
789 for(instr=0; instr<bb->instr_count; instr++, instr_info++) {
791 /* get debug info of current instruction address and dump cost
792 * if CLG_(clo).dump_bbs or file/line has changed
794 if (!get_debug_pos(bbcc, bb_addr(bb) + instr_info->instr_offset,
795 &(newCost->p))) {
796 /* if we don't have debug info, don't switch to file "???" */
797 newCost->p.file = bbcc->cxt->fn[0]->file;
800 if (CLG_(clo).dump_bbs || CLG_(clo).dump_instr ||
801 (newCost->p.line != currCost->p.line) ||
802 (newCost->p.file != currCost->p.file)) {
804 if (!CLG_(is_zero_cost)( CLG_(sets).full, currCost->cost )) {
805 something_written = True;
807 fprint_apos(fd, &(currCost->p), last, bbcc->cxt->fn[0]->file);
808 fprint_fcost(fd, currCost, last);
811 /* switch buffers */
812 currSum = 1 - currSum;
813 currCost = &(ccSum[currSum]);
814 newCost = &(ccSum[1-currSum]);
817 /* add line cost to current cost sum */
818 (*CLG_(cachesim).add_icost)(currCost->cost, bbcc, instr_info, ecounter);
820 /* print jcc's if there are: only jumps */
821 if (bb->jmp[jmp].instr == instr) {
822 jcc_count=0;
823 for(jcc=bbcc->jmp[jmp].jcc_list; jcc; jcc=jcc->next_from)
824 if (((jcc->jmpkind != jk_Call) && (jcc->call_counter >0)) ||
825 (!CLG_(is_zero_cost)( CLG_(sets).full, jcc->cost )))
826 jcc_count++;
828 if (jcc_count>0) {
829 if (!CLG_(is_zero_cost)( CLG_(sets).full, currCost->cost )) {
830 /* no need to switch buffers, as position is the same */
831 fprint_apos(fd, &(currCost->p), last, bbcc->cxt->fn[0]->file);
832 fprint_fcost(fd, currCost, last);
834 get_debug_pos(bbcc, bb_addr(bb)+instr_info->instr_offset, &(currCost->p));
835 fprint_apos(fd, &(currCost->p), last, bbcc->cxt->fn[0]->file);
836 something_written = True;
837 for(jcc=bbcc->jmp[jmp].jcc_list; jcc; jcc=jcc->next_from) {
838 if (((jcc->jmpkind != jk_Call) && (jcc->call_counter >0)) ||
839 (!CLG_(is_zero_cost)( CLG_(sets).full, jcc->cost )))
840 fprint_jcc(fd, jcc, &(currCost->p), last, ecounter);
845 /* update execution counter */
846 if (jmp < bb->cjmp_count)
847 if (bb->jmp[jmp].instr == instr) {
848 ecounter -= bbcc->jmp[jmp].ecounter;
849 jmp++;
853 /* jCCs at end? If yes, dump cumulated line info first */
854 jcc_count = 0;
855 for(jcc=bbcc->jmp[jmp].jcc_list; jcc; jcc=jcc->next_from) {
856 /* yes, if JCC only counts jmp arcs or cost >0 */
857 if ( ((jcc->jmpkind != jk_Call) && (jcc->call_counter >0)) ||
858 (!CLG_(is_zero_cost)( CLG_(sets).full, jcc->cost )))
859 jcc_count++;
862 if ( (bbcc->skipped &&
863 !CLG_(is_zero_cost)(CLG_(sets).full, bbcc->skipped)) ||
864 (jcc_count>0) ) {
866 if (!CLG_(is_zero_cost)( CLG_(sets).full, currCost->cost )) {
867 /* no need to switch buffers, as position is the same */
868 fprint_apos(fd, &(currCost->p), last, bbcc->cxt->fn[0]->file);
869 fprint_fcost(fd, currCost, last);
872 get_debug_pos(bbcc, bb_jmpaddr(bb), &(currCost->p));
873 fprint_apos(fd, &(currCost->p), last, bbcc->cxt->fn[0]->file);
874 something_written = True;
876 /* first, print skipped costs for calls */
877 if (bbcc->skipped && !CLG_(is_zero_cost)( CLG_(sets).full,
878 bbcc->skipped )) {
879 CLG_(add_and_zero_cost)( CLG_(sets).full,
880 currCost->cost, bbcc->skipped );
881 #if 0
882 VG_(sprintf)(outbuf, "# Skipped\n");
883 my_fwrite(fd, outbuf, VG_(strlen)(outbuf));
884 #endif
885 fprint_fcost(fd, currCost, last);
888 if (jcc_count > 0)
889 for(jcc=bbcc->jmp[jmp].jcc_list; jcc; jcc=jcc->next_from) {
890 CLG_ASSERT(jcc->jmp == jmp);
891 if ( ((jcc->jmpkind != jk_Call) && (jcc->call_counter >0)) ||
892 (!CLG_(is_zero_cost)( CLG_(sets).full, jcc->cost )))
894 fprint_jcc(fd, jcc, &(currCost->p), last, ecounter);
898 if (CLG_(clo).dump_bbs || CLG_(clo).dump_bb) {
899 if (!CLG_(is_zero_cost)( CLG_(sets).full, currCost->cost )) {
900 something_written = True;
902 fprint_apos(fd, &(currCost->p), last, bbcc->cxt->fn[0]->file);
903 fprint_fcost(fd, currCost, last);
905 if (CLG_(clo).dump_bbs) my_fwrite(fd, "\n", 1);
907 /* when every cost was immediatly written, we must have done so,
908 * as this function is only called when there's cost in a BBCC
910 CLG_ASSERT(something_written);
913 bbcc->ecounter_sum = 0;
914 for(i=0; i<=bbcc->bb->cjmp_count; i++)
915 bbcc->jmp[i].ecounter = 0;
916 bbcc->ret_counter = 0;
918 CLG_DEBUG(1, "- fprint_bbcc: JCCs %d\n", jcc_count);
920 return something_written;
923 /* order by
924 * recursion,
925 * from->bb->obj, from->bb->fn
926 * obj, fn[0]->file, fn
927 * address
929 static int my_cmp(BBCC** pbbcc1, BBCC** pbbcc2)
931 #if 0
932 return (*pbbcc1)->bb->offset - (*pbbcc2)->bb->offset;
933 #else
934 BBCC *bbcc1 = *pbbcc1;
935 BBCC *bbcc2 = *pbbcc2;
936 Context* cxt1 = bbcc1->cxt;
937 Context* cxt2 = bbcc2->cxt;
938 int off = 1;
940 if (cxt1->fn[0]->file->obj != cxt2->fn[0]->file->obj)
941 return cxt1->fn[0]->file->obj - cxt2->fn[0]->file->obj;
943 if (cxt1->fn[0]->file != cxt2->fn[0]->file)
944 return cxt1->fn[0]->file - cxt2->fn[0]->file;
946 if (cxt1->fn[0] != cxt2->fn[0])
947 return cxt1->fn[0] - cxt2->fn[0];
949 if (bbcc1->rec_index != bbcc2->rec_index)
950 return bbcc1->rec_index - bbcc2->rec_index;
952 while((off < cxt1->size) && (off < cxt2->size)) {
953 fn_node* ffn1 = cxt1->fn[off];
954 fn_node* ffn2 = cxt2->fn[off];
955 if (ffn1->file->obj != ffn2->file->obj)
956 return ffn1->file->obj - ffn2->file->obj;
957 if (ffn1 != ffn2)
958 return ffn1 - ffn2;
959 off++;
961 if (cxt1->size > cxt2->size) return 1;
962 else if (cxt1->size < cxt2->size) return -1;
964 return bbcc1->bb->offset - bbcc2->bb->offset;
965 #endif
972 /* modified version of:
974 * qsort -- qsort interface implemented by faster quicksort.
975 * J. L. Bentley and M. D. McIlroy, SPE 23 (1993) 1249-1265.
976 * Copyright 1993, John Wiley.
979 static __inline__
980 void swap(BBCC** a, BBCC** b)
982 BBCC* t;
983 t = *a; *a = *b; *b = t;
986 #define min(x, y) ((x)<=(y) ? (x) : (y))
988 static
989 BBCC** med3(BBCC **a, BBCC **b, BBCC **c, int (*cmp)(BBCC**,BBCC**))
990 { return cmp(a, b) < 0 ?
991 (cmp(b, c) < 0 ? b : cmp(a, c) < 0 ? c : a)
992 : (cmp(b, c) > 0 ? b : cmp(a, c) > 0 ? c : a);
995 static BBCC** qsort_start = 0;
997 static void qsort(BBCC **a, int n, int (*cmp)(BBCC**,BBCC**))
999 BBCC **pa, **pb, **pc, **pd, **pl, **pm, **pn, **pv;
1000 int s, r;
1001 BBCC* v;
1003 CLG_DEBUG(8, " qsort(%ld,%ld)\n", a-qsort_start + 0L, n + 0L);
1005 if (n < 7) { /* Insertion sort on smallest arrays */
1006 for (pm = a+1; pm < a+n; pm++)
1007 for (pl = pm; pl > a && cmp(pl-1, pl) > 0; pl --)
1008 swap(pl, pl-1);
1010 CLG_DEBUGIF(8) {
1011 for (pm = a; pm < a+n; pm++) {
1012 VG_(printf)(" %3ld BB %#lx, ",
1013 pm - qsort_start + 0L,
1014 bb_addr((*pm)->bb));
1015 CLG_(print_cxt)(9, (*pm)->cxt, (*pm)->rec_index);
1018 return;
1020 pm = a + n/2; /* Small arrays, middle element */
1021 if (n > 7) {
1022 pl = a;
1023 pn = a + (n-1);
1024 if (n > 40) { /* Big arrays, pseudomedian of 9 */
1025 s = n/8;
1026 pl = med3(pl, pl+s, pl+2*s, cmp);
1027 pm = med3(pm-s, pm, pm+s, cmp);
1028 pn = med3(pn-2*s, pn-s, pn, cmp);
1030 pm = med3(pl, pm, pn, cmp); /* Mid-size, med of 3 */
1034 v = *pm;
1035 pv = &v;
1036 pa = pb = a;
1037 pc = pd = a + (n-1);
1038 for (;;) {
1039 while ((pb <= pc) && ((r=cmp(pb, pv)) <= 0)) {
1040 if (r==0) {
1041 /* same as pivot, to start */
1042 swap(pa,pb); pa++;
1044 pb ++;
1046 while ((pb <= pc) && ((r=cmp(pc, pv)) >= 0)) {
1047 if (r==0) {
1048 /* same as pivot, to end */
1049 swap(pc,pd); pd--;
1051 pc --;
1053 if (pb > pc) { break; }
1054 swap(pb, pc);
1055 pb ++;
1056 pc --;
1058 pb--;
1059 pc++;
1061 /* put pivot from start into middle */
1062 if ((s = pa-a)>0) { for(r=0;r<s;r++) swap(a+r, pb+1-s+r); }
1063 /* put pivot from end into middle */
1064 if ((s = a+n-1-pd)>0) { for(r=0;r<s;r++) swap(pc+r, a+n-s+r); }
1066 CLG_DEBUGIF(8) {
1067 VG_(printf)(" PV BB %#lx, ", bb_addr((*pv)->bb));
1068 CLG_(print_cxt)(9, (*pv)->cxt, (*pv)->rec_index);
1070 s = pb-pa+1;
1071 VG_(printf)(" Lower %ld - %ld:\n",
1072 a-qsort_start + 0L,
1073 a+s-1-qsort_start + 0L);
1074 for (r=0;r<s;r++) {
1075 pm = a+r;
1076 VG_(printf)(" %3ld BB %#lx, ",
1077 pm-qsort_start + 0L,
1078 bb_addr((*pm)->bb));
1079 CLG_(print_cxt)(9, (*pm)->cxt, (*pm)->rec_index);
1082 s = pd-pc+1;
1083 VG_(printf)(" Upper %ld - %ld:\n",
1084 a+n-s-qsort_start + 0L,
1085 a+n-1-qsort_start + 0L);
1086 for (r=0;r<s;r++) {
1087 pm = a+n-s+r;
1088 VG_(printf)(" %3ld BB %#lx, ",
1089 pm-qsort_start + 0L,
1090 bb_addr((*pm)->bb));
1091 CLG_(print_cxt)(9, (*pm)->cxt, (*pm)->rec_index);
1095 if ((s = pb+1-pa) > 1) qsort(a, s, cmp);
1096 if ((s = pd+1-pc) > 1) qsort(a+n-s, s, cmp);
1100 /* Helpers for prepare_dump */
1102 static Int prepare_count;
1103 static BBCC** prepare_ptr;
1106 static void hash_addCount(BBCC* bbcc)
1108 if ((bbcc->ecounter_sum > 0) || (bbcc->ret_counter>0))
1109 prepare_count++;
1112 static void hash_addPtr(BBCC* bbcc)
1114 if ((bbcc->ecounter_sum == 0) &&
1115 (bbcc->ret_counter == 0)) return;
1117 *prepare_ptr = bbcc;
1118 prepare_ptr++;
1122 static void cs_addCount(thread_info* ti)
1124 Int i;
1125 BBCC* bbcc;
1127 /* add BBCCs with active call in call stack of current thread.
1128 * update cost sums for active calls
1131 for(i = 0; i < CLG_(current_call_stack).sp; i++) {
1132 call_entry* e = &(CLG_(current_call_stack).entry[i]);
1133 if (e->jcc == 0) continue;
1135 CLG_(add_diff_cost_lz)( CLG_(sets).full, &(e->jcc->cost),
1136 e->enter_cost, CLG_(current_state).cost);
1137 bbcc = e->jcc->from;
1139 CLG_DEBUG(1, " [%2d] (tid %d), added active: %s\n",
1140 i,CLG_(current_tid),bbcc->cxt->fn[0]->name);
1142 if (bbcc->ecounter_sum>0 || bbcc->ret_counter>0) {
1143 /* already counted */
1144 continue;
1146 prepare_count++;
1150 static void cs_addPtr(thread_info* ti)
1152 Int i;
1153 BBCC* bbcc;
1155 /* add BBCCs with active call in call stack of current thread.
1156 * update cost sums for active calls
1159 for(i = 0; i < CLG_(current_call_stack).sp; i++) {
1160 call_entry* e = &(CLG_(current_call_stack).entry[i]);
1161 if (e->jcc == 0) continue;
1163 bbcc = e->jcc->from;
1165 if (bbcc->ecounter_sum>0 || bbcc->ret_counter>0) {
1166 /* already counted */
1167 continue;
1170 *prepare_ptr = bbcc;
1171 prepare_ptr++;
1177 * Put all BBCCs with costs into a sorted array.
1178 * The returned arrays ends with a null pointer.
1179 * Must be freed after dumping.
1181 static
1182 BBCC** prepare_dump(void)
1184 BBCC **array;
1186 prepare_count = 0;
1188 /* if we do not separate among threads, this gives all */
1189 /* count number of BBCCs with >0 executions */
1190 CLG_(forall_bbccs)(hash_addCount);
1192 /* even if we do not separate among threads,
1193 * call stacks are separated */
1194 if (CLG_(clo).separate_threads)
1195 cs_addCount(0);
1196 else
1197 CLG_(forall_threads)(cs_addCount);
1199 CLG_DEBUG(0, "prepare_dump: %d BBCCs\n", prepare_count);
1201 /* allocate bbcc array, insert BBCCs and sort */
1202 prepare_ptr = array =
1203 (BBCC**) CLG_MALLOC("cl.dump.pd.1",
1204 (prepare_count+1) * sizeof(BBCC*));
1206 CLG_(forall_bbccs)(hash_addPtr);
1208 if (CLG_(clo).separate_threads)
1209 cs_addPtr(0);
1210 else
1211 CLG_(forall_threads)(cs_addPtr);
1213 CLG_ASSERT(array + prepare_count == prepare_ptr);
1215 /* end mark */
1216 *prepare_ptr = 0;
1218 CLG_DEBUG(0," BBCCs inserted\n");
1220 qsort_start = array;
1221 qsort(array, prepare_count, my_cmp);
1223 CLG_DEBUG(0," BBCCs sorted\n");
1225 return array;
1231 static void fprint_cost_ln(int fd, const HChar* prefix,
1232 EventMapping* em, ULong* cost)
1234 int p;
1236 p = VG_(sprintf)(outbuf, "%s", prefix);
1237 p += CLG_(sprint_mappingcost)(outbuf + p, em, cost);
1238 VG_(sprintf)(outbuf + p, "\n");
1239 my_fwrite(fd, outbuf, VG_(strlen)(outbuf));
1242 static ULong bbs_done = 0;
1243 static HChar* filename = 0;
1245 static
1246 void file_err(void)
1248 VG_(message)(Vg_UserMsg,
1249 "Error: can not open cache simulation output file `%s'\n",
1250 filename );
1251 VG_(exit)(1);
1255 * Create a new dump file and write header.
1257 * Naming: <CLG_(clo).filename_base>.<pid>[.<part>][-<tid>]
1258 * <part> is skipped for final dump (trigger==0)
1259 * <tid> is skipped for thread 1 with CLG_(clo).separate_threads=no
1261 * Returns the file descriptor, and -1 on error (no write permission)
1263 static int new_dumpfile(HChar buf[BUF_LEN], int tid, const HChar* trigger)
1265 Bool appending = False;
1266 int i, fd;
1267 FullCost sum = 0;
1268 SysRes res;
1270 CLG_ASSERT(dumps_initialized);
1271 CLG_ASSERT(filename != 0);
1273 if (!CLG_(clo).combine_dumps) {
1274 i = VG_(sprintf)(filename, "%s", out_file);
1276 if (trigger)
1277 i += VG_(sprintf)(filename+i, ".%d", out_counter);
1279 if (CLG_(clo).separate_threads)
1280 VG_(sprintf)(filename+i, "-%02d", tid);
1282 res = VG_(open)(filename, VKI_O_WRONLY|VKI_O_TRUNC, 0);
1284 else {
1285 VG_(sprintf)(filename, "%s", out_file);
1286 res = VG_(open)(filename, VKI_O_WRONLY|VKI_O_APPEND, 0);
1287 if (!sr_isError(res) && out_counter>1)
1288 appending = True;
1291 if (sr_isError(res)) {
1292 res = VG_(open)(filename, VKI_O_CREAT|VKI_O_WRONLY,
1293 VKI_S_IRUSR|VKI_S_IWUSR);
1294 if (sr_isError(res)) {
1295 /* If the file can not be opened for whatever reason (conflict
1296 between multiple supervised processes?), give up now. */
1297 file_err();
1300 fd = (Int) sr_Res(res);
1302 CLG_DEBUG(2, " new_dumpfile '%s'\n", filename);
1304 if (!appending)
1305 reset_dump_array();
1308 if (!appending) {
1309 /* version */
1310 VG_(sprintf)(buf, "version: 1\n");
1311 my_fwrite(fd, buf, VG_(strlen)(buf));
1313 /* creator */
1314 VG_(sprintf)(buf, "creator: callgrind-" VERSION "\n");
1315 my_fwrite(fd, buf, VG_(strlen)(buf));
1317 /* "pid:" line */
1318 VG_(sprintf)(buf, "pid: %d\n", VG_(getpid)());
1319 my_fwrite(fd, buf, VG_(strlen)(buf));
1321 /* "cmd:" line */
1322 VG_(strcpy)(buf, "cmd: ");
1323 my_fwrite(fd, buf, VG_(strlen)(buf));
1324 my_fwrite(fd, cmdbuf, VG_(strlen)(cmdbuf));
1327 VG_(sprintf)(buf, "\npart: %d\n", out_counter);
1328 my_fwrite(fd, buf, VG_(strlen)(buf));
1329 if (CLG_(clo).separate_threads) {
1330 VG_(sprintf)(buf, "thread: %d\n", tid);
1331 my_fwrite(fd, buf, VG_(strlen)(buf));
1334 /* "desc:" lines */
1335 if (!appending) {
1336 my_fwrite(fd, "\n", 1);
1338 #if 0
1339 /* Global options changing the tracing behaviour */
1340 VG_(sprintf)(buf, "\ndesc: Option: --skip-plt=%s\n",
1341 CLG_(clo).skip_plt ? "yes" : "no");
1342 my_fwrite(fd, buf, VG_(strlen)(buf));
1343 VG_(sprintf)(buf, "desc: Option: --collect-jumps=%s\n",
1344 CLG_(clo).collect_jumps ? "yes" : "no");
1345 my_fwrite(fd, buf, VG_(strlen)(buf));
1346 VG_(sprintf)(buf, "desc: Option: --separate-recs=%d\n",
1347 CLG_(clo).separate_recursions);
1348 my_fwrite(fd, buf, VG_(strlen)(buf));
1349 VG_(sprintf)(buf, "desc: Option: --separate-callers=%d\n",
1350 CLG_(clo).separate_callers);
1351 my_fwrite(fd, buf, VG_(strlen)(buf));
1353 VG_(sprintf)(buf, "desc: Option: --dump-bbs=%s\n",
1354 CLG_(clo).dump_bbs ? "yes" : "no");
1355 my_fwrite(fd, buf, VG_(strlen)(buf));
1356 VG_(sprintf)(buf, "desc: Option: --separate-threads=%s\n",
1357 CLG_(clo).separate_threads ? "yes" : "no");
1358 my_fwrite(fd, buf, VG_(strlen)(buf));
1359 #endif
1361 (*CLG_(cachesim).getdesc)(buf);
1362 my_fwrite(fd, buf, VG_(strlen)(buf));
1365 VG_(sprintf)(buf, "\ndesc: Timerange: Basic block %llu - %llu\n",
1366 bbs_done, CLG_(stat).bb_executions);
1368 my_fwrite(fd, buf, VG_(strlen)(buf));
1369 VG_(sprintf)(buf, "desc: Trigger: %s\n",
1370 trigger ? trigger : "Program termination");
1371 my_fwrite(fd, buf, VG_(strlen)(buf));
1373 #if 0
1374 /* Output function specific config
1375 * FIXME */
1376 for (i = 0; i < N_FNCONFIG_ENTRIES; i++) {
1377 fnc = fnc_table[i];
1378 while (fnc) {
1379 if (fnc->skip) {
1380 VG_(sprintf)(buf, "desc: Option: --fn-skip=%s\n", fnc->name);
1381 my_fwrite(fd, buf, VG_(strlen)(buf));
1383 if (fnc->dump_at_enter) {
1384 VG_(sprintf)(buf, "desc: Option: --fn-dump-at-enter=%s\n",
1385 fnc->name);
1386 my_fwrite(fd, buf, VG_(strlen)(buf));
1388 if (fnc->dump_at_leave) {
1389 VG_(sprintf)(buf, "desc: Option: --fn-dump-at-leave=%s\n",
1390 fnc->name);
1391 my_fwrite(fd, buf, VG_(strlen)(buf));
1393 if (fnc->separate_callers != CLG_(clo).separate_callers) {
1394 VG_(sprintf)(buf, "desc: Option: --separate-callers%d=%s\n",
1395 fnc->separate_callers, fnc->name);
1396 my_fwrite(fd, buf, VG_(strlen)(buf));
1398 if (fnc->separate_recursions != CLG_(clo).separate_recursions) {
1399 VG_(sprintf)(buf, "desc: Option: --separate-recs%d=%s\n",
1400 fnc->separate_recursions, fnc->name);
1401 my_fwrite(fd, buf, VG_(strlen)(buf));
1403 fnc = fnc->next;
1406 #endif
1408 /* "positions:" line */
1409 VG_(sprintf)(buf, "\npositions:%s%s%s\n",
1410 CLG_(clo).dump_instr ? " instr" : "",
1411 CLG_(clo).dump_bb ? " bb" : "",
1412 CLG_(clo).dump_line ? " line" : "");
1413 my_fwrite(fd, buf, VG_(strlen)(buf));
1415 /* "events:" line */
1416 i = VG_(sprintf)(buf, "events: ");
1417 CLG_(sprint_eventmapping)(buf+i, CLG_(dumpmap));
1418 my_fwrite(fd, buf, VG_(strlen)(buf));
1419 my_fwrite(fd, "\n", 1);
1421 /* summary lines */
1422 sum = CLG_(get_eventset_cost)( CLG_(sets).full );
1423 CLG_(zero_cost)(CLG_(sets).full, sum);
1424 if (CLG_(clo).separate_threads) {
1425 thread_info* ti = CLG_(get_current_thread)();
1426 CLG_(add_diff_cost)(CLG_(sets).full, sum, ti->lastdump_cost,
1427 ti->states.entry[0]->cost);
1429 else {
1430 /* This function is called once for thread 1, where
1431 * all costs are summed up when not dumping separate per thread.
1432 * But this is not true for summary: we need to add all threads.
1434 int t;
1435 thread_info** thr = CLG_(get_threads)();
1436 for(t=1;t<VG_N_THREADS;t++) {
1437 if (!thr[t]) continue;
1438 CLG_(add_diff_cost)(CLG_(sets).full, sum,
1439 thr[t]->lastdump_cost,
1440 thr[t]->states.entry[0]->cost);
1443 fprint_cost_ln(fd, "summary: ", CLG_(dumpmap), sum);
1445 /* all dumped cost will be added to total_fcc */
1446 CLG_(init_cost_lz)( CLG_(sets).full, &dump_total_cost );
1448 my_fwrite(fd, "\n\n",2);
1450 if (VG_(clo_verbosity) > 1)
1451 VG_(message)(Vg_DebugMsg, "Dump to %s\n", filename);
1453 return fd;
1457 static void close_dumpfile(int fd)
1459 if (fd <0) return;
1461 fprint_cost_ln(fd, "totals: ", CLG_(dumpmap),
1462 dump_total_cost);
1463 //fprint_fcc_ln(fd, "summary: ", &dump_total_fcc);
1464 CLG_(add_cost_lz)(CLG_(sets).full,
1465 &CLG_(total_cost), dump_total_cost);
1467 fwrite_flush();
1468 VG_(close)(fd);
1470 if (filename[0] == '.') {
1471 if (-1 == VG_(rename) (filename, filename+1)) {
1472 /* Can not rename to correct file name: give out warning */
1473 VG_(message)(Vg_DebugMsg, "Warning: Can not rename .%s to %s\n",
1474 filename, filename);
1480 /* Helper for print_bbccs */
1482 static Int print_fd;
1483 static const HChar* print_trigger;
1484 static HChar print_buf[BUF_LEN];
1486 static void print_bbccs_of_thread(thread_info* ti)
1488 BBCC **p, **array;
1489 FnPos lastFnPos;
1490 AddrPos lastAPos;
1492 CLG_DEBUG(1, "+ print_bbccs(tid %d)\n", CLG_(current_tid));
1494 print_fd = new_dumpfile(print_buf, CLG_(current_tid), print_trigger);
1495 if (print_fd <0) {
1496 CLG_DEBUG(1, "- print_bbccs(tid %d): No output...\n", CLG_(current_tid));
1497 return;
1500 p = array = prepare_dump();
1501 init_fpos(&lastFnPos);
1502 init_apos(&lastAPos, 0, 0, 0);
1504 if (p) while(1) {
1506 /* on context/function change, print old cost buffer before */
1507 if (lastFnPos.cxt && ((*p==0) ||
1508 (lastFnPos.cxt != (*p)->cxt) ||
1509 (lastFnPos.rec_index != (*p)->rec_index))) {
1510 if (!CLG_(is_zero_cost)( CLG_(sets).full, ccSum[currSum].cost )) {
1511 /* no need to switch buffers, as position is the same */
1512 fprint_apos(print_fd, &(ccSum[currSum].p), &lastAPos,
1513 lastFnPos.cxt->fn[0]->file);
1514 fprint_fcost(print_fd, &ccSum[currSum], &lastAPos);
1517 if (ccSum[currSum].p.file != lastFnPos.cxt->fn[0]->file) {
1518 /* switch back to file of function */
1519 VG_(sprintf)(print_buf, "fe=");
1520 print_file(print_buf+3, lastFnPos.cxt->fn[0]->file);
1521 my_fwrite(print_fd, print_buf, VG_(strlen)(print_buf));
1523 my_fwrite(print_fd, "\n", 1);
1526 if (*p == 0) break;
1528 if (print_fn_pos(print_fd, &lastFnPos, *p)) {
1530 /* new function */
1531 init_apos(&lastAPos, 0, 0, (*p)->cxt->fn[0]->file);
1532 init_fcost(&ccSum[0], 0, 0, 0);
1533 init_fcost(&ccSum[1], 0, 0, 0);
1534 currSum = 0;
1537 if (CLG_(clo).dump_bbs) {
1538 /* FIXME: Specify Object of BB if different to object of fn */
1539 int i, pos = 0;
1540 ULong ecounter = (*p)->ecounter_sum;
1541 pos = VG_(sprintf)(print_buf, "bb=%#lx ", (*p)->bb->offset);
1542 for(i = 0; i<(*p)->bb->cjmp_count;i++) {
1543 pos += VG_(sprintf)(print_buf+pos, "%d %llu ",
1544 (*p)->bb->jmp[i].instr,
1545 ecounter);
1546 ecounter -= (*p)->jmp[i].ecounter;
1548 VG_(sprintf)(print_buf+pos, "%d %llu\n",
1549 (*p)->bb->instr_count,
1550 ecounter);
1551 my_fwrite(print_fd, print_buf, VG_(strlen)(print_buf));
1554 fprint_bbcc(print_fd, *p, &lastAPos);
1556 p++;
1559 close_dumpfile(print_fd);
1560 if (array) VG_(free)(array);
1562 /* set counters of last dump */
1563 CLG_(copy_cost)( CLG_(sets).full, ti->lastdump_cost,
1564 CLG_(current_state).cost );
1566 CLG_DEBUG(1, "- print_bbccs(tid %d)\n", CLG_(current_tid));
1570 static void print_bbccs(const HChar* trigger, Bool only_current_thread)
1572 init_dump_array();
1573 init_debug_cache();
1575 print_fd = -1;
1576 print_trigger = trigger;
1578 if (!CLG_(clo).separate_threads) {
1579 /* All BBCC/JCC costs is stored for thread 1 */
1580 Int orig_tid = CLG_(current_tid);
1582 CLG_(switch_thread)(1);
1583 print_bbccs_of_thread( CLG_(get_current_thread)() );
1584 CLG_(switch_thread)(orig_tid);
1586 else if (only_current_thread)
1587 print_bbccs_of_thread( CLG_(get_current_thread)() );
1588 else
1589 CLG_(forall_threads)(print_bbccs_of_thread);
1591 free_dump_array();
1595 void CLG_(dump_profile)(const HChar* trigger, Bool only_current_thread)
1597 CLG_DEBUG(2, "+ dump_profile(Trigger '%s')\n",
1598 trigger ? trigger : "Prg.Term.");
1600 CLG_(init_dumps)();
1602 if (VG_(clo_verbosity) > 1)
1603 VG_(message)(Vg_DebugMsg, "Start dumping at BB %llu (%s)...\n",
1604 CLG_(stat).bb_executions,
1605 trigger ? trigger : "Prg.Term.");
1607 out_counter++;
1609 print_bbccs(trigger, only_current_thread);
1611 bbs_done = CLG_(stat).bb_executions++;
1613 if (VG_(clo_verbosity) > 1)
1614 VG_(message)(Vg_DebugMsg, "Dumping done.\n");
1617 /* Copy command to cmd buffer. We want to original command line
1618 * (can change at runtime)
1620 static
1621 void init_cmdbuf(void)
1623 Int i,j,size = 0;
1624 HChar* argv;
1626 CLG_ASSERT( VG_(strlen)( VG_(args_the_exename) ) < BUF_LEN-1);
1627 size = VG_(sprintf)(cmdbuf, " %s", VG_(args_the_exename));
1629 for(i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
1630 argv = * (HChar**) VG_(indexXA)( VG_(args_for_client), i );
1631 if (!argv) continue;
1632 if ((size>0) && (size < BUF_LEN)) cmdbuf[size++] = ' ';
1633 for(j=0;argv[j]!=0;j++)
1634 if (size < BUF_LEN) cmdbuf[size++] = argv[j];
1637 if (size >= BUF_LEN) size = BUF_LEN-1;
1638 cmdbuf[size] = 0;
1642 * Set up file names for dump output: <out_file>.
1643 * <out_file> is derived from the output format string, which defaults
1644 * to "callgrind.out.%p", where %p is replaced with the PID.
1645 * For the final file name, on intermediate dumps a counter is appended,
1646 * and further, if separate dumps per thread are requested, the thread ID.
1648 * <out_file> always starts with a full absolute path.
1649 * If the output format string represents a relative path, the current
1650 * working directory at program start is used.
1652 * This function has to be called every time a profile dump is generated
1653 * to be able to react on PID changes.
1655 void CLG_(init_dumps)()
1657 SysRes res;
1659 static int thisPID = 0;
1660 int currentPID = VG_(getpid)();
1661 if (currentPID == thisPID) {
1662 /* already initialized, and no PID change */
1663 CLG_ASSERT(out_file != 0);
1664 return;
1666 thisPID = currentPID;
1668 if (!CLG_(clo).out_format)
1669 CLG_(clo).out_format = DEFAULT_OUTFORMAT;
1671 /* If a file name was already set, clean up before */
1672 if (out_file) {
1673 VG_(free)(out_file);
1674 VG_(free)(filename);
1675 out_counter = 0;
1678 // Setup output filename.
1679 out_file =
1680 VG_(expand_file_name)("--callgrind-out-file", CLG_(clo).out_format);
1682 /* allocate space big enough for final filenames */
1683 filename = (HChar*) CLG_MALLOC("cl.dump.init_dumps.2",
1684 VG_(strlen)(out_file)+32);
1685 CLG_ASSERT(filename != 0);
1687 /* Make sure the output base file can be written.
1688 * This is used for the dump at program termination.
1689 * We stop with an error here if we can not create the
1690 * file: This is probably because of missing rights,
1691 * and trace parts wouldn't be allowed to be written, too.
1693 VG_(strcpy)(filename, out_file);
1694 res = VG_(open)(filename, VKI_O_WRONLY|VKI_O_TRUNC, 0);
1695 if (sr_isError(res)) {
1696 res = VG_(open)(filename, VKI_O_CREAT|VKI_O_WRONLY,
1697 VKI_S_IRUSR|VKI_S_IWUSR);
1698 if (sr_isError(res)) {
1699 file_err();
1702 if (!sr_isError(res)) VG_(close)( (Int)sr_Res(res) );
1704 if (!dumps_initialized)
1705 init_cmdbuf();
1707 dumps_initialized = True;