blob: cbbc7b65f9376fff64e46d5b999c71d698d79a67 [file] [log] [blame]
weidendoa17f2a32006-03-20 10:27:30 +00001/*--------------------------------------------------------------------*/
2/*--- Callgrind ---*/
3/*--- ct_jumps.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7 This file is part of Callgrind, a Valgrind tool for call tracing.
8
sewardj45057902006-06-05 23:27:18 +00009 Copyright (C) 2002-2006, Josef Weidendorfer (Josef.Weidendorfer@gmx.de)
weidendoa17f2a32006-03-20 10:27:30 +000010
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License as
13 published by the Free Software Foundation; either version 2 of the
14 License, or (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24 02111-1307, USA.
25
26 The GNU General Public License is contained in the file COPYING.
27*/
28
29#include "global.h"
30
31#define N_JCC_INITIAL_ENTRIES 4437
32
33/*------------------------------------------------------------*/
34/*--- Jump Cost Center (JCC) operations, including Calls ---*/
35/*------------------------------------------------------------*/
36
37#define N_JCC_INITIAL_ENTRIES 4437
38
39jcc_hash current_jccs;
40
41void CLG_(init_jcc_hash)(jcc_hash* jccs)
42{
43 Int i;
44
45 CLG_ASSERT(jccs != 0);
46
47 jccs->size = N_JCC_INITIAL_ENTRIES;
48 jccs->entries = 0;
49 jccs->table = (jCC**) CLG_MALLOC(jccs->size * sizeof(jCC*));
50 jccs->spontaneous = 0;
51
52 for (i = 0; i < jccs->size; i++)
53 jccs->table[i] = 0;
54}
55
56
57void CLG_(copy_current_jcc_hash)(jcc_hash* dst)
58{
59 CLG_ASSERT(dst != 0);
60
61 dst->size = current_jccs.size;
62 dst->entries = current_jccs.entries;
63 dst->table = current_jccs.table;
64 dst->spontaneous = current_jccs.spontaneous;
65}
66
67void CLG_(set_current_jcc_hash)(jcc_hash* h)
68{
69 CLG_ASSERT(h != 0);
70
71 current_jccs.size = h->size;
72 current_jccs.entries = h->entries;
73 current_jccs.table = h->table;
74 current_jccs.spontaneous = h->spontaneous;
75}
76
77__inline__
78static UInt jcc_hash_idx(BBCC* from, UInt jmp, BBCC* to, UInt size)
79{
80 return (UInt) ( (UWord)from + 7* (UWord)to + 13*jmp) % size;
81}
82
83/* double size of jcc table */
84static void resize_jcc_table(void)
85{
86 Int i, new_size, conflicts1 = 0, conflicts2 = 0;
87 jCC** new_table;
88 UInt new_idx;
89 jCC *curr_jcc, *next_jcc;
90
91 new_size = 2* current_jccs.size +3;
92 new_table = (jCC**) CLG_MALLOC(new_size * sizeof(jCC*));
93
94 if (!new_table) return;
95
96 for (i = 0; i < new_size; i++)
97 new_table[i] = NULL;
98
99 for (i = 0; i < current_jccs.size; i++) {
100 if (current_jccs.table[i] == NULL) continue;
101
102 curr_jcc = current_jccs.table[i];
103 while (NULL != curr_jcc) {
104 next_jcc = curr_jcc->next_hash;
105
106 new_idx = jcc_hash_idx(curr_jcc->from, curr_jcc->jmp,
107 curr_jcc->to, new_size);
108
109 curr_jcc->next_hash = new_table[new_idx];
110 new_table[new_idx] = curr_jcc;
111 if (curr_jcc->next_hash) {
112 conflicts1++;
113 if (curr_jcc->next_hash->next_hash)
114 conflicts2++;
115 }
116
117 curr_jcc = next_jcc;
118 }
119 }
120
121 VG_(free)(current_jccs.table);
122
123
124 CLG_DEBUG(0, "Resize JCC Hash: %d => %d (entries %d, conflicts %d/%d)\n",
125 current_jccs.size, new_size,
126 current_jccs.entries, conflicts1, conflicts2);
127
128 current_jccs.size = new_size;
129 current_jccs.table = new_table;
130 CLG_(stat).jcc_hash_resizes++;
131}
132
133
134
135/* new jCC structure: a call was done to a BB of a BBCC
136 * for a spontaneous call, from is 0 (i.e. caller unknown)
137 */
138static jCC* new_jcc(BBCC* from, UInt jmp, BBCC* to)
139{
140 jCC* new;
141 UInt new_idx;
142
143 /* check fill degree of jcc hash table and resize if needed (>80%) */
144 current_jccs.entries++;
145 if (10 * current_jccs.entries / current_jccs.size > 8)
146 resize_jcc_table();
147
148 new = (jCC*) CLG_MALLOC(sizeof(jCC));
149
150 new->from = from;
151 new->jmp = jmp;
152 new->to = to;
153 new->jmpkind = Ijk_Call;
154 new->call_counter = 0;
155 new->cost = 0;
156
157 /* insert into JCC chain of calling BBCC.
158 * This list is only used at dumping time */
159
160 if (from) {
161 new->next_from = from->jmp[jmp].jcc_list;
162 from->jmp[jmp].jcc_list = new;
163 }
164 else {
165 new->next_from = current_jccs.spontaneous;
166 current_jccs.spontaneous = new;
167 }
168
169 /* insert into JCC hash table */
170 new_idx = jcc_hash_idx(from, jmp, to, current_jccs.size);
171 new->next_hash = current_jccs.table[new_idx];
172 current_jccs.table[new_idx] = new;
173
174 CLG_(stat).distinct_jccs++;
175
176 CLG_DEBUGIF(3) {
177 VG_(printf)(" new_jcc (now %d): %p\n",
178 CLG_(stat).distinct_jccs, new);
179 }
180
181 return new;
182}
183
184
185/* get the jCC for a call arc (BBCC->BBCC) */
186jCC* CLG_(get_jcc)(BBCC* from, UInt jmp, BBCC* to)
187{
188 jCC* jcc;
189 UInt idx;
190
191 CLG_DEBUG(5, "+ get_jcc(bbcc %p/%d => bbcc %p)\n",
192 from, jmp, to);
193
194 /* first check last recently used JCC */
195 jcc = to->lru_to_jcc;
196 if (jcc && (jcc->from == from) && (jcc->jmp == jmp)) {
197 CLG_ASSERT(to == jcc->to);
198 CLG_DEBUG(5,"- get_jcc: [LRU to] jcc %p\n", jcc);
199 return jcc;
200 }
201
202 jcc = from->lru_from_jcc;
203 if (jcc && (jcc->to == to) && (jcc->jmp == jmp)) {
204 CLG_ASSERT(from == jcc->from);
205 CLG_DEBUG(5, "- get_jcc: [LRU from] jcc %p\n", jcc);
206 return jcc;
207 }
208
209 CLG_(stat).jcc_lru_misses++;
210
211 idx = jcc_hash_idx(from, jmp, to, current_jccs.size);
212 jcc = current_jccs.table[idx];
213
214 while(jcc) {
215 if ((jcc->from == from) &&
216 (jcc->jmp == jmp) &&
217 (jcc->to == to)) break;
218 jcc = jcc->next_hash;
219 }
220
221 if (!jcc)
222 jcc = new_jcc(from, jmp, to);
223
224 /* set LRU */
225 from->lru_from_jcc = jcc;
226 to->lru_to_jcc = jcc;
227
228 CLG_DEBUG(5, "- get_jcc(bbcc %p => bbcc %p)\n",
229 from, to);
230
231 return jcc;
232}
233