1 /*--------------------------------------------------------------------*/
4 /*--------------------------------------------------------------------*/
7 This file is part of Callgrind, a Valgrind tool for call tracing.
9 Copyright (C) 2002-2017, 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
26 The GNU General Public License is contained in the file COPYING.
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
;
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 Int
CLG_(get_dump_counter
)(void)
58 /*------------------------------------------------------------*/
59 /*--- Output file related stuff ---*/
60 /*------------------------------------------------------------*/
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;
71 void reset_dump_array(void)
75 CLG_ASSERT(dump_array
!= 0);
77 for(i
=0;i
<dump_array_size
;i
++)
78 dump_array
[i
] = False
;
82 void init_dump_array(void)
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
;
98 CLG_DEBUG(1, " init_dump_array: size %d\n", dump_array_size
);
102 void free_dump_array(void)
104 CLG_ASSERT(dump_array
!= 0);
105 VG_(free
)(dump_array
);
115 /* Initialize to an invalid position */
117 void init_fpos(FnPos
* p
)
127 static void print_obj(VgFile
*fp
, const HChar
* prefix
, obj_node
* obj
)
129 if (CLG_(clo
).compress_strings
) {
130 CLG_ASSERT(obj_dumped
!= 0);
131 if (obj_dumped
[obj
->number
])
132 VG_(fprintf
)(fp
, "%s(%u)\n", prefix
, obj
->number
);
134 VG_(fprintf
)(fp
, "%s(%u) %s\n", prefix
, obj
->number
, obj
->name
);
138 VG_(fprintf
)(fp
, "%s%s\n", prefix
, obj
->name
);
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
);
149 obj_dumped
[obj
->number
] = True
;
153 static void print_file(VgFile
*fp
, const char *prefix
, const file_node
* file
)
155 if (CLG_(clo
).compress_strings
) {
156 CLG_ASSERT(file_dumped
!= 0);
157 if (file_dumped
[file
->number
])
158 VG_(fprintf
)(fp
, "%s(%u)\n", prefix
, file
->number
);
160 VG_(fprintf
)(fp
, "%s(%u) %s\n", prefix
, file
->number
, file
->name
);
161 file_dumped
[file
->number
] = True
;
165 VG_(fprintf
)(fp
, "%s%s\n", prefix
, file
->name
);
169 * tag can be "fn", "cfn", "jfn"
171 static void print_fn(VgFile
*fp
, const HChar
* tag
, const fn_node
* fn
)
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
, "(%u)\n", fn
->number
);
179 VG_(fprintf
)(fp
, "(%u) %s\n", fn
->number
, fn
->name
);
180 fn_dumped
[fn
->number
] = True
;
184 VG_(fprintf
)(fp
, "%s\n", fn
->name
);
187 static void print_mangled_fn(VgFile
*fp
, const HChar
* tag
,
188 Context
* cxt
, int rec_index
)
192 if (CLG_(clo
).compress_strings
&& CLG_(clo
).compress_mangled
) {
197 CLG_ASSERT(cxt_dumped
!= 0);
198 if (cxt_dumped
[cxt
->base_number
+rec_index
]) {
199 VG_(fprintf
)(fp
, "%s=(%u)\n",
200 tag
, cxt
->base_number
+ rec_index
);
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
);
213 cxt_dumped
[n
] = True
;
214 last
= cxt
->fn
[i
-1]->pure_cxt
;
216 /* If the last context was the context to print, we are finished */
217 if ((last
== cxt
) && (rec_index
== 0)) return;
219 VG_(fprintf
)(fp
, "%s=(%u) (%u)", tag
,
220 cxt
->base_number
+ rec_index
,
221 cxt
->fn
[0]->pure_cxt
->base_number
);
223 VG_(fprintf
)(fp
, "'%d", rec_index
+1);
224 for(i
=1;i
<cxt
->size
;i
++)
225 VG_(fprintf
)(fp
, "'(%u)",
226 cxt
->fn
[i
]->pure_cxt
->base_number
);
227 VG_(fprintf
)(fp
, "\n");
229 cxt_dumped
[cxt
->base_number
+rec_index
] = True
;
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
, "(%u)\n", cxt
->base_number
+ rec_index
);
242 VG_(fprintf
)(fp
, "(%u) ", cxt
->base_number
+ rec_index
);
243 cxt_dumped
[cxt
->base_number
+rec_index
] = True
;
247 VG_(fprintf
)(fp
, "%s", cxt
->fn
[0]->name
);
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
);
253 VG_(fprintf
)(fp
, "\n");
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.
263 static Bool
print_fn_pos(VgFile
*fp
, FnPos
* last
, BBCC
* bbcc
)
267 CLG_ASSERT(bbcc
&& bbcc
->cxt
);
270 CLG_DEBUG(2, "+ print_fn_pos: ");
271 CLG_(print_cxt
)(16, bbcc
->cxt
, bbcc
->rec_index
);
274 if (!CLG_(clo
).mangle_names
) {
275 if (last
->rec_index
!= bbcc
->rec_index
) {
276 VG_(fprintf
)(fp
, "rec=%u\n\n", bbcc
->rec_index
);
277 last
->rec_index
= bbcc
->rec_index
;
278 last
->cxt
= 0; /* reprint context */
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");
294 else if (last_from
!= curr_from
) {
295 print_fn(fp
, "frfn", curr_from
);
298 last
->cxt
= bbcc
->cxt
;
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
;
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
;
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];
322 /* Print mangled name if context or rec_index changes */
323 if ((last
->rec_index
!= bbcc
->rec_index
) ||
324 (last
->cxt
!= bbcc
->cxt
)) {
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
;
333 last
->cxt
= bbcc
->cxt
;
335 CLG_DEBUG(2, "- print_fn_pos: %s\n", res
? "changed" : "");
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.
343 #define DEBUG_CACHE_SIZE 1777
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
];
351 void init_debug_cache(void)
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;
362 static /* __inline__ */
363 Bool
get_debug_pos(BBCC
* bbcc
, Addr addr
, AddrPos
* p
)
365 const HChar
*file
, *dir
;
366 Bool found_file_line
;
368 int cachepos
= addr
% DEBUG_CACHE_SIZE
;
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
];
376 DiEpoch ep
= VG_(current_DiEpoch
)();
377 found_file_line
= VG_(get_filename_linenum
)(ep
, addr
,
381 if (!found_file_line
) {
385 p
->file
= CLG_(get_file_node
)(bbcc
->bb
->obj
, dir
, file
);
387 debug_cache_info
[cachepos
] = found_file_line
;
388 debug_cache_addr
[cachepos
] = addr
;
389 debug_cache_line
[cachepos
] = p
->line
;
390 debug_cache_file
[cachepos
] = p
->file
;
393 /* Address offset from bbcc start address */
394 p
->addr
= addr
- bbcc
->bb
->obj
->offset
;
395 p
->bb_addr
= bbcc
->bb
->offset
;
397 CLG_DEBUG(3, " get_debug_pos(%#lx): BB %#lx, fn '%s', file '%s', line %u\n",
398 addr
, bb_addr(bbcc
->bb
), bbcc
->cxt
->fn
[0]->name
,
399 p
->file
->name
, p
->line
);
401 return found_file_line
;
405 /* copy file position and init cost */
406 static void init_apos(AddrPos
* p
, Addr addr
, Addr bbaddr
, file_node
* file
)
414 static void copy_apos(AddrPos
* dst
, AddrPos
* src
)
416 dst
->addr
= src
->addr
;
417 dst
->bb_addr
= src
->bb_addr
;
418 dst
->file
= src
->file
;
419 dst
->line
= src
->line
;
422 /* copy file position and init cost */
423 static void init_fcost(AddrCost
* c
, Addr addr
, Addr bbaddr
, file_node
* file
)
425 init_apos( &(c
->p
), addr
, bbaddr
, file
);
426 /* FIXME: This is a memory leak as a AddrCost is inited multiple times */
427 c
->cost
= CLG_(get_eventset_cost
)( CLG_(sets
).full
);
428 CLG_(init_cost
)( CLG_(sets
).full
, c
->cost
);
433 * print position change inside of a BB (last -> curr)
434 * this doesn't update last to curr!
436 static void fprint_apos(VgFile
*fp
, AddrPos
* curr
, AddrPos
* last
,
437 file_node
* func_file
)
439 CLG_ASSERT(curr
->file
!= 0);
440 CLG_DEBUG(2, " print_apos(file '%s', line %u, bb %#lx, addr %#lx) fnFile '%s'\n",
441 curr
->file
->name
, curr
->line
, curr
->bb_addr
, curr
->addr
,
444 if (curr
->file
!= last
->file
) {
446 /* if we switch back to orig file, use fe=... */
447 if (curr
->file
== func_file
)
448 print_file(fp
, "fe=", curr
->file
);
450 print_file(fp
, "fi=", curr
->file
);
453 if (CLG_(clo
).dump_bbs
) {
454 if (curr
->line
!= last
->line
) {
455 VG_(fprintf
)(fp
, "ln=%u\n", curr
->line
);
464 * This prints out differences if allowed
466 * This doesn't set last to curr afterwards!
469 void fprint_pos(VgFile
*fp
, const AddrPos
* curr
, const AddrPos
* last
)
471 if (0) //CLG_(clo).dump_bbs)
472 VG_(fprintf
)(fp
, "%lu ", curr
->addr
- curr
->bb_addr
);
474 if (CLG_(clo
).dump_instr
) {
475 int diff
= curr
->addr
- last
->addr
;
476 if ( CLG_(clo
).compress_pos
&& (last
->addr
>0) &&
477 (diff
> -100) && (diff
< 100)) {
479 VG_(fprintf
)(fp
, "+%d ", diff
);
481 VG_(fprintf
)(fp
, "* ");
483 VG_(fprintf
)(fp
, "%d ", diff
);
486 VG_(fprintf
)(fp
, "%#lx ", curr
->addr
);
489 if (CLG_(clo
).dump_bb
) {
490 int diff
= curr
->bb_addr
- last
->bb_addr
;
491 if ( CLG_(clo
).compress_pos
&& (last
->bb_addr
>0) &&
492 (diff
> -100) && (diff
< 100)) {
494 VG_(fprintf
)(fp
, "+%d ", diff
);
496 VG_(fprintf
)(fp
, "* ");
498 VG_(fprintf
)(fp
, "%d ", diff
);
501 VG_(fprintf
)(fp
, "%#lx ", curr
->bb_addr
);
504 if (CLG_(clo
).dump_line
) {
505 int diff
= curr
->line
- last
->line
;
506 if ( CLG_(clo
).compress_pos
&& (last
->line
>0) &&
507 (diff
> -100) && (diff
< 100)) {
510 VG_(fprintf
)(fp
, "+%d ", diff
);
512 VG_(fprintf
)(fp
, "* ");
514 VG_(fprintf
)(fp
, "%d ", diff
);
517 VG_(fprintf
)(fp
, "%u ", curr
->line
);
528 void fprint_cost(VgFile
*fp
, const EventMapping
* es
, const ULong
* cost
)
530 HChar
*mcost
= CLG_(mappingcost_as_string
)(es
, cost
);
531 VG_(fprintf
)(fp
, "%s\n", mcost
);
537 /* Write the cost of a source line; only that parts of the source
538 * position are written that changed relative to last written position.
539 * funcPos is the source position of the first line of actual function.
540 * Something is written only if cost != 0; returns True in this case.
542 static void fprint_fcost(VgFile
*fp
, AddrCost
* c
, AddrPos
* last
)
545 CLG_DEBUG(2, " print_fcost(file '%s', line %u, bb %#lx, addr %#lx):\n",
546 c
->p
.file
->name
, c
->p
.line
, c
->p
.bb_addr
, c
->p
.addr
);
547 CLG_(print_cost
)(-5, CLG_(sets
).full
, c
->cost
);
550 fprint_pos(fp
, &(c
->p
), last
);
551 copy_apos( last
, &(c
->p
) ); /* update last to current position */
553 fprint_cost(fp
, CLG_(dumpmap
), c
->cost
);
555 /* add cost to total */
556 CLG_(add_and_zero_cost
)( CLG_(sets
).full
, dump_total_cost
, c
->cost
);
560 /* Write out the calls from jcc (at pos)
562 static void fprint_jcc(VgFile
*fp
, jCC
* jcc
, AddrPos
* curr
, AddrPos
* last
,
565 static AddrPos target
;
570 CLG_DEBUG(2, " fprint_jcc (jkind %d)\n", (Int
)jcc
->jmpkind
);
571 CLG_(print_jcc
)(-10, jcc
);
574 CLG_ASSERT(jcc
->to
!=0);
575 CLG_ASSERT(jcc
->from
!=0);
577 if (!get_debug_pos(jcc
->to
, bb_addr(jcc
->to
->bb
), &target
)) {
578 /* if we don't have debug info, don't switch to file "???" */
579 target
.file
= last
->file
;
582 if ((jcc
->jmpkind
== jk_CondJump
) || (jcc
->jmpkind
== jk_Jump
)) {
584 /* this is a JCC for a followed conditional or boring jump. */
585 CLG_ASSERT(CLG_(is_zero_cost
)( CLG_(sets
).full
, jcc
->cost
));
587 /* objects among jumps should be the same.
588 * Otherwise this jump would have been changed to a call
591 CLG_ASSERT(jcc
->from
->bb
->obj
== jcc
->to
->bb
->obj
);
593 /* only print if target position info is useful */
594 if (!CLG_(clo
).dump_instr
&& !CLG_(clo
).dump_bb
&& target
.line
==0) {
595 jcc
->call_counter
= 0;
599 /* Different files/functions are possible e.g. with longjmp's
600 * which change the stack, and thus context
602 if (last
->file
!= target
.file
) {
603 print_file(fp
, "jfi=", target
.file
);
606 if (jcc
->from
->cxt
!= jcc
->to
->cxt
) {
607 if (CLG_(clo
).mangle_names
)
608 print_mangled_fn(fp
, "jfn",
609 jcc
->to
->cxt
, jcc
->to
->rec_index
);
611 print_fn(fp
, "jfn", jcc
->to
->cxt
->fn
[0]);
614 if (jcc
->jmpkind
== jk_CondJump
) {
615 /* format: jcnd=<followed>/<executions> <target> */
616 VG_(fprintf
)(fp
, "jcnd=%llu/%llu ",
617 jcc
->call_counter
, ecounter
);
620 /* format: jump=<jump count> <target> */
621 VG_(fprintf
)(fp
, "jump=%llu ",
625 fprint_pos(fp
, &target
, last
);
626 VG_(fprintf
)(fp
, "\n");
627 fprint_pos(fp
, curr
, last
);
628 VG_(fprintf
)(fp
, "\n");
630 jcc
->call_counter
= 0;
634 file
= jcc
->to
->cxt
->fn
[0]->file
;
635 obj
= jcc
->to
->bb
->obj
;
637 /* object of called position different to object of this function?*/
638 if (jcc
->from
->cxt
->fn
[0]->file
->obj
!= obj
) {
639 print_obj(fp
, "cob=", obj
);
642 /* file of called position different to current file? */
643 if (last
->file
!= file
) {
644 print_file(fp
, "cfi=", file
);
647 if (CLG_(clo
).mangle_names
)
648 print_mangled_fn(fp
, "cfn", jcc
->to
->cxt
, jcc
->to
->rec_index
);
650 print_fn(fp
, "cfn", jcc
->to
->cxt
->fn
[0]);
652 if (!CLG_(is_zero_cost
)( CLG_(sets
).full
, jcc
->cost
)) {
653 VG_(fprintf
)(fp
, "calls=%llu ",
656 fprint_pos(fp
, &target
, last
);
657 VG_(fprintf
)(fp
, "\n");
658 fprint_pos(fp
, curr
, last
);
659 fprint_cost(fp
, CLG_(dumpmap
), jcc
->cost
);
661 CLG_(init_cost
)( CLG_(sets
).full
, jcc
->cost
);
663 jcc
->call_counter
= 0;
669 /* Cost summation of functions.We use alternately ccSum[0/1], thus
670 * ssSum[currSum] for recently read lines with same line number.
672 static AddrCost ccSum
[2];
676 * Print all costs of a BBCC:
677 * - FCCs of instructions
678 * - JCCs of the unique jump of this BB
679 * returns True if something was written
681 static Bool
fprint_bbcc(VgFile
*fp
, BBCC
* bbcc
, AddrPos
* last
)
683 InstrInfo
* instr_info
;
685 Bool something_written
= False
;
687 AddrCost
*currCost
, *newCost
;
688 Int jcc_count
= 0, instr
, i
, jmp
;
691 CLG_ASSERT(bbcc
->cxt
!= 0);
693 VG_(printf
)("+ fprint_bbcc (Instr %u): ", bb
->instr_count
);
694 CLG_(print_bbcc
)(15, bbcc
);
697 CLG_ASSERT(currSum
== 0 || currSum
== 1);
698 currCost
= &(ccSum
[currSum
]);
699 newCost
= &(ccSum
[1-currSum
]);
701 ecounter
= bbcc
->ecounter_sum
;
703 instr_info
= &(bb
->instr
[0]);
704 for(instr
=0; instr
<bb
->instr_count
; instr
++, instr_info
++) {
706 /* get debug info of current instruction address and dump cost
707 * if CLG_(clo).dump_bbs or file/line has changed
709 if (!get_debug_pos(bbcc
, bb_addr(bb
) + instr_info
->instr_offset
,
711 /* if we don't have debug info, don't switch to file "???" */
712 newCost
->p
.file
= bbcc
->cxt
->fn
[0]->file
;
715 if (CLG_(clo
).dump_bbs
|| CLG_(clo
).dump_instr
||
716 (newCost
->p
.line
!= currCost
->p
.line
) ||
717 (newCost
->p
.file
!= currCost
->p
.file
)) {
719 if (!CLG_(is_zero_cost
)( CLG_(sets
).full
, currCost
->cost
)) {
720 something_written
= True
;
722 fprint_apos(fp
, &(currCost
->p
), last
, bbcc
->cxt
->fn
[0]->file
);
723 fprint_fcost(fp
, currCost
, last
);
727 currSum
= 1 - currSum
;
728 currCost
= &(ccSum
[currSum
]);
729 newCost
= &(ccSum
[1-currSum
]);
732 /* add line cost to current cost sum */
733 (*CLG_(cachesim
).add_icost
)(currCost
->cost
, bbcc
, instr_info
, ecounter
);
735 /* print jcc's if there are: only jumps */
736 if (bb
->jmp
[jmp
].instr
== instr
) {
738 for(jcc
=bbcc
->jmp
[jmp
].jcc_list
; jcc
; jcc
=jcc
->next_from
)
739 if (((jcc
->jmpkind
!= jk_Call
) && (jcc
->call_counter
>0)) ||
740 (!CLG_(is_zero_cost
)( CLG_(sets
).full
, jcc
->cost
)))
744 if (!CLG_(is_zero_cost
)( CLG_(sets
).full
, currCost
->cost
)) {
745 /* no need to switch buffers, as position is the same */
746 fprint_apos(fp
, &(currCost
->p
), last
, bbcc
->cxt
->fn
[0]->file
);
747 fprint_fcost(fp
, currCost
, last
);
749 get_debug_pos(bbcc
, bb_addr(bb
)+instr_info
->instr_offset
, &(currCost
->p
));
750 fprint_apos(fp
, &(currCost
->p
), last
, bbcc
->cxt
->fn
[0]->file
);
751 something_written
= True
;
752 for(jcc
=bbcc
->jmp
[jmp
].jcc_list
; jcc
; jcc
=jcc
->next_from
) {
753 if (((jcc
->jmpkind
!= jk_Call
) && (jcc
->call_counter
>0)) ||
754 (!CLG_(is_zero_cost
)( CLG_(sets
).full
, jcc
->cost
)))
755 fprint_jcc(fp
, jcc
, &(currCost
->p
), last
, ecounter
);
760 /* update execution counter */
761 if (jmp
< bb
->cjmp_count
)
762 if (bb
->jmp
[jmp
].instr
== instr
) {
763 ecounter
-= bbcc
->jmp
[jmp
].ecounter
;
768 /* jCCs at end? If yes, dump cumulated line info first */
770 for(jcc
=bbcc
->jmp
[jmp
].jcc_list
; jcc
; jcc
=jcc
->next_from
) {
771 /* yes, if JCC only counts jmp arcs or cost >0 */
772 if ( ((jcc
->jmpkind
!= jk_Call
) && (jcc
->call_counter
>0)) ||
773 (!CLG_(is_zero_cost
)( CLG_(sets
).full
, jcc
->cost
)))
777 if ( (bbcc
->skipped
&&
778 !CLG_(is_zero_cost
)(CLG_(sets
).full
, bbcc
->skipped
)) ||
781 if (!CLG_(is_zero_cost
)( CLG_(sets
).full
, currCost
->cost
)) {
782 /* no need to switch buffers, as position is the same */
783 fprint_apos(fp
, &(currCost
->p
), last
, bbcc
->cxt
->fn
[0]->file
);
784 fprint_fcost(fp
, currCost
, last
);
787 get_debug_pos(bbcc
, bb_jmpaddr(bb
), &(currCost
->p
));
788 fprint_apos(fp
, &(currCost
->p
), last
, bbcc
->cxt
->fn
[0]->file
);
789 something_written
= True
;
791 /* first, print skipped costs for calls */
792 if (bbcc
->skipped
&& !CLG_(is_zero_cost
)( CLG_(sets
).full
,
794 CLG_(add_and_zero_cost
)( CLG_(sets
).full
,
795 currCost
->cost
, bbcc
->skipped
);
797 VG_(fprintf
)(fp
, "# Skipped\n");
799 fprint_fcost(fp
, currCost
, last
);
803 for(jcc
=bbcc
->jmp
[jmp
].jcc_list
; jcc
; jcc
=jcc
->next_from
) {
804 CLG_ASSERT(jcc
->jmp
== jmp
);
805 if ( ((jcc
->jmpkind
!= jk_Call
) && (jcc
->call_counter
>0)) ||
806 (!CLG_(is_zero_cost
)( CLG_(sets
).full
, jcc
->cost
)))
808 fprint_jcc(fp
, jcc
, &(currCost
->p
), last
, ecounter
);
812 if (CLG_(clo
).dump_bbs
|| CLG_(clo
).dump_bb
) {
813 if (!CLG_(is_zero_cost
)( CLG_(sets
).full
, currCost
->cost
)) {
814 something_written
= True
;
816 fprint_apos(fp
, &(currCost
->p
), last
, bbcc
->cxt
->fn
[0]->file
);
817 fprint_fcost(fp
, currCost
, last
);
819 if (CLG_(clo
).dump_bbs
) VG_(fprintf
)(fp
, "\n");
821 /* when every cost was immediately written, we must have done so,
822 * as this function is only called when there's cost in a BBCC
824 CLG_ASSERT(something_written
);
827 bbcc
->ecounter_sum
= 0;
828 for(i
=0; i
<=bbcc
->bb
->cjmp_count
; i
++)
829 bbcc
->jmp
[i
].ecounter
= 0;
830 bbcc
->ret_counter
= 0;
832 CLG_DEBUG(1, "- fprint_bbcc: JCCs %d\n", jcc_count
);
834 return something_written
;
839 * from->bb->obj, from->bb->fn
840 * obj, fn[0]->file, fn
843 static int my_cmp(BBCC
** pbbcc1
, BBCC
** pbbcc2
)
846 return (*pbbcc1
)->bb
->offset
- (*pbbcc2
)->bb
->offset
;
848 BBCC
*bbcc1
= *pbbcc1
;
849 BBCC
*bbcc2
= *pbbcc2
;
850 Context
* cxt1
= bbcc1
->cxt
;
851 Context
* cxt2
= bbcc2
->cxt
;
854 if (cxt1
->fn
[0]->file
->obj
!= cxt2
->fn
[0]->file
->obj
)
855 return cxt1
->fn
[0]->file
->obj
- cxt2
->fn
[0]->file
->obj
;
857 if (cxt1
->fn
[0]->file
!= cxt2
->fn
[0]->file
)
858 return cxt1
->fn
[0]->file
- cxt2
->fn
[0]->file
;
860 if (cxt1
->fn
[0] != cxt2
->fn
[0])
861 return cxt1
->fn
[0] - cxt2
->fn
[0];
863 if (bbcc1
->rec_index
!= bbcc2
->rec_index
)
864 return bbcc1
->rec_index
- bbcc2
->rec_index
;
866 while((off
< cxt1
->size
) && (off
< cxt2
->size
)) {
867 fn_node
* ffn1
= cxt1
->fn
[off
];
868 fn_node
* ffn2
= cxt2
->fn
[off
];
869 if (ffn1
->file
->obj
!= ffn2
->file
->obj
)
870 return ffn1
->file
->obj
- ffn2
->file
->obj
;
875 if (cxt1
->size
> cxt2
->size
) return 1;
876 else if (cxt1
->size
< cxt2
->size
) return -1;
878 return bbcc1
->bb
->offset
- bbcc2
->bb
->offset
;
886 /* modified version of:
888 * qsort -- qsort interface implemented by faster quicksort.
889 * J. L. Bentley and M. D. McIlroy, SPE 23 (1993) 1249-1265.
890 * Copyright 1993, John Wiley.
894 void swap(BBCC
** a
, BBCC
** b
)
897 t
= *a
; *a
= *b
; *b
= t
;
900 #define min(x, y) ((x)<=(y) ? (x) : (y))
903 BBCC
** med3(BBCC
**a
, BBCC
**b
, BBCC
**c
, int (*cmp
)(BBCC
**,BBCC
**))
904 { return cmp(a
, b
) < 0 ?
905 (cmp(b
, c
) < 0 ? b
: cmp(a
, c
) < 0 ? c
: a
)
906 : (cmp(b
, c
) > 0 ? b
: cmp(a
, c
) > 0 ? c
: a
);
909 static BBCC
** qsort_start
= 0;
911 static void CLG_(qsort
)(BBCC
**a
, int n
, int (*cmp
)(BBCC
**,BBCC
**))
913 BBCC
**pa
, **pb
, **pc
, **pd
, **pl
, **pm
, **pn
, **pv
;
917 CLG_DEBUG(8, " qsort(%ld,%ld)\n", a
-qsort_start
+ 0L, n
+ 0L);
919 if (n
< 7) { /* Insertion sort on smallest arrays */
920 for (pm
= a
+1; pm
< a
+n
; pm
++)
921 for (pl
= pm
; pl
> a
&& cmp(pl
-1, pl
) > 0; pl
--)
925 for (pm
= a
; pm
< a
+n
; pm
++) {
926 VG_(printf
)(" %3ld BB %#lx, ",
927 pm
- qsort_start
+ 0L,
929 CLG_(print_cxt
)(9, (*pm
)->cxt
, (*pm
)->rec_index
);
934 pm
= a
+ n
/2; /* Small arrays, middle element */
938 if (n
> 40) { /* Big arrays, pseudomedian of 9 */
940 pl
= med3(pl
, pl
+s
, pl
+2*s
, cmp
);
941 pm
= med3(pm
-s
, pm
, pm
+s
, cmp
);
942 pn
= med3(pn
-2*s
, pn
-s
, pn
, cmp
);
944 pm
= med3(pl
, pm
, pn
, cmp
); /* Mid-size, med of 3 */
953 while ((pb
<= pc
) && ((r
=cmp(pb
, pv
)) <= 0)) {
955 /* same as pivot, to start */
960 while ((pb
<= pc
) && ((r
=cmp(pc
, pv
)) >= 0)) {
962 /* same as pivot, to end */
967 if (pb
> pc
) { break; }
975 /* put pivot from start into middle */
976 if ((s
= pa
-a
)>0) { for(r
=0;r
<s
;r
++) swap(a
+r
, pb
+1-s
+r
); }
977 /* put pivot from end into middle */
978 if ((s
= a
+n
-1-pd
)>0) { for(r
=0;r
<s
;r
++) swap(pc
+r
, a
+n
-s
+r
); }
981 VG_(printf
)(" PV BB %#lx, ", bb_addr((*pv
)->bb
));
982 CLG_(print_cxt
)(9, (*pv
)->cxt
, (*pv
)->rec_index
);
985 VG_(printf
)(" Lower %ld - %ld:\n",
987 a
+s
-1-qsort_start
+ 0L);
990 VG_(printf
)(" %3ld BB %#lx, ",
993 CLG_(print_cxt
)(9, (*pm
)->cxt
, (*pm
)->rec_index
);
997 VG_(printf
)(" Upper %ld - %ld:\n",
998 a
+n
-s
-qsort_start
+ 0L,
999 a
+n
-1-qsort_start
+ 0L);
1002 VG_(printf
)(" %3ld BB %#lx, ",
1003 pm
-qsort_start
+ 0L,
1004 bb_addr((*pm
)->bb
));
1005 CLG_(print_cxt
)(9, (*pm
)->cxt
, (*pm
)->rec_index
);
1009 if ((s
= pb
+1-pa
) > 1) CLG_(qsort
)(a
, s
, cmp
);
1010 if ((s
= pd
+1-pc
) > 1) CLG_(qsort
)(a
+n
-s
, s
, cmp
);
1014 /* Helpers for prepare_dump */
1016 static Int prepare_count
;
1017 static BBCC
** prepare_ptr
;
1020 static void hash_addCount(BBCC
* bbcc
)
1022 if ((bbcc
->ecounter_sum
> 0) || (bbcc
->ret_counter
>0))
1026 static void hash_addPtr(BBCC
* bbcc
)
1028 if ((bbcc
->ecounter_sum
== 0) &&
1029 (bbcc
->ret_counter
== 0)) return;
1031 *prepare_ptr
= bbcc
;
1036 static void cs_addCount(thread_info
* ti
)
1041 /* add BBCCs with active call in call stack of current thread.
1042 * update cost sums for active calls
1045 for(i
= 0; i
< CLG_(current_call_stack
).sp
; i
++) {
1046 call_entry
* e
= &(CLG_(current_call_stack
).entry
[i
]);
1047 if (e
->jcc
== 0) continue;
1049 CLG_(add_diff_cost_lz
)( CLG_(sets
).full
, &(e
->jcc
->cost
),
1050 e
->enter_cost
, CLG_(current_state
).cost
);
1051 bbcc
= e
->jcc
->from
;
1053 CLG_DEBUG(1, " [%2d] (tid %u), added active: %s\n",
1054 i
,CLG_(current_tid
),bbcc
->cxt
->fn
[0]->name
);
1056 if (bbcc
->ecounter_sum
>0 || bbcc
->ret_counter
>0) {
1057 /* already counted */
1064 static void cs_addPtr(thread_info
* ti
)
1069 /* add BBCCs with active call in call stack of current thread.
1070 * update cost sums for active calls
1073 for(i
= 0; i
< CLG_(current_call_stack
).sp
; i
++) {
1074 call_entry
* e
= &(CLG_(current_call_stack
).entry
[i
]);
1075 if (e
->jcc
== 0) continue;
1077 bbcc
= e
->jcc
->from
;
1079 if (bbcc
->ecounter_sum
>0 || bbcc
->ret_counter
>0) {
1080 /* already counted */
1084 *prepare_ptr
= bbcc
;
1091 * Put all BBCCs with costs into a sorted array.
1092 * The returned arrays ends with a null pointer.
1093 * Must be freed after dumping.
1096 BBCC
** prepare_dump(void)
1102 /* if we do not separate among threads, this gives all */
1103 /* count number of BBCCs with >0 executions */
1104 CLG_(forall_bbccs
)(hash_addCount
);
1106 /* even if we do not separate among threads,
1107 * call stacks are separated */
1108 if (CLG_(clo
).separate_threads
)
1111 CLG_(forall_threads
)(cs_addCount
);
1113 CLG_DEBUG(0, "prepare_dump: %d BBCCs\n", prepare_count
);
1115 /* allocate bbcc array, insert BBCCs and sort */
1116 prepare_ptr
= array
=
1117 (BBCC
**) CLG_MALLOC("cl.dump.pd.1",
1118 (prepare_count
+1) * sizeof(BBCC
*));
1120 CLG_(forall_bbccs
)(hash_addPtr
);
1122 if (CLG_(clo
).separate_threads
)
1125 CLG_(forall_threads
)(cs_addPtr
);
1127 CLG_ASSERT(array
+ prepare_count
== prepare_ptr
);
1132 CLG_DEBUG(0," BBCCs inserted\n");
1134 qsort_start
= array
;
1135 CLG_(qsort
)(array
, prepare_count
, my_cmp
);
1137 CLG_DEBUG(0," BBCCs sorted\n");
1145 static void fprint_cost_ln(VgFile
*fp
, const HChar
* prefix
,
1146 const EventMapping
* em
, const ULong
* cost
)
1148 HChar
*mcost
= CLG_(mappingcost_as_string
)(em
, cost
);
1149 VG_(fprintf
)(fp
, "%s%s\n", prefix
, mcost
);
1153 static ULong bbs_done
= 0;
1154 static HChar
* filename
= 0;
1159 VG_(message
)(Vg_UserMsg
,
1160 "Error: can not open cache simulation output file `%s'\n",
1166 * Create a new dump file and write header.
1168 * Naming: <CLG_(clo).filename_base>.<pid>[.<part>][-<tid>]
1169 * <part> is skipped for final dump (trigger==0)
1170 * <tid> is skipped for thread 1 with CLG_(clo).separate_threads=no
1172 * Returns the file descriptor, and -1 on error (no write permission)
1174 static VgFile
*new_dumpfile(int tid
, const HChar
* trigger
)
1176 Bool appending
= False
;
1181 CLG_ASSERT(dumps_initialized
);
1182 CLG_ASSERT(filename
!= 0);
1184 if (!CLG_(clo
).combine_dumps
) {
1185 i
= VG_(sprintf
)(filename
, "%s", out_file
);
1188 i
+= VG_(sprintf
)(filename
+i
, ".%d", out_counter
);
1190 if (CLG_(clo
).separate_threads
)
1191 VG_(sprintf
)(filename
+i
, "-%02d", tid
);
1193 fp
= VG_(fopen
)(filename
, VKI_O_WRONLY
|VKI_O_TRUNC
, 0);
1196 VG_(sprintf
)(filename
, "%s", out_file
);
1197 fp
= VG_(fopen
)(filename
, VKI_O_WRONLY
|VKI_O_APPEND
, 0);
1198 if (fp
&& out_counter
>1)
1203 fp
= VG_(fopen
)(filename
, VKI_O_CREAT
|VKI_O_WRONLY
,
1204 VKI_S_IRUSR
|VKI_S_IWUSR
);
1206 /* If the file can not be opened for whatever reason (conflict
1207 between multiple supervised processes?), give up now. */
1212 CLG_DEBUG(2, " new_dumpfile '%s'\n", filename
);
1219 /* callgrind format specification, has to be on 1st line */
1220 VG_(fprintf
)(fp
, "# callgrind format\n");
1223 VG_(fprintf
)(fp
, "version: 1\n");
1226 VG_(fprintf
)(fp
, "creator: callgrind-" VERSION
"\n");
1229 VG_(fprintf
)(fp
, "pid: %d\n", VG_(getpid
)());
1232 VG_(fprintf
)(fp
, "cmd: %s", cmdbuf
);
1235 VG_(fprintf
)(fp
, "\npart: %d\n", out_counter
);
1236 if (CLG_(clo
).separate_threads
) {
1237 VG_(fprintf
)(fp
, "thread: %d\n", tid
);
1242 VG_(fprintf
)(fp
, "\n");
1245 /* Global options changing the tracing behaviour */
1246 VG_(fprintf
)(fp
, "\ndesc: Option: --skip-plt=%s\n",
1247 CLG_(clo
).skip_plt
? "yes" : "no");
1248 VG_(fprintf
)(fp
, "desc: Option: --collect-jumps=%s\n",
1249 CLG_(clo
).collect_jumps
? "yes" : "no");
1250 VG_(fprintf
)(fp
, "desc: Option: --separate-recs=%d\n",
1251 CLG_(clo
).separate_recursions
);
1252 VG_(fprintf
)(fp
, "desc: Option: --separate-callers=%d\n",
1253 CLG_(clo
).separate_callers
);
1255 VG_(fprintf
)(fp
, "desc: Option: --dump-bbs=%s\n",
1256 CLG_(clo
).dump_bbs
? "yes" : "no");
1257 VG_(fprintf
)(fp
, "desc: Option: --separate-threads=%s\n",
1258 CLG_(clo
).separate_threads
? "yes" : "no");
1261 (*CLG_(cachesim
).dump_desc
)(fp
);
1264 VG_(fprintf
)(fp
, "\ndesc: Timerange: Basic block %llu - %llu\n",
1265 bbs_done
, CLG_(stat
).bb_executions
);
1267 VG_(fprintf
)(fp
, "desc: Trigger: %s\n",
1268 trigger
? trigger
: "Program termination");
1271 /* Output function specific config
1273 for (i
= 0; i
< N_FNCONFIG_ENTRIES
; i
++) {
1277 VG_(fprintf
)(fp
, "desc: Option: --fn-skip=%s\n", fnc
->name
);
1279 if (fnc
->dump_at_enter
) {
1280 VG_(fprintf
)(fp
, "desc: Option: --fn-dump-at-enter=%s\n",
1283 if (fnc
->dump_at_leave
) {
1284 VG_(fprintf
)(fp
, "desc: Option: --fn-dump-at-leave=%s\n",
1287 if (fnc
->separate_callers
!= CLG_(clo
).separate_callers
) {
1288 VG_(fprintf
)(fp
, "desc: Option: --separate-callers%d=%s\n",
1289 fnc
->separate_callers
, fnc
->name
);
1291 if (fnc
->separate_recursions
!= CLG_(clo
).separate_recursions
) {
1292 VG_(fprintf
)(fp
, "desc: Option: --separate-recs%d=%s\n",
1293 fnc
->separate_recursions
, fnc
->name
);
1300 /* "positions:" line */
1301 VG_(fprintf
)(fp
, "\npositions:%s%s%s\n",
1302 CLG_(clo
).dump_instr
? " instr" : "",
1303 CLG_(clo
).dump_bb
? " bb" : "",
1304 CLG_(clo
).dump_line
? " line" : "");
1306 /* "events:" line */
1307 HChar
*evmap
= CLG_(eventmapping_as_string
)(CLG_(dumpmap
));
1308 VG_(fprintf
)(fp
, "events: %s\n", evmap
);
1312 sum
= CLG_(get_eventset_cost
)( CLG_(sets
).full
);
1313 CLG_(zero_cost
)(CLG_(sets
).full
, sum
);
1314 if (CLG_(clo
).separate_threads
) {
1315 thread_info
* ti
= CLG_(get_current_thread
)();
1316 CLG_(add_diff_cost
)(CLG_(sets
).full
, sum
, ti
->lastdump_cost
,
1317 ti
->states
.entry
[0]->cost
);
1320 /* This function is called once for thread 1, where
1321 * all costs are summed up when not dumping separate per thread.
1322 * But this is not true for summary: we need to add all threads.
1325 thread_info
** thr
= CLG_(get_threads
)();
1326 for(t
=1;t
<VG_N_THREADS
;t
++) {
1327 if (!thr
[t
]) continue;
1328 CLG_(add_diff_cost
)(CLG_(sets
).full
, sum
,
1329 thr
[t
]->lastdump_cost
,
1330 thr
[t
]->states
.entry
[0]->cost
);
1333 fprint_cost_ln(fp
, "summary: ", CLG_(dumpmap
), sum
);
1335 /* all dumped cost will be added to total_fcc */
1336 CLG_(init_cost_lz
)( CLG_(sets
).full
, &dump_total_cost
);
1338 VG_(fprintf
)(fp
, "\n\n");
1340 if (VG_(clo_verbosity
) > 1)
1341 VG_(message
)(Vg_DebugMsg
, "Dump to %s\n", filename
);
1347 static void close_dumpfile(VgFile
*fp
)
1349 if (fp
== NULL
) return;
1351 fprint_cost_ln(fp
, "totals: ", CLG_(dumpmap
),
1353 //fprint_fcc_ln(fp, "summary: ", &dump_total_fcc);
1354 CLG_(add_cost_lz
)(CLG_(sets
).full
,
1355 &CLG_(total_cost
), dump_total_cost
);
1359 if (filename
[0] == '.') {
1360 if (-1 == VG_(rename
) (filename
, filename
+1)) {
1361 /* Can not rename to correct file name: give out warning */
1362 VG_(message
)(Vg_DebugMsg
, "Warning: Can not rename .%s to %s\n",
1363 filename
, filename
);
1369 /* Helper for print_bbccs */
1371 static const HChar
* print_trigger
;
1373 static void print_bbccs_of_thread(thread_info
* ti
)
1379 CLG_DEBUG(1, "+ print_bbccs(tid %u)\n", CLG_(current_tid
));
1381 VgFile
*print_fp
= new_dumpfile(CLG_(current_tid
), print_trigger
);
1382 if (print_fp
== NULL
) {
1383 CLG_DEBUG(1, "- print_bbccs(tid %u): No output...\n", CLG_(current_tid
));
1387 p
= array
= prepare_dump();
1388 init_fpos(&lastFnPos
);
1389 init_apos(&lastAPos
, 0, 0, 0);
1393 /* on context/function change, print old cost buffer before */
1394 if (lastFnPos
.cxt
&& ((*p
==0) ||
1395 (lastFnPos
.cxt
!= (*p
)->cxt
) ||
1396 (lastFnPos
.rec_index
!= (*p
)->rec_index
))) {
1397 if (!CLG_(is_zero_cost
)( CLG_(sets
).full
, ccSum
[currSum
].cost
)) {
1398 /* no need to switch buffers, as position is the same */
1399 fprint_apos(print_fp
, &(ccSum
[currSum
].p
), &lastAPos
,
1400 lastFnPos
.cxt
->fn
[0]->file
);
1401 fprint_fcost(print_fp
, &ccSum
[currSum
], &lastAPos
);
1404 if (ccSum
[currSum
].p
.file
!= lastFnPos
.cxt
->fn
[0]->file
) {
1405 /* switch back to file of function */
1406 print_file(print_fp
, "fe=", lastFnPos
.cxt
->fn
[0]->file
);
1408 VG_(fprintf
)(print_fp
, "\n");
1413 if (print_fn_pos(print_fp
, &lastFnPos
, *p
)) {
1416 init_apos(&lastAPos
, 0, 0, (*p
)->cxt
->fn
[0]->file
);
1417 init_fcost(&ccSum
[0], 0, 0, 0);
1418 init_fcost(&ccSum
[1], 0, 0, 0);
1422 if (CLG_(clo
).dump_bbs
) {
1423 /* FIXME: Specify Object of BB if different to object of fn */
1425 ULong ecounter
= (*p
)->ecounter_sum
;
1426 VG_(fprintf
)(print_fp
, "bb=%#lx ", (UWord
)(*p
)->bb
->offset
);
1427 for(i
= 0; i
<(*p
)->bb
->cjmp_count
;i
++) {
1428 VG_(fprintf
)(print_fp
, "%u %llu ",
1429 (*p
)->bb
->jmp
[i
].instr
,
1431 ecounter
-= (*p
)->jmp
[i
].ecounter
;
1433 VG_(fprintf
)(print_fp
, "%u %llu\n",
1434 (*p
)->bb
->instr_count
,
1438 fprint_bbcc(print_fp
, *p
, &lastAPos
);
1443 close_dumpfile(print_fp
);
1446 /* set counters of last dump */
1447 CLG_(copy_cost
)( CLG_(sets
).full
, ti
->lastdump_cost
,
1448 CLG_(current_state
).cost
);
1450 CLG_DEBUG(1, "- print_bbccs(tid %u)\n", CLG_(current_tid
));
1454 static void print_bbccs(const HChar
* trigger
, Bool only_current_thread
)
1459 print_trigger
= trigger
;
1461 if (!CLG_(clo
).separate_threads
) {
1462 /* All BBCC/JCC costs is stored for thread 1 */
1463 Int orig_tid
= CLG_(current_tid
);
1465 CLG_(switch_thread
)(1);
1466 print_bbccs_of_thread( CLG_(get_current_thread
)() );
1467 CLG_(switch_thread
)(orig_tid
);
1469 else if (only_current_thread
)
1470 print_bbccs_of_thread( CLG_(get_current_thread
)() );
1472 CLG_(forall_threads
)(print_bbccs_of_thread
);
1478 void CLG_(dump_profile
)(const HChar
* trigger
, Bool only_current_thread
)
1480 CLG_DEBUG(2, "+ dump_profile(Trigger '%s')\n",
1481 trigger
? trigger
: "Prg.Term.");
1485 if (VG_(clo_verbosity
) > 1)
1486 VG_(message
)(Vg_DebugMsg
, "Start dumping at BB %llu (%s)...\n",
1487 CLG_(stat
).bb_executions
,
1488 trigger
? trigger
: "Prg.Term.");
1492 print_bbccs(trigger
, only_current_thread
);
1494 bbs_done
= CLG_(stat
).bb_executions
++;
1496 if (VG_(clo_verbosity
) > 1)
1497 VG_(message
)(Vg_DebugMsg
, "Dumping done.\n");
1500 /* Copy command to cmd buffer. We want to original command line
1501 * (can change at runtime)
1504 void init_cmdbuf(void)
1509 /* Pass #1: How many bytes do we need? */
1510 size
= 1; // leading ' '
1511 size
+= VG_(strlen
)( VG_(args_the_exename
) );
1512 for (i
= 0; i
< VG_(sizeXA
)( VG_(args_for_client
) ); i
++) {
1513 const HChar
*arg
= *(HChar
**)VG_(indexXA
)( VG_(args_for_client
), i
);
1514 size
+= 1; // separator ' '
1515 // escape NL in arguments to not break dump format
1516 for(j
=0; arg
[j
]; j
++)
1520 size
++; // fall through
1526 cmdbuf
= CLG_MALLOC("cl.dump.ic.1", size
+ 1); // +1 for '\0'
1528 /* Pass #2: Build up the string */
1529 size
= VG_(sprintf
)(cmdbuf
, " %s", VG_(args_the_exename
));
1531 for(i
= 0; i
< VG_(sizeXA
)( VG_(args_for_client
) ); i
++) {
1532 const HChar
*arg
= * (HChar
**) VG_(indexXA
)( VG_(args_for_client
), i
);
1533 cmdbuf
[size
++] = ' ';
1534 for(j
=0; arg
[j
]; j
++)
1537 cmdbuf
[size
++] = '\\';
1538 cmdbuf
[size
++] = 'n';
1541 cmdbuf
[size
++] = '\\';
1542 cmdbuf
[size
++] = '\\';
1545 cmdbuf
[size
++] = arg
[j
];
1549 cmdbuf
[size
] = '\0';
1553 * Set up file names for dump output: <out_file>.
1554 * <out_file> is derived from the output format string, which defaults
1555 * to "callgrind.out.%p", where %p is replaced with the PID.
1556 * For the final file name, on intermediate dumps a counter is appended,
1557 * and further, if separate dumps per thread are requested, the thread ID.
1559 * <out_file> always starts with a full absolute path.
1560 * If the output format string represents a relative path, the current
1561 * working directory at program start is used.
1563 * This function has to be called every time a profile dump is generated
1564 * to be able to react on PID changes.
1566 void CLG_(init_dumps
)()
1570 static int thisPID
= 0;
1571 int currentPID
= VG_(getpid
)();
1572 if (currentPID
== thisPID
) {
1573 /* already initialized, and no PID change */
1574 CLG_ASSERT(out_file
!= 0);
1577 thisPID
= currentPID
;
1579 if (!CLG_(clo
).out_format
)
1580 CLG_(clo
).out_format
= DEFAULT_OUTFORMAT
;
1582 /* If a file name was already set, clean up before */
1584 VG_(free
)(out_file
);
1585 VG_(free
)(filename
);
1589 // Setup output filename.
1591 VG_(expand_file_name
)("--callgrind-out-file", CLG_(clo
).out_format
);
1593 /* allocate space big enough for final filenames */
1594 filename
= (HChar
*) CLG_MALLOC("cl.dump.init_dumps.2",
1595 VG_(strlen
)(out_file
)+32);
1597 /* Make sure the output base file can be written.
1598 * This is used for the dump at program termination.
1599 * We stop with an error here if we can not create the
1600 * file: This is probably because of missing rights,
1601 * and trace parts wouldn't be allowed to be written, too.
1603 VG_(strcpy
)(filename
, out_file
);
1604 res
= VG_(open
)(filename
, VKI_O_WRONLY
|VKI_O_TRUNC
, 0);
1605 if (sr_isError(res
)) {
1606 res
= VG_(open
)(filename
, VKI_O_CREAT
|VKI_O_WRONLY
,
1607 VKI_S_IRUSR
|VKI_S_IWUSR
);
1608 if (sr_isError(res
)) {
1612 if (!sr_isError(res
)) VG_(close
)( (Int
)sr_Res(res
) );
1614 if (!dumps_initialized
)
1617 dumps_initialized
= True
;