1 /*--------------------------------------------------------------------*/
3 /*--- ct_context.c ---*/
4 /*--------------------------------------------------------------------*/
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
26 The GNU General Public License is contained in the file COPYING.
32 /*------------------------------------------------------------*/
33 /*--- Context operations ---*/
34 /*------------------------------------------------------------*/
36 #define N_FNSTACK_INITIAL_ENTRIES 500
37 #define N_CXT_INITIAL_ENTRIES 2537
39 fn_stack
CLG_(current_fn_stack
);
41 void CLG_(init_fn_stack
)(fn_stack
* s
)
45 s
->size
= N_FNSTACK_INITIAL_ENTRIES
;
46 s
->bottom
= (fn_node
**) CLG_MALLOC("cl.context.ifs.1",
47 s
->size
* sizeof(fn_node
*));
52 void CLG_(copy_current_fn_stack
)(fn_stack
* dst
)
56 dst
->size
= CLG_(current_fn_stack
).size
;
57 dst
->bottom
= CLG_(current_fn_stack
).bottom
;
58 dst
->top
= CLG_(current_fn_stack
).top
;
61 void CLG_(set_current_fn_stack
)(fn_stack
* s
)
65 CLG_(current_fn_stack
).size
= s
->size
;
66 CLG_(current_fn_stack
).bottom
= s
->bottom
;
67 CLG_(current_fn_stack
).top
= s
->top
;
72 void CLG_(init_cxt_table
)()
76 cxts
.size
= N_CXT_INITIAL_ENTRIES
;
78 cxts
.table
= (Context
**) CLG_MALLOC("cl.context.ict.1",
79 cxts
.size
* sizeof(Context
*));
81 for (i
= 0; i
< cxts
.size
; i
++)
85 /* double size of cxt table */
86 static void resize_cxt_table(void)
88 UInt i
, new_size
, conflicts1
= 0, conflicts2
= 0;
89 Context
**new_table
, *curr
, *next
;
92 new_size
= 2* cxts
.size
+3;
93 new_table
= (Context
**) CLG_MALLOC("cl.context.rct.1",
94 new_size
* sizeof(Context
*));
96 if (!new_table
) return;
98 for (i
= 0; i
< new_size
; i
++)
101 for (i
= 0; i
< cxts
.size
; i
++) {
102 if (cxts
.table
[i
] == NULL
) continue;
104 curr
= cxts
.table
[i
];
105 while (NULL
!= curr
) {
108 new_idx
= (UInt
) (curr
->hash
% new_size
);
110 curr
->next
= new_table
[new_idx
];
111 new_table
[new_idx
] = curr
;
114 if (curr
->next
->next
)
122 VG_(free
)(cxts
.table
);
125 CLG_DEBUG(0, "Resize Context Hash: %d => %d (entries %d, conflicts %d/%d)\n",
127 cxts
.entries
, conflicts1
, conflicts2
);
129 cxts
.size
= new_size
;
130 cxts
.table
= new_table
;
131 CLG_(stat
).cxt_hash_resizes
++;
135 static UWord
cxt_hash_val(fn_node
** fn
, UInt size
)
140 hash
= (hash
<<7) + (hash
>>25) + (UWord
)(*fn
);
149 static Bool
is_cxt(UWord hash
, fn_node
** fn
, Context
* cxt
)
154 if (hash
!= cxt
->hash
) return False
;
157 cxt_fn
= &(cxt
->fn
[0]);
158 while((*fn
!= 0) && (count
>0)) {
159 if (*cxt_fn
!= *fn
) return False
;
168 * Allocate new Context structure
170 static Context
* new_cxt(fn_node
** fn
)
180 if (top_fn
== 0) return 0;
182 size
= top_fn
->separate_callers
+1;
183 recs
= top_fn
->separate_recursions
;
186 /* check fill degree of context hash table and resize if needed (>80%) */
188 if (10 * cxts
.entries
/ cxts
.size
> 8)
191 cxt
= (Context
*) CLG_MALLOC("cl.context.nc.1",
192 sizeof(Context
)+sizeof(fn_node
*)*size
);
194 // hash value calculation similar to cxt_hash_val(), but additionally
195 // copying function pointers in one run
199 hash
= (hash
<<7) + (hash
>>25) + (UWord
)(*fn
);
200 cxt
->fn
[offset
] = *fn
;
203 if (offset
>= size
) break;
205 if (offset
< size
) size
= offset
;
208 cxt
->base_number
= CLG_(stat
).context_counter
;
211 CLG_(stat
).context_counter
+= recs
;
212 CLG_(stat
).distinct_contexts
++;
214 /* insert into Context hash table */
215 idx
= (UInt
) (hash
% cxts
.size
);
216 cxt
->next
= cxts
.table
[idx
];
217 cxts
.table
[idx
] = cxt
;
221 VG_(printf
)(" new_cxt ox%p: ", cxt
);
222 CLG_(print_cxt
)(12, cxt
, 0);
229 /* get the Context structure for current context */
230 Context
* CLG_(get_cxt
)(fn_node
** fn
)
237 if (*fn
== 0) return 0;
238 size
= (*fn
)->separate_callers
+1;
239 if (size
<=0) { size
= -size
+1; }
241 CLG_DEBUG(5, "+ get_cxt(fn '%s'): size %d\n",
244 hash
= cxt_hash_val(fn
, size
);
246 if ( ((cxt
= (*fn
)->last_cxt
) != 0) && is_cxt(hash
, fn
, cxt
)) {
247 CLG_DEBUG(5, "- get_cxt: %p\n", cxt
);
251 CLG_(stat
).cxt_lru_misses
++;
253 idx
= (UInt
) (hash
% cxts
.size
);
254 cxt
= cxts
.table
[idx
];
257 if (is_cxt(hash
,fn
,cxt
)) break;
264 (*fn
)->last_cxt
= cxt
;
266 CLG_DEBUG(5, "- get_cxt: %p\n", cxt
);
273 * Change execution context by calling a new function from current context
274 * Pushing 0x0 specifies a marker for a signal handler entry
276 void CLG_(push_cxt
)(fn_node
* fn
)
278 call_stack
* cs
= &CLG_(current_call_stack
);
281 CLG_DEBUG(5, "+ push_cxt(fn '%s'): old ctx %d\n",
282 fn
? fn
->name
: "0x0",
283 CLG_(current_state
).cxt
?
284 CLG_(current_state
).cxt
->base_number
: -1);
286 /* save old context on stack (even if not changed at all!) */
287 CLG_ASSERT(cs
->sp
< cs
->size
);
288 CLG_ASSERT(cs
->entry
[cs
->sp
].cxt
== 0);
289 cs
->entry
[cs
->sp
].cxt
= CLG_(current_state
).cxt
;
290 cs
->entry
[cs
->sp
].fn_sp
= CLG_(current_fn_stack
).top
- CLG_(current_fn_stack
).bottom
;
292 if (fn
&& (*(CLG_(current_fn_stack
).top
) == fn
)) return;
293 if (fn
&& (fn
->group
>0) &&
294 ((*(CLG_(current_fn_stack
).top
))->group
== fn
->group
)) return;
296 /* resizing needed ? */
297 fn_entries
= CLG_(current_fn_stack
).top
- CLG_(current_fn_stack
).bottom
;
298 if (fn_entries
== CLG_(current_fn_stack
).size
-1) {
299 int new_size
= CLG_(current_fn_stack
).size
*2;
300 fn_node
** new_array
= (fn_node
**) CLG_MALLOC("cl.context.pc.1",
301 new_size
* sizeof(fn_node
*));
303 for(i
=0;i
<CLG_(current_fn_stack
).size
;i
++)
304 new_array
[i
] = CLG_(current_fn_stack
).bottom
[i
];
305 VG_(free
)(CLG_(current_fn_stack
).bottom
);
306 CLG_(current_fn_stack
).top
= new_array
+ fn_entries
;
307 CLG_(current_fn_stack
).bottom
= new_array
;
309 CLG_DEBUG(0, "Resize Context Stack: %d => %d (pushing '%s')\n",
310 CLG_(current_fn_stack
).size
, new_size
,
311 fn
? fn
->name
: "0x0");
313 CLG_(current_fn_stack
).size
= new_size
;
316 if (fn
&& (*(CLG_(current_fn_stack
).top
) == 0)) {
319 /* this is first function: increment its active count */
320 pactive
= CLG_(get_fn_entry
)(fn
->number
);
324 CLG_(current_fn_stack
).top
++;
325 *(CLG_(current_fn_stack
).top
) = fn
;
326 CLG_(current_state
).cxt
= CLG_(get_cxt
)(CLG_(current_fn_stack
).top
);
328 CLG_DEBUG(5, "- push_cxt(fn '%s'): new cxt %d, fn_sp %ld\n",
329 fn
? fn
->name
: "0x0",
330 CLG_(current_state
).cxt
?
331 CLG_(current_state
).cxt
->base_number
: -1,
332 CLG_(current_fn_stack
).top
- CLG_(current_fn_stack
).bottom
+ 0L);