Add bug 467036 Add time cost statistics for Regtest to NEWS
[valgrind.git] / callgrind / bb.c
blobda64caa13e6fbfd03e1683e7b67e7eb8193b6f4d
1 /*--------------------------------------------------------------------*/
2 /*--- Callgrind ---*/
3 /*--- bb.c ---*/
4 /*--------------------------------------------------------------------*/
6 /*
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, see <http://www.gnu.org/licenses/>.
24 The GNU General Public License is contained in the file COPYING.
27 #include "global.h"
29 /*------------------------------------------------------------*/
30 /*--- Basic block (BB) operations ---*/
31 /*------------------------------------------------------------*/
33 /* BB hash, resizable */
34 bb_hash bbs;
36 void CLG_(init_bb_hash)()
38 Int i;
40 bbs.size = 8437;
41 bbs.entries = 0;
42 bbs.table = (BB**) CLG_MALLOC("cl.bb.ibh.1",
43 bbs.size * sizeof(BB*));
45 for (i = 0; i < bbs.size; i++) bbs.table[i] = NULL;
48 bb_hash* CLG_(get_bb_hash)()
50 return &bbs;
53 /* The hash stores BBs according to
54 * - ELF object (is 0 for code in anonymous mapping)
55 * - BB base as object file offset
57 static __inline__
58 UInt bb_hash_idx(obj_node* obj, PtrdiffT offset, UInt size)
60 return (((Addr)obj) + offset) % size;
63 /* double size of bb table */
64 static
65 void resize_bb_table(void)
67 Int i, new_size, conflicts1 = 0, conflicts2 = 0;
68 BB **new_table, *curr, *next;
69 UInt new_idx;
71 new_size = 2* bbs.size +3;
72 new_table = (BB**) CLG_MALLOC("cl.bb.rbt.1",
73 new_size * sizeof(BB*));
75 for (i = 0; i < new_size; i++)
76 new_table[i] = NULL;
78 for (i = 0; i < bbs.size; i++) {
79 if (bbs.table[i] == NULL) continue;
81 curr = bbs.table[i];
82 while (NULL != curr) {
83 next = curr->next;
85 new_idx = bb_hash_idx(curr->obj, curr->offset, new_size);
87 curr->next = new_table[new_idx];
88 new_table[new_idx] = curr;
89 if (curr->next) {
90 conflicts1++;
91 if (curr->next->next)
92 conflicts2++;
95 curr = next;
99 VG_(free)(bbs.table);
102 CLG_DEBUG(0, "Resize BB Hash: %u => %d (entries %u, conflicts %d/%d)\n",
103 bbs.size, new_size,
104 bbs.entries, conflicts1, conflicts2);
106 bbs.size = new_size;
107 bbs.table = new_table;
108 CLG_(stat).bb_hash_resizes++;
113 * Allocate new BB structure (including space for event type list)
114 * Not initialized:
115 * - instr_len, cost_count, instr[]
117 static BB* new_bb(obj_node* obj, PtrdiffT offset,
118 UInt instr_count, UInt cjmp_count, Bool cjmp_inverted)
120 BB* bb;
121 UInt idx, size;
123 /* check fill degree of bb hash table and resize if needed (>80%) */
124 bbs.entries++;
125 if (10 * bbs.entries / bbs.size > 8)
126 resize_bb_table();
128 size = sizeof(BB) + instr_count * sizeof(InstrInfo)
129 + (cjmp_count+1) * sizeof(CJmpInfo);
130 bb = (BB*) CLG_MALLOC("cl.bb.nb.1", size);
131 VG_(memset)(bb, 0, size);
133 bb->obj = obj;
134 bb->offset = offset;
136 bb->instr_count = instr_count;
137 bb->cjmp_count = cjmp_count;
138 bb->cjmp_inverted = cjmp_inverted;
139 bb->jmp = (CJmpInfo*) &(bb->instr[instr_count]);
140 bb->instr_len = 0;
141 bb->cost_count = 0;
142 bb->sect_kind = VG_(DebugInfo_sect_kind)(NULL, offset + obj->offset);
143 bb->fn = 0;
144 bb->line = 0;
145 bb->is_entry = 0;
146 bb->bbcc_list = 0;
147 bb->last_bbcc = 0;
149 /* insert into BB hash table */
150 idx = bb_hash_idx(obj, offset, bbs.size);
151 bb->next = bbs.table[idx];
152 bbs.table[idx] = bb;
154 CLG_(stat).distinct_bbs++;
156 #if CLG_ENABLE_DEBUG
157 CLG_DEBUGIF(3) {
158 VG_(printf)(" new_bb (instr %u, jmps %u, inv %s) [now %d]: ",
159 instr_count, cjmp_count,
160 cjmp_inverted ? "yes":"no",
161 CLG_(stat).distinct_bbs);
162 CLG_(print_bb)(0, bb);
163 VG_(printf)("\n");
165 #endif
167 CLG_(get_fn_node)(bb);
169 return bb;
173 /* get the BB structure for a BB start address */
174 static __inline__
175 BB* lookup_bb(obj_node* obj, PtrdiffT offset)
177 BB* bb;
178 Int idx;
180 idx = bb_hash_idx(obj, offset, bbs.size);
181 bb = bbs.table[idx];
183 while(bb) {
184 if ((bb->obj == obj) && (bb->offset == offset)) break;
185 bb = bb->next;
188 CLG_DEBUG(5, " lookup_bb (Obj %s, off %#lx): %p\n",
189 obj->name, (UWord)offset, bb);
190 return bb;
193 static __inline__
194 obj_node* obj_of_address(Addr addr)
196 obj_node* obj;
197 DebugInfo* di;
198 PtrdiffT offset;
200 DiEpoch ep = VG_(current_DiEpoch)();
201 di = VG_(find_DebugInfo)(ep, addr);
202 obj = CLG_(get_obj_node)( di );
204 /* Update symbol offset in object if remapped */
205 /* FIXME (or at least check this) 2008 Feb 19: 'offset' is
206 only correct for text symbols, not for data symbols */
207 offset = di ? VG_(DebugInfo_get_text_bias)(di):0;
208 if (obj->offset != offset) {
209 Addr start = di ? VG_(DebugInfo_get_text_avma)(di) : 0;
211 CLG_DEBUG(0, "Mapping changed for '%s': %#lx -> %#lx\n",
212 obj->name, obj->start, start);
214 /* Size should be the same, and offset diff == start diff */
215 CLG_ASSERT( obj->size == (di ? VG_(DebugInfo_get_text_size)(di) : 0) );
216 CLG_ASSERT( obj->start - start == obj->offset - offset );
217 obj->offset = offset;
218 obj->start = start;
221 return obj;
224 /* Get the BB structure for a BB start address.
225 * If the BB has to be created, the IRBB is needed to
226 * compute the event type list for costs, and seen_before is
227 * set to False. Otherwise, seen_before is set to True.
229 * BBs are never discarded. There are 2 cases where this function
230 * is called from CLG_(instrument)() and a BB already exists:
231 * - The instrumented version was removed from Valgrinds TT cache
232 * - The ELF object of the BB was unmapped and mapped again.
233 * This involves a possibly different address, but is handled by
234 * looking up a BB keyed by (obj_node, file offset).
236 * bbIn==0 is possible for artificial BB without real code.
237 * Such a BB is created when returning to an unknown function.
239 BB* CLG_(get_bb)(Addr addr, IRSB* bbIn, /*OUT*/ Bool *seen_before)
241 BB* bb;
242 obj_node* obj;
243 UInt n_instrs, n_jmps;
244 Bool cjmp_inverted = False;
246 CLG_DEBUG(5, "+ get_bb(BB %#lx)\n", addr);
248 obj = obj_of_address(addr);
249 bb = lookup_bb(obj, addr - obj->offset);
251 n_instrs = 0;
252 n_jmps = 0;
253 CLG_(collectBlockInfo)(bbIn, &n_instrs, &n_jmps, &cjmp_inverted);
255 *seen_before = bb ? True : False;
256 if (*seen_before) {
257 if (bb->instr_count != n_instrs) {
258 VG_(message)(Vg_DebugMsg,
259 "ERROR: BB Retranslation Mismatch at BB %#lx\n", addr);
260 VG_(message)(Vg_DebugMsg,
261 " new: Obj %s, Off %#lx, BBOff %#lx, Instrs %u\n",
262 obj->name, (UWord)obj->offset,
263 addr - obj->offset, n_instrs);
264 VG_(message)(Vg_DebugMsg,
265 " old: Obj %s, Off %#lx, BBOff %#lx, Instrs %u\n",
266 bb->obj->name, (UWord)bb->obj->offset,
267 (UWord)bb->offset, bb->instr_count);
268 CLG_ASSERT(bb->instr_count == n_instrs );
270 CLG_ASSERT(bb->cjmp_count == n_jmps );
271 CLG_(stat).bb_retranslations++;
273 CLG_DEBUG(5, "- get_bb(BB %#lx): seen before.\n", addr);
274 return bb;
277 bb = new_bb(obj, addr - obj->offset, n_instrs, n_jmps, cjmp_inverted);
279 CLG_DEBUG(5, "- get_bb(BB %#lx)\n", addr);
281 return bb;
284 /* Delete the BB info for the bb with unredirected entry-point
285 address 'addr'. */
286 void CLG_(delete_bb)(Addr addr)
288 BB *bb, *bp;
289 Int idx, size;
291 obj_node* obj = obj_of_address(addr);
292 PtrdiffT offset = addr - obj->offset;
294 idx = bb_hash_idx(obj, offset, bbs.size);
295 bb = bbs.table[idx];
297 /* bb points at the current bb under consideration, and bp is the
298 one before. */
299 bp = NULL;
300 while(bb) {
301 if ((bb->obj == obj) && (bb->offset == offset)) break;
302 bp = bb;
303 bb = bb->next;
306 if (bb == NULL) {
307 CLG_DEBUG(3, " delete_bb (Obj %s, off %#lx): NOT FOUND\n",
308 obj->name, (UWord)offset);
310 /* we didn't find it.
311 * this happens when callgrinds instrumentation mode
312 * was off at BB translation time, ie. no BB was created.
314 return;
317 /* unlink it from hash table */
319 if (bp == NULL) {
320 /* we found the first one in the list. */
321 tl_assert(bb == bbs.table[idx]);
322 bbs.table[idx] = bb->next;
323 } else {
324 tl_assert(bb != bbs.table[idx]);
325 bp->next = bb->next;
328 CLG_DEBUG(3, " delete_bb (Obj %s, off %#lx): %p, BBCC head: %p\n",
329 obj->name, (UWord)offset, bb, bb->bbcc_list);
331 if (bb->bbcc_list == 0) {
332 /* can be safely deleted */
334 /* Fill the block up with junk and then free it, so we will
335 hopefully get a segfault if it is used again by mistake. */
336 size = sizeof(BB)
337 + bb->instr_count * sizeof(InstrInfo)
338 + (bb->cjmp_count+1) * sizeof(CJmpInfo);
339 VG_(memset)( bb, 0xAA, size );
340 CLG_FREE(bb);
341 return;
343 CLG_DEBUG(3, " delete_bb: BB in use, can not free!\n");