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, see <http://www.gnu.org/licenses/>.
24 The GNU General Public License is contained in the file COPYING.
29 /*------------------------------------------------------------*/
30 /*--- Jump Cost Center (JCC) operations, including Calls ---*/
31 /*------------------------------------------------------------*/
33 #define N_JCC_INITIAL_ENTRIES 4437
35 static jcc_hash current_jccs
;
37 void CLG_(init_jcc_hash
)(jcc_hash
* jccs
)
41 CLG_ASSERT(jccs
!= 0);
43 jccs
->size
= N_JCC_INITIAL_ENTRIES
;
45 jccs
->table
= (jCC
**) CLG_MALLOC("cl.jumps.ijh.1",
46 jccs
->size
* sizeof(jCC
*));
47 jccs
->spontaneous
= 0;
49 for (i
= 0; i
< jccs
->size
; i
++)
54 void CLG_(copy_current_jcc_hash
)(jcc_hash
* dst
)
58 dst
->size
= current_jccs
.size
;
59 dst
->entries
= current_jccs
.entries
;
60 dst
->table
= current_jccs
.table
;
61 dst
->spontaneous
= current_jccs
.spontaneous
;
64 void CLG_(set_current_jcc_hash
)(jcc_hash
* h
)
68 current_jccs
.size
= h
->size
;
69 current_jccs
.entries
= h
->entries
;
70 current_jccs
.table
= h
->table
;
71 current_jccs
.spontaneous
= h
->spontaneous
;
75 static UInt
jcc_hash_idx(BBCC
* from
, UInt jmp
, BBCC
* to
, UInt size
)
77 return (UInt
) ( (UWord
)from
+ 7* (UWord
)to
+ 13*jmp
) % size
;
80 /* double size of jcc table */
81 static void resize_jcc_table(void)
83 Int i
, new_size
, conflicts1
= 0, conflicts2
= 0;
86 jCC
*curr_jcc
, *next_jcc
;
88 new_size
= 2* current_jccs
.size
+3;
89 new_table
= (jCC
**) CLG_MALLOC("cl.jumps.rjt.1",
90 new_size
* sizeof(jCC
*));
92 for (i
= 0; i
< new_size
; i
++)
95 for (i
= 0; i
< current_jccs
.size
; i
++) {
96 if (current_jccs
.table
[i
] == NULL
) continue;
98 curr_jcc
= current_jccs
.table
[i
];
99 while (NULL
!= curr_jcc
) {
100 next_jcc
= curr_jcc
->next_hash
;
102 new_idx
= jcc_hash_idx(curr_jcc
->from
, curr_jcc
->jmp
,
103 curr_jcc
->to
, new_size
);
105 curr_jcc
->next_hash
= new_table
[new_idx
];
106 new_table
[new_idx
] = curr_jcc
;
107 if (curr_jcc
->next_hash
) {
109 if (curr_jcc
->next_hash
->next_hash
)
117 VG_(free
)(current_jccs
.table
);
120 CLG_DEBUG(0, "Resize JCC Hash: %u => %d (entries %u, conflicts %d/%d)\n",
121 current_jccs
.size
, new_size
,
122 current_jccs
.entries
, conflicts1
, conflicts2
);
124 current_jccs
.size
= new_size
;
125 current_jccs
.table
= new_table
;
126 CLG_(stat
).jcc_hash_resizes
++;
131 /* new jCC structure: a call was done to a BB of a BBCC
132 * for a spontaneous call, from is 0 (i.e. caller unknown)
134 static jCC
* new_jcc(BBCC
* from
, UInt jmp
, BBCC
* to
)
139 /* check fill degree of jcc hash table and resize if needed (>80%) */
140 current_jccs
.entries
++;
141 if (10 * current_jccs
.entries
/ current_jccs
.size
> 8)
144 jcc
= (jCC
*) CLG_MALLOC("cl.jumps.nj.1", sizeof(jCC
));
149 jcc
->jmpkind
= jk_Call
;
150 jcc
->call_counter
= 0;
153 /* insert into JCC chain of calling BBCC.
154 * This list is only used at dumping time */
157 /* Prohibit corruption by array overrun */
158 CLG_ASSERT(jmp
<= from
->bb
->cjmp_count
);
159 jcc
->next_from
= from
->jmp
[jmp
].jcc_list
;
160 from
->jmp
[jmp
].jcc_list
= jcc
;
163 jcc
->next_from
= current_jccs
.spontaneous
;
164 current_jccs
.spontaneous
= jcc
;
167 /* insert into JCC hash table */
168 new_idx
= jcc_hash_idx(from
, jmp
, to
, current_jccs
.size
);
169 jcc
->next_hash
= current_jccs
.table
[new_idx
];
170 current_jccs
.table
[new_idx
] = jcc
;
172 CLG_(stat
).distinct_jccs
++;
175 VG_(printf
)(" new_jcc (now %d): %p\n",
176 CLG_(stat
).distinct_jccs
, jcc
);
183 /* get the jCC for a call arc (BBCC->BBCC) */
184 jCC
* CLG_(get_jcc
)(BBCC
* from
, UInt jmp
, BBCC
* to
)
189 CLG_DEBUG(5, "+ get_jcc(bbcc %p/%u => bbcc %p)\n",
192 /* first check last recently used JCC */
193 jcc
= to
->lru_to_jcc
;
194 if (jcc
&& (jcc
->from
== from
) && (jcc
->jmp
== jmp
)) {
195 CLG_ASSERT(to
== jcc
->to
);
196 CLG_DEBUG(5,"- get_jcc: [LRU to] jcc %p\n", jcc
);
200 jcc
= from
->lru_from_jcc
;
201 if (jcc
&& (jcc
->to
== to
) && (jcc
->jmp
== jmp
)) {
202 CLG_ASSERT(from
== jcc
->from
);
203 CLG_DEBUG(5, "- get_jcc: [LRU from] jcc %p\n", jcc
);
207 CLG_(stat
).jcc_lru_misses
++;
209 idx
= jcc_hash_idx(from
, jmp
, to
, current_jccs
.size
);
210 jcc
= current_jccs
.table
[idx
];
213 if ((jcc
->from
== from
) &&
215 (jcc
->to
== to
)) break;
216 jcc
= jcc
->next_hash
;
220 jcc
= new_jcc(from
, jmp
, to
);
223 from
->lru_from_jcc
= jcc
;
224 to
->lru_to_jcc
= jcc
;
226 CLG_DEBUG(5, "- get_jcc(bbcc %p => bbcc %p)\n",