blob: da3bd1b4c3cad34adc256827bc23fbc22e83f4e2 [file] [log] [blame]
sewardj07133bf2002-06-13 10:25:56 +00001
njn4f9c9342002-04-29 16:03:24 +00002/*--------------------------------------------------------------------*/
njn101e5722005-04-21 02:37:54 +00003/*--- Cachegrind: everything but the simulation itself. ---*/
njn25cac76cb2002-09-23 11:21:57 +00004/*--- cg_main.c ---*/
njn4f9c9342002-04-29 16:03:24 +00005/*--------------------------------------------------------------------*/
6
7/*
nethercote137bc552003-11-14 17:47:54 +00008 This file is part of Cachegrind, a Valgrind tool for cache
njnc9539842002-10-02 13:26:35 +00009 profiling programs.
njn4f9c9342002-04-29 16:03:24 +000010
njn53612422005-03-12 16:22:54 +000011 Copyright (C) 2002-2005 Nicholas Nethercote
njn2bc10122005-05-08 02:10:27 +000012 njn@valgrind.org
njn4f9c9342002-04-29 16:03:24 +000013
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
njn25e49d8e72002-09-23 09:36:25 +000029 The GNU General Public License is contained in the file COPYING.
njn4f9c9342002-04-29 16:03:24 +000030*/
31
njnc7561b92005-06-19 01:24:32 +000032#include "pub_tool_basics.h"
njnea27e462005-05-31 02:38:09 +000033#include "pub_tool_debuginfo.h"
njn81c00df2005-05-14 21:28:43 +000034#include "pub_tool_hashtable.h"
njn97405b22005-06-02 03:39:33 +000035#include "pub_tool_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000036#include "pub_tool_libcassert.h"
njneb8896b2005-06-04 20:03:55 +000037#include "pub_tool_libcfile.h"
njn36a20fa2005-06-03 03:08:39 +000038#include "pub_tool_libcprint.h"
njnf39e9a32005-06-12 02:43:17 +000039#include "pub_tool_libcproc.h"
njnf536bbb2005-06-13 04:21:38 +000040#include "pub_tool_machine.h"
njn717cde52005-05-10 02:47:21 +000041#include "pub_tool_mallocfree.h"
njn20242342005-05-16 23:31:24 +000042#include "pub_tool_options.h"
njn31513b42005-06-01 03:09:59 +000043#include "pub_tool_profile.h"
njn43b9a8a2005-05-10 04:37:01 +000044#include "pub_tool_tooliface.h"
sewardj45f4e7c2005-09-27 19:20:21 +000045#include "pub_tool_clientstate.h"
njn25e49d8e72002-09-23 09:36:25 +000046
nethercoteb35a8b92004-09-11 16:45:27 +000047#include "cg_arch.h"
nethercote27fc1da2004-01-04 16:56:57 +000048#include "cg_sim.c"
njn4f9c9342002-04-29 16:03:24 +000049
njn25e49d8e72002-09-23 09:36:25 +000050/*------------------------------------------------------------*/
51/*--- Constants ---*/
52/*------------------------------------------------------------*/
njn4f9c9342002-04-29 16:03:24 +000053
sewardj5155dec2005-10-12 10:09:23 +000054/* Set to 1 for very verbose debugging */
55#define DEBUG_CG 0
56
nethercote9313ac42004-07-06 21:54:20 +000057#define MIN_LINE_SIZE 16
58#define FILE_LEN 256
59#define FN_LEN 256
njn7cf0bd32002-06-08 13:36:03 +000060
61/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +000062/*--- Profiling events ---*/
njn7cf0bd32002-06-08 13:36:03 +000063/*------------------------------------------------------------*/
64
njn25e49d8e72002-09-23 09:36:25 +000065typedef
66 enum {
nethercote9313ac42004-07-06 21:54:20 +000067 VgpGetLineCC = VgpFini+1,
njn25e49d8e72002-09-23 09:36:25 +000068 VgpCacheSimulate,
69 VgpCacheResults
70 }
nethercote7cc9c232004-01-21 15:08:04 +000071 VgpToolCC;
sewardj07133bf2002-06-13 10:25:56 +000072
njn4f9c9342002-04-29 16:03:24 +000073/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +000074/*--- Types and Data Structures ---*/
njn4f9c9342002-04-29 16:03:24 +000075/*------------------------------------------------------------*/
76
77typedef struct _CC CC;
78struct _CC {
79 ULong a;
80 ULong m1;
81 ULong m2;
82};
83
nethercote9313ac42004-07-06 21:54:20 +000084//------------------------------------------------------------
85// Primary data structure #1: CC table
86// - Holds the per-source-line hit/miss stats, grouped by file/function/line.
87// - hash(file, hash(fn, hash(line+CC)))
88// - Each hash table is separately chained.
89// - The array sizes below work fairly well for Konqueror.
90// - Lookups done by instr_addr, which is converted immediately to a source
91// location.
92// - Traversed for dumping stats at end in file/func/line hierarchy.
njn4f9c9342002-04-29 16:03:24 +000093
94#define N_FILE_ENTRIES 251
95#define N_FN_ENTRIES 53
nethercote9313ac42004-07-06 21:54:20 +000096#define N_LINE_ENTRIES 37
njn4f9c9342002-04-29 16:03:24 +000097
nethercote9313ac42004-07-06 21:54:20 +000098typedef struct _lineCC lineCC;
99struct _lineCC {
100 Int line;
101 CC Ir;
102 CC Dr;
103 CC Dw;
104 lineCC* next;
njn4f9c9342002-04-29 16:03:24 +0000105};
106
nethercote9313ac42004-07-06 21:54:20 +0000107typedef struct _fnCC fnCC;
108struct _fnCC {
109 Char* fn;
110 fnCC* next;
111 lineCC* lines[N_LINE_ENTRIES];
njn4f9c9342002-04-29 16:03:24 +0000112};
113
nethercote9313ac42004-07-06 21:54:20 +0000114typedef struct _fileCC fileCC;
115struct _fileCC {
116 Char* file;
117 fileCC* next;
118 fnCC* fns[N_FN_ENTRIES];
njn4f9c9342002-04-29 16:03:24 +0000119};
120
nethercote9313ac42004-07-06 21:54:20 +0000121// Top level of CC table. Auto-zeroed.
122static fileCC *CC_table[N_FILE_ENTRIES];
njn4f9c9342002-04-29 16:03:24 +0000123
nethercote9313ac42004-07-06 21:54:20 +0000124//------------------------------------------------------------
njnf69f9452005-07-03 17:53:11 +0000125// Primary data structure #2: Instr-info table
nethercote9313ac42004-07-06 21:54:20 +0000126// - Holds the cached info about each instr that is used for simulation.
127// - table(BB_start_addr, list(instr_info))
128// - For each BB, each instr_info in the list holds info about the
njn6a3009b2005-03-20 00:20:06 +0000129// instruction (instr_len, instr_addr, etc), plus a pointer to its line
nethercote9313ac42004-07-06 21:54:20 +0000130// CC. This node is what's passed to the simulation function.
131// - When BBs are discarded the relevant list(instr_details) is freed.
132
133typedef struct _instr_info instr_info;
134struct _instr_info {
nethercoteca1f2dc2004-07-21 08:49:02 +0000135 Addr instr_addr;
njn6a3009b2005-03-20 00:20:06 +0000136 UChar instr_len;
nethercoteca1f2dc2004-07-21 08:49:02 +0000137 lineCC* parent; // parent line-CC
nethercote9313ac42004-07-06 21:54:20 +0000138};
139
140typedef struct _BB_info BB_info;
141struct _BB_info {
142 BB_info* next; // next field
143 Addr BB_addr; // key
144 Int n_instrs;
145 instr_info instrs[0];
146};
147
148VgHashTable instr_info_table; // hash(Addr, BB_info)
149
150//------------------------------------------------------------
151// Stats
sewardj4f29ddf2002-05-03 22:29:04 +0000152static Int distinct_files = 0;
153static Int distinct_fns = 0;
nethercote9313ac42004-07-06 21:54:20 +0000154static Int distinct_lines = 0;
sewardj4f29ddf2002-05-03 22:29:04 +0000155static Int distinct_instrs = 0;
nethercote9313ac42004-07-06 21:54:20 +0000156
sewardj4f29ddf2002-05-03 22:29:04 +0000157static Int full_debug_BBs = 0;
158static Int file_line_debug_BBs = 0;
nethercote9313ac42004-07-06 21:54:20 +0000159static Int fn_debug_BBs = 0;
sewardj4f29ddf2002-05-03 22:29:04 +0000160static Int no_debug_BBs = 0;
njn4f9c9342002-04-29 16:03:24 +0000161
sewardj4f29ddf2002-05-03 22:29:04 +0000162static Int BB_retranslations = 0;
njn4f9c9342002-04-29 16:03:24 +0000163
nethercote9313ac42004-07-06 21:54:20 +0000164/*------------------------------------------------------------*/
165/*--- CC table operations ---*/
166/*------------------------------------------------------------*/
njn4294fd42002-06-05 14:41:10 +0000167
nethercote9313ac42004-07-06 21:54:20 +0000168static void get_debug_info(Addr instr_addr, Char file[FILE_LEN],
169 Char fn[FN_LEN], Int* line)
njn4f9c9342002-04-29 16:03:24 +0000170{
sewardj7cee6f92005-06-13 17:39:06 +0000171 Bool found_file_line = VG_(get_filename_linenum)(
172 instr_addr,
173 file, FILE_LEN,
174 NULL, 0, NULL,
175 line
176 );
nethercote9313ac42004-07-06 21:54:20 +0000177 Bool found_fn = VG_(get_fnname)(instr_addr, fn, FN_LEN);
njn4f9c9342002-04-29 16:03:24 +0000178
nethercote9313ac42004-07-06 21:54:20 +0000179 if (!found_file_line) {
180 VG_(strcpy)(file, "???");
181 *line = 0;
182 }
183 if (!found_fn) {
184 VG_(strcpy)(fn, "???");
185 }
186 if (found_file_line) {
187 if (found_fn) full_debug_BBs++;
188 else file_line_debug_BBs++;
189 } else {
190 if (found_fn) fn_debug_BBs++;
191 else no_debug_BBs++;
njn4f9c9342002-04-29 16:03:24 +0000192 }
193}
194
njn4f9c9342002-04-29 16:03:24 +0000195static UInt hash(Char *s, UInt table_size)
196{
njn0103de52005-10-10 16:49:01 +0000197 const Int hash_constant = 256;
198 Int hash_value = 0;
nethercote9313ac42004-07-06 21:54:20 +0000199 for ( ; *s; s++)
200 hash_value = (hash_constant * hash_value + *s) % table_size;
201 return hash_value;
njn4f9c9342002-04-29 16:03:24 +0000202}
203
nethercote9313ac42004-07-06 21:54:20 +0000204static __inline__
205fileCC* new_fileCC(Char filename[], fileCC* next)
nethercote09d853e2004-01-21 16:12:55 +0000206{
nethercote9313ac42004-07-06 21:54:20 +0000207 // Using calloc() zeroes the fns[] array
208 fileCC* cc = VG_(calloc)(1, sizeof(fileCC));
209 cc->file = VG_(strdup)(filename);
210 cc->next = next;
211 return cc;
nethercote09d853e2004-01-21 16:12:55 +0000212}
213
nethercote9313ac42004-07-06 21:54:20 +0000214static __inline__
215fnCC* new_fnCC(Char fn[], fnCC* next)
njn4f9c9342002-04-29 16:03:24 +0000216{
nethercote9313ac42004-07-06 21:54:20 +0000217 // Using calloc() zeroes the lines[] array
218 fnCC* cc = VG_(calloc)(1, sizeof(fnCC));
219 cc->fn = VG_(strdup)(fn);
220 cc->next = next;
221 return cc;
222}
njn4f9c9342002-04-29 16:03:24 +0000223
nethercote9313ac42004-07-06 21:54:20 +0000224static __inline__
225lineCC* new_lineCC(Int line, lineCC* next)
226{
227 // Using calloc() zeroes the Ir/Dr/Dw CCs and the instrs[] array
228 lineCC* cc = VG_(calloc)(1, sizeof(lineCC));
229 cc->line = line;
230 cc->next = next;
231 return cc;
232}
njn4f9c9342002-04-29 16:03:24 +0000233
nethercote9313ac42004-07-06 21:54:20 +0000234// Do a three step traversal: by file, then fn, then line.
235// In all cases prepends new nodes to their chain. Returns a pointer to the
236// line node, creates a new one if necessary.
njn6a3009b2005-03-20 00:20:06 +0000237static lineCC* get_lineCC(Addr origAddr)
nethercote9313ac42004-07-06 21:54:20 +0000238{
239 fileCC *curr_fileCC;
240 fnCC *curr_fnCC;
241 lineCC *curr_lineCC;
242 Char file[FILE_LEN], fn[FN_LEN];
243 Int line;
244 UInt file_hash, fn_hash, line_hash;
245
njn6a3009b2005-03-20 00:20:06 +0000246 get_debug_info(origAddr, file, fn, &line);
nethercote9313ac42004-07-06 21:54:20 +0000247
248 VGP_PUSHCC(VgpGetLineCC);
249
250 // level 1
251 file_hash = hash(file, N_FILE_ENTRIES);
252 curr_fileCC = CC_table[file_hash];
253 while (NULL != curr_fileCC && !VG_STREQ(file, curr_fileCC->file)) {
254 curr_fileCC = curr_fileCC->next;
njn4f9c9342002-04-29 16:03:24 +0000255 }
nethercote9313ac42004-07-06 21:54:20 +0000256 if (NULL == curr_fileCC) {
257 CC_table[file_hash] = curr_fileCC =
258 new_fileCC(file, CC_table[file_hash]);
njn4f9c9342002-04-29 16:03:24 +0000259 distinct_files++;
260 }
261
nethercote9313ac42004-07-06 21:54:20 +0000262 // level 2
263 fn_hash = hash(fn, N_FN_ENTRIES);
264 curr_fnCC = curr_fileCC->fns[fn_hash];
265 while (NULL != curr_fnCC && !VG_STREQ(fn, curr_fnCC->fn)) {
266 curr_fnCC = curr_fnCC->next;
njn4f9c9342002-04-29 16:03:24 +0000267 }
nethercote9313ac42004-07-06 21:54:20 +0000268 if (NULL == curr_fnCC) {
269 curr_fileCC->fns[fn_hash] = curr_fnCC =
270 new_fnCC(fn, curr_fileCC->fns[fn_hash]);
njn4f9c9342002-04-29 16:03:24 +0000271 distinct_fns++;
272 }
273
nethercote9313ac42004-07-06 21:54:20 +0000274 // level 3
275 line_hash = line % N_LINE_ENTRIES;
276 curr_lineCC = curr_fnCC->lines[line_hash];
277 while (NULL != curr_lineCC && line != curr_lineCC->line) {
278 curr_lineCC = curr_lineCC->next;
njn4f9c9342002-04-29 16:03:24 +0000279 }
nethercote9313ac42004-07-06 21:54:20 +0000280 if (NULL == curr_lineCC) {
281 curr_fnCC->lines[line_hash] = curr_lineCC =
282 new_lineCC(line, curr_fnCC->lines[line_hash]);
283 distinct_lines++;
njn4f9c9342002-04-29 16:03:24 +0000284 }
nethercote9313ac42004-07-06 21:54:20 +0000285
286 VGP_POPCC(VgpGetLineCC);
287 return curr_lineCC;
njn4f9c9342002-04-29 16:03:24 +0000288}
289
290/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +0000291/*--- Cache simulation functions ---*/
njn4f9c9342002-04-29 16:03:24 +0000292/*------------------------------------------------------------*/
293
njnaf839f52005-06-23 03:27:57 +0000294static VG_REGPARM(1)
nethercote9313ac42004-07-06 21:54:20 +0000295void log_1I_0D_cache_access(instr_info* n)
njn25e49d8e72002-09-23 09:36:25 +0000296{
sewardj5155dec2005-10-12 10:09:23 +0000297 //VG_(printf)("1I_0D : CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n",
298 // n, n->instr_addr, n->instr_len);
njn25e49d8e72002-09-23 09:36:25 +0000299 VGP_PUSHCC(VgpCacheSimulate);
njn6a3009b2005-03-20 00:20:06 +0000300 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000301 &n->parent->Ir.m1, &n->parent->Ir.m2);
302 n->parent->Ir.a++;
njn25e49d8e72002-09-23 09:36:25 +0000303 VGP_POPCC(VgpCacheSimulate);
304}
305
njnaf839f52005-06-23 03:27:57 +0000306static VG_REGPARM(2)
sewardj5155dec2005-10-12 10:09:23 +0000307void log_2I_0D_cache_access(instr_info* n, instr_info* n2)
njn25e49d8e72002-09-23 09:36:25 +0000308{
sewardj5155dec2005-10-12 10:09:23 +0000309 //VG_(printf)("2I_0D : CC1addr=0x%010lx, i1addr=0x%010lx, i1size=%lu\n"
310 // " CC2addr=0x%010lx, i2addr=0x%010lx, i2size=%lu\n",
311 // n, n->instr_addr, n->instr_len,
312 // n2, n2->instr_addr, n2->instr_len);
313 VGP_PUSHCC(VgpCacheSimulate);
314 cachesim_I1_doref(n->instr_addr, n->instr_len,
315 &n->parent->Ir.m1, &n->parent->Ir.m2);
316 n->parent->Ir.a++;
317 cachesim_I1_doref(n2->instr_addr, n2->instr_len,
318 &n2->parent->Ir.m1, &n2->parent->Ir.m2);
319 n2->parent->Ir.a++;
320 VGP_POPCC(VgpCacheSimulate);
321}
322
323static VG_REGPARM(3)
324void log_3I_0D_cache_access(instr_info* n, instr_info* n2, instr_info* n3)
325{
326 //VG_(printf)("3I_0D : CC1addr=0x%010lx, i1addr=0x%010lx, i1size=%lu\n"
327 // " CC2addr=0x%010lx, i2addr=0x%010lx, i2size=%lu\n"
328 // " CC3addr=0x%010lx, i3addr=0x%010lx, i3size=%lu\n",
329 // n, n->instr_addr, n->instr_len,
330 // n2, n2->instr_addr, n2->instr_len,
331 // n3, n3->instr_addr, n3->instr_len);
332 VGP_PUSHCC(VgpCacheSimulate);
333 cachesim_I1_doref(n->instr_addr, n->instr_len,
334 &n->parent->Ir.m1, &n->parent->Ir.m2);
335 n->parent->Ir.a++;
336 cachesim_I1_doref(n2->instr_addr, n2->instr_len,
337 &n2->parent->Ir.m1, &n2->parent->Ir.m2);
338 n2->parent->Ir.a++;
339 cachesim_I1_doref(n3->instr_addr, n3->instr_len,
340 &n3->parent->Ir.m1, &n3->parent->Ir.m2);
341 n3->parent->Ir.a++;
342 VGP_POPCC(VgpCacheSimulate);
343}
344
345static VG_REGPARM(3)
346void log_1I_1Dr_cache_access(instr_info* n, Addr data_addr, Word data_size)
347{
348 //VG_(printf)("1I_1Dr: CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n"
349 // " daddr=0x%010lx, dsize=%lu\n",
350 // n, n->instr_addr, n->instr_len, data_addr, data_size);
njn25e49d8e72002-09-23 09:36:25 +0000351 VGP_PUSHCC(VgpCacheSimulate);
njn6a3009b2005-03-20 00:20:06 +0000352 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000353 &n->parent->Ir.m1, &n->parent->Ir.m2);
354 n->parent->Ir.a++;
njn25e49d8e72002-09-23 09:36:25 +0000355
sewardj5155dec2005-10-12 10:09:23 +0000356 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000357 &n->parent->Dr.m1, &n->parent->Dr.m2);
358 n->parent->Dr.a++;
njn25e49d8e72002-09-23 09:36:25 +0000359 VGP_POPCC(VgpCacheSimulate);
360}
361
sewardj5155dec2005-10-12 10:09:23 +0000362static VG_REGPARM(3)
363void log_1I_1Dw_cache_access(instr_info* n, Addr data_addr, Word data_size)
njn25e49d8e72002-09-23 09:36:25 +0000364{
sewardj5155dec2005-10-12 10:09:23 +0000365 //VG_(printf)("1I_1Dw: CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n"
366 // " daddr=0x%010lx, dsize=%lu\n",
367 // n, n->instr_addr, n->instr_len, data_addr, data_size);
njn25e49d8e72002-09-23 09:36:25 +0000368 VGP_PUSHCC(VgpCacheSimulate);
njn6a3009b2005-03-20 00:20:06 +0000369 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000370 &n->parent->Ir.m1, &n->parent->Ir.m2);
371 n->parent->Ir.a++;
372
sewardj5155dec2005-10-12 10:09:23 +0000373 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000374 &n->parent->Dw.m1, &n->parent->Dw.m2);
375 n->parent->Dw.a++;
njn25e49d8e72002-09-23 09:36:25 +0000376 VGP_POPCC(VgpCacheSimulate);
377}
378
njnaf839f52005-06-23 03:27:57 +0000379static VG_REGPARM(3)
sewardj5155dec2005-10-12 10:09:23 +0000380void log_0I_1Dr_cache_access(instr_info* n, Addr data_addr, Word data_size)
njn25e49d8e72002-09-23 09:36:25 +0000381{
sewardj5155dec2005-10-12 10:09:23 +0000382 //VG_(printf)("0I_1Dr: CCaddr=0x%010lx, daddr=0x%010lx, dsize=%lu\n",
383 // n, data_addr, data_size);
njn25e49d8e72002-09-23 09:36:25 +0000384 VGP_PUSHCC(VgpCacheSimulate);
sewardj5155dec2005-10-12 10:09:23 +0000385 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000386 &n->parent->Dr.m1, &n->parent->Dr.m2);
387 n->parent->Dr.a++;
sewardj5155dec2005-10-12 10:09:23 +0000388 VGP_POPCC(VgpCacheSimulate);
389}
390
391static VG_REGPARM(3)
392void log_0I_1Dw_cache_access(instr_info* n, Addr data_addr, Word data_size)
393{
394 //VG_(printf)("0I_1Dw: CCaddr=0x%010lx, daddr=0x%010lx, dsize=%lu\n",
395 // n, data_addr, data_size);
396 VGP_PUSHCC(VgpCacheSimulate);
397 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000398 &n->parent->Dw.m1, &n->parent->Dw.m2);
399 n->parent->Dw.a++;
njn25e49d8e72002-09-23 09:36:25 +0000400 VGP_POPCC(VgpCacheSimulate);
401}
402
nethercote9313ac42004-07-06 21:54:20 +0000403/*------------------------------------------------------------*/
sewardj5155dec2005-10-12 10:09:23 +0000404/*--- Instrumentation types and structures ---*/
405/*------------------------------------------------------------*/
406
407/* Maintain an ordered list of memory events which are outstanding, in
408 the sense that no IR has yet been generated to do the relevant
409 helper calls. The BB is scanned top to bottom and memory events
410 are added to the end of the list, merging with the most recent
411 notified event where possible (Dw immediately following Dr and
412 having the same size and EA can be merged).
413
414 This merging is done so that for architectures which have
415 load-op-store instructions (x86, amd64), the insn is treated as if
416 it makes just one memory reference (a modify), rather than two (a
417 read followed by a write at the same address).
418
419 At various points the list will need to be flushed, that is, IR
420 generated from it. That must happen before any possible exit from
421 the block (the end, or an IRStmt_Exit). Flushing also takes place
422 when there is no space to add a new event.
423
424 If we require the simulation statistics to be up to date with
425 respect to possible memory exceptions, then the list would have to
426 be flushed before each memory reference. That would however lose
427 performance by inhibiting event-merging during flushing.
428
429 Flushing the list consists of walking it start to end and emitting
430 instrumentation IR for each event, in the order in which they
431 appear. It may be possible to emit a single call for two adjacent
432 events in order to reduce the number of helper function calls made.
433 For example, it could well be profitable to handle two adjacent Ir
434 events with a single helper call. */
435
436typedef
437 IRExpr
438 IRAtom;
439
440typedef
sewardj20edebf2005-10-12 10:29:40 +0000441 enum { Event_Ir, Event_Dr, Event_Dw, Event_Dm }
sewardj5155dec2005-10-12 10:09:23 +0000442 EventKind;
443
444typedef
445 struct {
446 EventKind ekind;
447 Int size; /* ALL */
448 Addr64 iaddr; /* ALL. For Dr/Dw/Dm is & of parent insn. */
449 IRAtom* dataEA; /* Dr/Dw/Dm only */ /* IR ATOM ONLY */
450 }
451 Event;
452
453/* Up to this many unnotified events are allowed. Number is
454 arbitrary. Larger numbers allow more event merging to occur, but
455 potentially induce more spilling due to extending live ranges of
456 address temporaries. */
457#define N_EVENTS 16
458
459
460/* A struct which holds all the running state during instrumentation.
461 Mostly to avoid passing loads of parameters everywhere. */
462typedef
463 struct {
464 /* The current outstanding-memory-event list. */
465 Event events[N_EVENTS];
466 Int events_used;
467
468 /* The array of instr_info bins for the BB. */
469 BB_info* bbInfo;
470
471 /* Number instr_info bins 'used' so far. */
472 Int bbInfo_i;
473
sewardj5155dec2005-10-12 10:09:23 +0000474 /* The output BB being constructed. */
475 IRBB* bbOut;
476 }
477 CgState;
478
479
sewardj5155dec2005-10-12 10:09:23 +0000480/*------------------------------------------------------------*/
481/*--- Instrumentation main ---*/
nethercote9313ac42004-07-06 21:54:20 +0000482/*------------------------------------------------------------*/
483
nethercote564b2b02004-08-07 15:54:53 +0000484static
sewardja3a29a52005-10-12 16:16:03 +0000485BB_info* get_BB_info(IRBB* bbIn, Addr origAddr)
nethercote9313ac42004-07-06 21:54:20 +0000486{
njn4bd67b52005-08-11 00:47:10 +0000487 Int i, n_instrs;
488 IRStmt* st;
489 BB_info* bbInfo;
nethercote9313ac42004-07-06 21:54:20 +0000490
njn6a3009b2005-03-20 00:20:06 +0000491 // Count number of original instrs in BB
492 n_instrs = 0;
493 for (i = 0; i < bbIn->stmts_used; i++) {
494 st = bbIn->stmts[i];
495 if (Ist_IMark == st->tag) n_instrs++;
nethercote9313ac42004-07-06 21:54:20 +0000496 }
497
njnf7d26092005-10-12 16:45:17 +0000498 // Check that we don't have an entry for this BB in the instr-info table.
499 // If this assertion fails, there has been some screwup: some
500 // translations must have been discarded but Cachegrind hasn't discarded
501 // the corresponding entries in the instr-info table.
njn4bd67b52005-08-11 00:47:10 +0000502 bbInfo = (BB_info*)VG_(HT_lookup)(instr_info_table, origAddr);
sewardja3a29a52005-10-12 16:16:03 +0000503 tl_assert(NULL == bbInfo);
504
505 // BB has never translated before (at this address, at least; could
506 // have been unloaded and then reloaded elsewhere in memory).
507 bbInfo = VG_(calloc)(1, sizeof(BB_info) + n_instrs*sizeof(instr_info));
508 bbInfo->BB_addr = origAddr;
509 bbInfo->n_instrs = n_instrs;
510 VG_(HT_add_node)( instr_info_table, (VgHashNode*)bbInfo );
511 distinct_instrs++;
512
njn6a3009b2005-03-20 00:20:06 +0000513 return bbInfo;
nethercote9313ac42004-07-06 21:54:20 +0000514}
njn6a3009b2005-03-20 00:20:06 +0000515
nethercote9313ac42004-07-06 21:54:20 +0000516
nethercote564b2b02004-08-07 15:54:53 +0000517static
njnf7d26092005-10-12 16:45:17 +0000518void init_instr_info( instr_info* n, Addr instr_addr, Int instr_len )
nethercote9313ac42004-07-06 21:54:20 +0000519{
njnf7d26092005-10-12 16:45:17 +0000520 n->instr_addr = instr_addr;
521 n->instr_len = instr_len;
522 n->parent = get_lineCC(instr_addr);
nethercote9313ac42004-07-06 21:54:20 +0000523}
524
sewardj5155dec2005-10-12 10:09:23 +0000525static void showEvent ( Event* ev )
nethercote9313ac42004-07-06 21:54:20 +0000526{
sewardj5155dec2005-10-12 10:09:23 +0000527 switch (ev->ekind) {
528 case Event_Ir:
529 VG_(printf)("Ir %d 0x%llx\n", ev->size, ev->iaddr);
530 break;
531 case Event_Dr:
532 VG_(printf)("Dr %d 0x%llx EA=", ev->size, ev->iaddr);
533 ppIRExpr(ev->dataEA);
534 VG_(printf)("\n");
535 break;
536 case Event_Dw:
537 VG_(printf)("Dw %d 0x%llx EA=", ev->size, ev->iaddr);
538 ppIRExpr(ev->dataEA);
539 VG_(printf)("\n");
540 break;
541 case Event_Dm:
542 VG_(printf)("Dm %d 0x%llx EA=", ev->size, ev->iaddr);
543 ppIRExpr(ev->dataEA);
544 VG_(printf)("\n");
545 break;
546 default:
547 tl_assert(0);
548 break;
549 }
njn6a3009b2005-03-20 00:20:06 +0000550}
551
sewardj5155dec2005-10-12 10:09:23 +0000552/* Reserve instr_info for the first mention of a new insn. */
553
554static instr_info* reserve_instr_info ( CgState* cgs )
njn6a3009b2005-03-20 00:20:06 +0000555{
sewardj5155dec2005-10-12 10:09:23 +0000556 instr_info* i_node;
557 tl_assert(cgs->bbInfo_i >= 0);
558 tl_assert(cgs->bbInfo_i < cgs->bbInfo->n_instrs);
559 i_node = &cgs->bbInfo->instrs[ cgs->bbInfo_i ];
560 cgs->bbInfo_i++;
561 return i_node;
562}
sewardj17a56bf2005-03-21 01:35:02 +0000563
sewardj17a56bf2005-03-21 01:35:02 +0000564
sewardj5155dec2005-10-12 10:09:23 +0000565/* Find the most recently allocated instr_info. */
sewardj17a56bf2005-03-21 01:35:02 +0000566
sewardj5155dec2005-10-12 10:09:23 +0000567static instr_info* find_most_recent_instr_info ( CgState* cgs )
568{
569 tl_assert(cgs->bbInfo_i >= 0);
570 tl_assert(cgs->bbInfo_i <= cgs->bbInfo->n_instrs);
571 if (cgs->bbInfo_i == 0)
572 return NULL;
573 else
574 return &cgs->bbInfo->instrs[ cgs->bbInfo_i - 1 ];
575}
njn016712a2005-04-04 02:52:16 +0000576
njn6a3009b2005-03-20 00:20:06 +0000577
sewardj5155dec2005-10-12 10:09:23 +0000578/* Generate code for all outstanding memory events, and mark the queue
579 empty. Code is generated into cgs->bbOut, and this activity
580 'consumes' slots in cgs->bbInfo. */
njn6a3009b2005-03-20 00:20:06 +0000581
sewardj5155dec2005-10-12 10:09:23 +0000582static void flushEvents ( CgState* cgs )
583{
584 Int i, regparms;
585 Char* helperName;
586 void* helperAddr;
587 IRExpr** argv;
588 IRExpr* i_node_expr;
589 IRExpr* i_node2_expr;
590 IRExpr* i_node3_expr;
591 IRDirty* di;
592 instr_info* i_node;
593 instr_info* i_node2;
594 instr_info* i_node3;
njn6a3009b2005-03-20 00:20:06 +0000595
sewardj5155dec2005-10-12 10:09:23 +0000596 i = 0;
597 while (i < cgs->events_used) {
njn6a3009b2005-03-20 00:20:06 +0000598
sewardj5155dec2005-10-12 10:09:23 +0000599 helperName = NULL;
600 helperAddr = NULL;
601 argv = NULL;
602 regparms = 0;
603
604 /* generate IR to notify event i and possibly the ones
605 immediately following it. */
606 tl_assert(i >= 0 && i < cgs->events_used);
607 if (DEBUG_CG) {
608 VG_(printf)(" flush ");
609 showEvent( &cgs->events[i] );
njn4f9c9342002-04-29 16:03:24 +0000610 }
sewardj5155dec2005-10-12 10:09:23 +0000611
612 /* For any event we find the relevant instr_info. The following
613 assumes that Event_Ir is the first event to refer to any
614 specific insn, and so a new entry in the cgs->bbInfo->instrs
615 is allocated. All other events (Dr,Dw,Dm) must refer to the
616 most recently encountered IMark and so we use the
617 most-recently allocated instrs[] entry, which must exist. */
618
619 if (cgs->events[i].ekind == Event_Ir) {
620 /* allocate an instr_info and fill in its addr/size. */
621 i_node = reserve_instr_info( cgs );
622 tl_assert(i_node);
sewardja3a29a52005-10-12 16:16:03 +0000623 init_instr_info( i_node,
sewardj5155dec2005-10-12 10:09:23 +0000624 (Addr)cgs->events[i].iaddr, /* i addr */
625 cgs->events[i].size /* i size */);
626 } else {
627 /* use the most-recently allocated i_node but don't mess with
628 its internals */
629 i_node = find_most_recent_instr_info( cgs );
630 /* it must actually exist */
631 tl_assert(i_node);
632 /* it must match the declared parent instruction of this
633 event. */
634 tl_assert(i_node->instr_addr == cgs->events[i].iaddr);
635 }
636
637 i_node_expr = mkIRExpr_HWord( (HWord)i_node );
638
639 /* Decide on helper fn to call and args to pass it, and advance
640 i appropriately. */
641 switch (cgs->events[i].ekind) {
642 case Event_Ir:
643 /* Merge with a following Dr/Dm if it is from this insn. */
644 if (i < cgs->events_used-1
645 && cgs->events[i+1].iaddr == cgs->events[i].iaddr
646 && (cgs->events[i+1].ekind == Event_Dr
647 || cgs->events[i+1].ekind == Event_Dm)) {
648 helperName = "log_1I_1Dr_cache_access";
649 helperAddr = &log_1I_1Dr_cache_access;
650 argv = mkIRExprVec_3( i_node_expr,
651 cgs->events[i+1].dataEA,
652 mkIRExpr_HWord( cgs->events[i+1].size ) );
653 regparms = 3;
654 i += 2;
655 }
656 /* Merge with a following Dw if it is from this insn. */
657 else
658 if (i < cgs->events_used-1
659 && cgs->events[i+1].iaddr == cgs->events[i].iaddr
660 && cgs->events[i+1].ekind == Event_Dw) {
661 helperName = "log_1I_1Dw_cache_access";
662 helperAddr = &log_1I_1Dw_cache_access;
663 argv = mkIRExprVec_3( i_node_expr,
664 cgs->events[i+1].dataEA,
665 mkIRExpr_HWord( cgs->events[i+1].size ) );
666 regparms = 3;
667 i += 2;
668 }
669 /* Merge with two following Irs if possible. */
670 else
671 if (i < cgs->events_used-2
672 && cgs->events[i+1].ekind == Event_Ir
673 && cgs->events[i+2].ekind == Event_Ir) {
674 helperName = "log_3I_0D_cache_access";
675 helperAddr = &log_3I_0D_cache_access;
676
677 i_node2 = reserve_instr_info( cgs );
678 tl_assert(i_node2);
sewardja3a29a52005-10-12 16:16:03 +0000679 init_instr_info( i_node2,
sewardj5155dec2005-10-12 10:09:23 +0000680 (Addr)cgs->events[i+1].iaddr, /* i addr */
681 cgs->events[i+1].size /* i size */);
682 i_node2_expr = mkIRExpr_HWord( (HWord)i_node2 );
683
684 i_node3 = reserve_instr_info( cgs );
685 tl_assert(i_node3);
sewardja3a29a52005-10-12 16:16:03 +0000686 init_instr_info( i_node3,
sewardj5155dec2005-10-12 10:09:23 +0000687 (Addr)cgs->events[i+2].iaddr, /* i addr */
688 cgs->events[i+2].size /* i size */);
689 i_node3_expr = mkIRExpr_HWord( (HWord)i_node3 );
690
691 argv = mkIRExprVec_3( i_node_expr, i_node2_expr, i_node3_expr );
692 regparms = 3;
693 i += 3;
694 }
695 /* Merge with a following Ir if possible. */
696 else
697 if (i < cgs->events_used-1
698 && cgs->events[i+1].ekind == Event_Ir) {
699 helperName = "log_2I_0D_cache_access";
700 helperAddr = &log_2I_0D_cache_access;
701 i_node2 = reserve_instr_info( cgs );
702 tl_assert(i_node2);
sewardja3a29a52005-10-12 16:16:03 +0000703 init_instr_info( i_node2,
sewardj5155dec2005-10-12 10:09:23 +0000704 (Addr)cgs->events[i+1].iaddr, /* i addr */
705 cgs->events[i+1].size /* i size */);
706 i_node2_expr = mkIRExpr_HWord( (HWord)i_node2 );
707 argv = mkIRExprVec_2( i_node_expr, i_node2_expr );
708 regparms = 2;
709 i += 2;
710 }
711 /* No merging possible; emit as-is. */
712 else {
713 helperName = "log_1I_0D_cache_access";
714 helperAddr = &log_1I_0D_cache_access;
715 argv = mkIRExprVec_1( i_node_expr );
716 regparms = 1;
717 i++;
718 }
719 break;
720 case Event_Dr:
721 case Event_Dm:
722 helperName = "log_0I_1Dr_cache_access";
723 helperAddr = &log_0I_1Dr_cache_access;
724 argv = mkIRExprVec_3( i_node_expr,
725 cgs->events[i].dataEA,
726 mkIRExpr_HWord( cgs->events[i].size ) );
727 regparms = 3;
728 i++;
729 break;
730 case Event_Dw:
731 helperName = "log_0I_1Dw_cache_access";
732 helperAddr = &log_0I_1Dw_cache_access;
733 argv = mkIRExprVec_3( i_node_expr,
734 cgs->events[i].dataEA,
735 mkIRExpr_HWord( cgs->events[i].size ) );
736 regparms = 3;
737 i++;
738 break;
739 default:
740 tl_assert(0);
741 }
742
743 /* Add the helper. */
744 tl_assert(helperName);
745 tl_assert(helperAddr);
746 tl_assert(argv);
747 di = unsafeIRDirty_0_N( regparms, helperName, helperAddr, argv);
748 addStmtToIRBB( cgs->bbOut, IRStmt_Dirty(di) );
njn4f9c9342002-04-29 16:03:24 +0000749 }
750
sewardj5155dec2005-10-12 10:09:23 +0000751 cgs->events_used = 0;
njn4f9c9342002-04-29 16:03:24 +0000752}
njn14d01ce2004-11-26 11:30:14 +0000753
sewardj5155dec2005-10-12 10:09:23 +0000754
755static void addEvent_Ir ( CgState* cgs, Int size, Addr64 iaddr )
756{
757 Event* evt;
758 tl_assert(size >= 0 && size <= MIN_LINE_SIZE);
759 if (cgs->events_used == N_EVENTS)
760 flushEvents(cgs);
761 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
762 /* If vex fails to decode an insn, the size will be zero, but that
763 can't really be true -- the cpu couldn't have determined the
764 insn was undecodable without looking at it. Hence: */
765 if (size == 0)
766 size = 1;
767 evt = &cgs->events[cgs->events_used];
768 evt->ekind = Event_Ir;
769 evt->size = size;
770 evt->iaddr = iaddr;
771 evt->dataEA = NULL; /*paranoia*/
772 cgs->events_used++;
773}
774
775static void addEvent_Dr ( CgState* cgs, Int size, Addr64 iaddr, IRAtom* ea )
776{
777 Event* evt;
778 tl_assert(isIRAtom(ea));
779 tl_assert(size >= 1 && size <= MIN_LINE_SIZE);
780 if (cgs->events_used == N_EVENTS)
781 flushEvents(cgs);
782 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
783 evt = &cgs->events[cgs->events_used];
784 evt->ekind = Event_Dr;
785 evt->size = size;
786 evt->iaddr = iaddr;
787 evt->dataEA = ea;
788 cgs->events_used++;
789}
790
791static void addEvent_Dw ( CgState* cgs, Int size, Addr64 iaddr, IRAtom* ea )
792{
793 tl_assert(isIRAtom(ea));
794 tl_assert(size >= 1 && size <= MIN_LINE_SIZE);
795
796 /* Is it possible to merge this write into an immediately preceding
797 read? */
798 if (cgs->events_used > 0
799 && cgs->events[cgs->events_used-1].ekind == Event_Dr
800 && cgs->events[cgs->events_used-1].size == size
801 && cgs->events[cgs->events_used-1].iaddr == iaddr
802 && eqIRAtom(cgs->events[cgs->events_used-1].dataEA, ea)) {
803 cgs->events[cgs->events_used-1].ekind = Event_Dm;
804 return;
805 }
806
807 /* No. Add as normal. */
808 if (cgs->events_used == N_EVENTS)
809 flushEvents(cgs);
810 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
811 cgs->events[cgs->events_used].ekind = Event_Dw;
812 cgs->events[cgs->events_used].size = size;
813 cgs->events[cgs->events_used].iaddr = iaddr;
814 cgs->events[cgs->events_used].dataEA = ea;
815 cgs->events_used++;
816}
817
818////////////////////////////////////////////////////////////
819
820
njn51d827b2005-05-09 01:02:08 +0000821static IRBB* cg_instrument ( IRBB* bbIn, VexGuestLayout* layout,
822 IRType gWordTy, IRType hWordTy )
njn14d01ce2004-11-26 11:30:14 +0000823{
sewardj5155dec2005-10-12 10:09:23 +0000824 Int i;
825 IRStmt* st;
826 Addr64 cia; /* address of current insn */
827 CgState cgs;
828 IRTypeEnv* tyenv = bbIn->tyenv;
829
njn6a3009b2005-03-20 00:20:06 +0000830
sewardjd54babf2005-03-21 00:55:49 +0000831 if (gWordTy != hWordTy) {
832 /* We don't currently support this case. */
833 VG_(tool_panic)("host/guest word size mismatch");
834 }
835
njn6a3009b2005-03-20 00:20:06 +0000836 /* Set up BB */
sewardj5155dec2005-10-12 10:09:23 +0000837 cgs.bbOut = emptyIRBB();
838 cgs.bbOut->tyenv = dopyIRTypeEnv(tyenv);
njn6a3009b2005-03-20 00:20:06 +0000839
sewardj5155dec2005-10-12 10:09:23 +0000840 // Get the first statement, and initial cia from it
njn6a3009b2005-03-20 00:20:06 +0000841 i = 0;
842 tl_assert(bbIn->stmts_used > 0);
843 st = bbIn->stmts[0];
844 tl_assert(Ist_IMark == st->tag);
sewardj5155dec2005-10-12 10:09:23 +0000845 cia = st->Ist.IMark.addr;
njn6a3009b2005-03-20 00:20:06 +0000846
sewardj5155dec2005-10-12 10:09:23 +0000847 // Set up running state and get block info
848 cgs.events_used = 0;
sewardja3a29a52005-10-12 16:16:03 +0000849 cgs.bbInfo = get_BB_info(bbIn, (Addr)cia);
sewardj5155dec2005-10-12 10:09:23 +0000850 cgs.bbInfo_i = 0;
njn6a3009b2005-03-20 00:20:06 +0000851
sewardj5155dec2005-10-12 10:09:23 +0000852 if (DEBUG_CG)
853 VG_(printf)("\n\n---------- cg_instrument ----------\n");
njn6a3009b2005-03-20 00:20:06 +0000854
sewardj5155dec2005-10-12 10:09:23 +0000855 // Traverse the block, adding events and flushing as necessary.
856 for (i = 0; i < bbIn->stmts_used; i++) {
njn6a3009b2005-03-20 00:20:06 +0000857
sewardj5155dec2005-10-12 10:09:23 +0000858 st = bbIn->stmts[i];
859 tl_assert(isFlatIRStmt(st));
njnb3507ea2005-08-02 23:07:02 +0000860
sewardj5155dec2005-10-12 10:09:23 +0000861 switch (st->tag) {
862 case Ist_NoOp:
863 case Ist_AbiHint:
864 case Ist_Put:
865 case Ist_PutI:
866 case Ist_MFence:
867 break;
njn20677cc2005-08-12 23:47:51 +0000868
sewardj5155dec2005-10-12 10:09:23 +0000869 case Ist_IMark:
870 cia = st->Ist.IMark.addr;
871 addEvent_Ir( &cgs, st->Ist.IMark.len, cia );
872 break;
873
874 case Ist_Tmp: {
875 IRExpr* data = st->Ist.Tmp.data;
876 if (data->tag == Iex_Load) {
877 IRExpr* aexpr = data->Iex.Load.addr;
878 tl_assert( isIRAtom(aexpr) );
879 // Note also, endianness info is ignored. I guess
880 // that's not interesting.
881 addEvent_Dr( &cgs, sizeofIRType(data->Iex.Load.ty),
882 cia, aexpr );
883 }
884 break;
njnb3507ea2005-08-02 23:07:02 +0000885 }
886
sewardj5155dec2005-10-12 10:09:23 +0000887 case Ist_Store: {
888 IRExpr* data = st->Ist.Store.data;
889 IRExpr* aexpr = st->Ist.Store.addr;
890 tl_assert( isIRAtom(aexpr) );
891 addEvent_Dw( &cgs,
892 sizeofIRType(typeOfIRExpr(tyenv, data)),
893 cia, aexpr );
894 break;
895 }
njnb3507ea2005-08-02 23:07:02 +0000896
sewardj5155dec2005-10-12 10:09:23 +0000897 case Ist_Dirty: {
898 Int dataSize;
899 IRDirty* d = st->Ist.Dirty.details;
900 if (d->mFx != Ifx_None) {
901 /* This dirty helper accesses memory. Collect the
902 details. */
903 tl_assert(d->mAddr != NULL);
904 tl_assert(d->mSize != 0);
905 dataSize = d->mSize;
906 // Large (eg. 28B, 108B, 512B on x86) data-sized
907 // instructions will be done inaccurately, but they're
908 // very rare and this avoids errors from hitting more
909 // than two cache lines in the simulation.
910 if (dataSize > MIN_LINE_SIZE)
911 dataSize = MIN_LINE_SIZE;
912 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
913 addEvent_Dr( &cgs, dataSize, cia, d->mAddr );
914 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
915 addEvent_Dw( &cgs, dataSize, cia, d->mAddr );
916 } else {
917 tl_assert(d->mAddr == NULL);
918 tl_assert(d->mSize == 0);
919 }
920 break;
921 }
njn6a3009b2005-03-20 00:20:06 +0000922
sewardj5155dec2005-10-12 10:09:23 +0000923 case Ist_Exit:
924 /* We may never reach the next statement, so need to flush
925 all outstanding transactions now. */
926 flushEvents( &cgs );
927 break;
928
929 default:
930 tl_assert(0);
931 break;
njnb3507ea2005-08-02 23:07:02 +0000932 }
njn6a3009b2005-03-20 00:20:06 +0000933
sewardj5155dec2005-10-12 10:09:23 +0000934 /* Copy the original statement */
935 addStmtToIRBB( cgs.bbOut, st );
njn6a3009b2005-03-20 00:20:06 +0000936
sewardj5155dec2005-10-12 10:09:23 +0000937 if (DEBUG_CG) {
938 ppIRStmt(st);
939 VG_(printf)("\n");
940 }
941 }
942
943 /* At the end of the bb. Flush outstandings. */
944 tl_assert(isIRAtom(bbIn->next));
945 flushEvents( &cgs );
946
947 /* copy where-next stuff. */
948 cgs.bbOut->next = dopyIRExpr(bbIn->next);
949 cgs.bbOut->jumpkind = bbIn->jumpkind;
950
951 /* done. stay sane ... */
952 tl_assert(cgs.bbInfo_i == cgs.bbInfo->n_instrs);
953
954 if (DEBUG_CG) {
955 VG_(printf)( "goto {");
956 ppIRJumpKind(bbIn->jumpkind);
957 VG_(printf)( "} ");
958 ppIRExpr( bbIn->next );
959 VG_(printf)( "}\n");
960 }
961
962 return cgs.bbOut;
njn14d01ce2004-11-26 11:30:14 +0000963}
njn4f9c9342002-04-29 16:03:24 +0000964
965/*------------------------------------------------------------*/
nethercoteb35a8b92004-09-11 16:45:27 +0000966/*--- Cache configuration ---*/
njn4f9c9342002-04-29 16:03:24 +0000967/*------------------------------------------------------------*/
968
sewardjb5f6f512005-03-10 23:59:00 +0000969#define UNDEFINED_CACHE { -1, -1, -1 }
njn25e49d8e72002-09-23 09:36:25 +0000970
971static cache_t clo_I1_cache = UNDEFINED_CACHE;
972static cache_t clo_D1_cache = UNDEFINED_CACHE;
973static cache_t clo_L2_cache = UNDEFINED_CACHE;
974
njn7cf0bd32002-06-08 13:36:03 +0000975/* Checks cache config is ok; makes it so if not. */
sewardj07133bf2002-06-13 10:25:56 +0000976static
njna1d1a642004-11-26 18:36:02 +0000977void check_cache(cache_t* cache, Char *name)
njn7cf0bd32002-06-08 13:36:03 +0000978{
979 /* First check they're all powers of two */
sewardj07133bf2002-06-13 10:25:56 +0000980 if (-1 == VG_(log2)(cache->size)) {
njn7cf0bd32002-06-08 13:36:03 +0000981 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000982 "error: %s size of %dB not a power of two; aborting.",
983 name, cache->size);
984 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000985 }
986
sewardj07133bf2002-06-13 10:25:56 +0000987 if (-1 == VG_(log2)(cache->assoc)) {
njn7cf0bd32002-06-08 13:36:03 +0000988 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000989 "error: %s associativity of %d not a power of two; aborting.",
990 name, cache->assoc);
991 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000992 }
993
sewardj07133bf2002-06-13 10:25:56 +0000994 if (-1 == VG_(log2)(cache->line_size)) {
njn7cf0bd32002-06-08 13:36:03 +0000995 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000996 "error: %s line size of %dB not a power of two; aborting.",
997 name, cache->line_size);
998 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000999 }
1000
njn6a3009b2005-03-20 00:20:06 +00001001 // Then check line size >= 16 -- any smaller and a single instruction could
1002 // straddle three cache lines, which breaks a simulation assertion and is
1003 // stupid anyway.
njn7cf0bd32002-06-08 13:36:03 +00001004 if (cache->line_size < MIN_LINE_SIZE) {
1005 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +00001006 "error: %s line size of %dB too small; aborting.",
1007 name, cache->line_size);
1008 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +00001009 }
1010
1011 /* Then check cache size > line size (causes seg faults if not). */
1012 if (cache->size <= cache->line_size) {
1013 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +00001014 "error: %s cache size of %dB <= line size of %dB; aborting.",
1015 name, cache->size, cache->line_size);
1016 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +00001017 }
1018
1019 /* Then check assoc <= (size / line size) (seg faults otherwise). */
1020 if (cache->assoc > (cache->size / cache->line_size)) {
1021 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +00001022 "warning: %s associativity > (size / line size); aborting.", name);
1023 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +00001024 }
1025}
1026
sewardj07133bf2002-06-13 10:25:56 +00001027static
nethercoteb35a8b92004-09-11 16:45:27 +00001028void configure_caches(cache_t* I1c, cache_t* D1c, cache_t* L2c)
njn7cf0bd32002-06-08 13:36:03 +00001029{
nethercote9313ac42004-07-06 21:54:20 +00001030#define DEFINED(L) (-1 != L.size || -1 != L.assoc || -1 != L.line_size)
1031
nethercoteb35a8b92004-09-11 16:45:27 +00001032 Int n_clos = 0;
nethercote9313ac42004-07-06 21:54:20 +00001033
nethercoteb35a8b92004-09-11 16:45:27 +00001034 // Count how many were defined on the command line.
1035 if (DEFINED(clo_I1_cache)) { n_clos++; }
1036 if (DEFINED(clo_D1_cache)) { n_clos++; }
1037 if (DEFINED(clo_L2_cache)) { n_clos++; }
njn7cf0bd32002-06-08 13:36:03 +00001038
njna1d1a642004-11-26 18:36:02 +00001039 // Set the cache config (using auto-detection, if supported by the
1040 // architecture)
njnaf839f52005-06-23 03:27:57 +00001041 VG_(configure_caches)( I1c, D1c, L2c, (3 == n_clos) );
sewardjb1a77a42002-07-13 13:31:20 +00001042
nethercote9313ac42004-07-06 21:54:20 +00001043 // Then replace with any defined on the command line.
nethercoteb35a8b92004-09-11 16:45:27 +00001044 if (DEFINED(clo_I1_cache)) { *I1c = clo_I1_cache; }
1045 if (DEFINED(clo_D1_cache)) { *D1c = clo_D1_cache; }
1046 if (DEFINED(clo_L2_cache)) { *L2c = clo_L2_cache; }
njn7cf0bd32002-06-08 13:36:03 +00001047
nethercote9313ac42004-07-06 21:54:20 +00001048 // Then check values and fix if not acceptable.
njna1d1a642004-11-26 18:36:02 +00001049 check_cache(I1c, "I1");
1050 check_cache(D1c, "D1");
1051 check_cache(L2c, "L2");
njn7cf0bd32002-06-08 13:36:03 +00001052
1053 if (VG_(clo_verbosity) > 1) {
1054 VG_(message)(Vg_UserMsg, "Cache configuration used:");
1055 VG_(message)(Vg_UserMsg, " I1: %dB, %d-way, %dB lines",
1056 I1c->size, I1c->assoc, I1c->line_size);
1057 VG_(message)(Vg_UserMsg, " D1: %dB, %d-way, %dB lines",
1058 D1c->size, D1c->assoc, D1c->line_size);
1059 VG_(message)(Vg_UserMsg, " L2: %dB, %d-way, %dB lines",
1060 L2c->size, L2c->assoc, L2c->line_size);
1061 }
nethercote9313ac42004-07-06 21:54:20 +00001062#undef CMD_LINE_DEFINED
njn7cf0bd32002-06-08 13:36:03 +00001063}
1064
njn4f9c9342002-04-29 16:03:24 +00001065/*------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +00001066/*--- cg_fini() and related function ---*/
njn4f9c9342002-04-29 16:03:24 +00001067/*------------------------------------------------------------*/
1068
nethercote9313ac42004-07-06 21:54:20 +00001069// Total reads/writes/misses. Calculated during CC traversal at the end.
1070// All auto-zeroed.
1071static CC Ir_total;
1072static CC Dr_total;
1073static CC Dw_total;
1074
1075static Char* cachegrind_out_file;
1076
nethercote9313ac42004-07-06 21:54:20 +00001077static void fprint_lineCC(Int fd, lineCC* n)
njn4f9c9342002-04-29 16:03:24 +00001078{
nethercote9313ac42004-07-06 21:54:20 +00001079 Char buf[512];
1080 VG_(sprintf)(buf, "%u %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
1081 n->line,
1082 n->Ir.a, n->Ir.m1, n->Ir.m2,
1083 n->Dr.a, n->Dr.m1, n->Dr.m2,
1084 n->Dw.a, n->Dw.m1, n->Dw.m2);
1085 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1086
1087 Ir_total.a += n->Ir.a; Ir_total.m1 += n->Ir.m1; Ir_total.m2 += n->Ir.m2;
1088 Dr_total.a += n->Dr.a; Dr_total.m1 += n->Dr.m1; Dr_total.m2 += n->Dr.m2;
1089 Dw_total.a += n->Dw.a; Dw_total.m1 += n->Dw.m1; Dw_total.m2 += n->Dw.m2;
1090}
1091
1092static void fprint_CC_table_and_calc_totals(void)
1093{
1094 Int fd;
sewardj92645592005-07-23 09:18:34 +00001095 SysRes sres;
nethercote9313ac42004-07-06 21:54:20 +00001096 Char buf[512];
1097 fileCC *curr_fileCC;
1098 fnCC *curr_fnCC;
1099 lineCC *curr_lineCC;
1100 Int i, j, k;
njn4f9c9342002-04-29 16:03:24 +00001101
njn25e49d8e72002-09-23 09:36:25 +00001102 VGP_PUSHCC(VgpCacheResults);
njn13f02932003-04-30 20:23:58 +00001103
sewardj92645592005-07-23 09:18:34 +00001104 sres = VG_(open)(cachegrind_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
1105 VKI_S_IRUSR|VKI_S_IWUSR);
1106 if (sres.isError) {
nethercote9313ac42004-07-06 21:54:20 +00001107 // If the file can't be opened for whatever reason (conflict
1108 // between multiple cachegrinded processes?), give up now.
njnee0e6a32005-04-24 00:21:01 +00001109 VG_(message)(Vg_UserMsg,
njn02bc4b82005-05-15 17:28:26 +00001110 "error: can't open cache simulation output file '%s'",
njnee0e6a32005-04-24 00:21:01 +00001111 cachegrind_out_file );
1112 VG_(message)(Vg_UserMsg,
1113 " ... so simulation results will be missing.");
sewardj0744b6c2002-12-11 00:45:42 +00001114 return;
sewardj92645592005-07-23 09:18:34 +00001115 } else {
1116 fd = sres.val;
sewardj0744b6c2002-12-11 00:45:42 +00001117 }
njn4f9c9342002-04-29 16:03:24 +00001118
nethercote9313ac42004-07-06 21:54:20 +00001119 // "desc:" lines (giving I1/D1/L2 cache configuration). The spaces after
1120 // the 2nd colon makes cg_annotate's output look nicer.
1121 VG_(sprintf)(buf, "desc: I1 cache: %s\n"
1122 "desc: D1 cache: %s\n"
1123 "desc: L2 cache: %s\n",
1124 I1.desc_line, D1.desc_line, L2.desc_line);
njn7cf0bd32002-06-08 13:36:03 +00001125 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njn4f9c9342002-04-29 16:03:24 +00001126
nethercote9313ac42004-07-06 21:54:20 +00001127 // "cmd:" line
njn4f9c9342002-04-29 16:03:24 +00001128 VG_(strcpy)(buf, "cmd:");
1129 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
sewardj45f4e7c2005-09-27 19:20:21 +00001130 if (VG_(args_the_exename)) {
1131 VG_(write)(fd, " ", 1);
1132 VG_(write)(fd, VG_(args_the_exename),
1133 VG_(strlen)( VG_(args_the_exename) ));
1134 }
1135 for (i = 0; i < VG_(args_for_client).used; i++) {
1136 if (VG_(args_for_client).strs[i]) {
1137 VG_(write)(fd, " ", 1);
1138 VG_(write)(fd, VG_(args_for_client).strs[i],
1139 VG_(strlen)(VG_(args_for_client).strs[i]));
1140 }
njn4f9c9342002-04-29 16:03:24 +00001141 }
nethercote9313ac42004-07-06 21:54:20 +00001142 // "events:" line
njn4f9c9342002-04-29 16:03:24 +00001143 VG_(sprintf)(buf, "\nevents: Ir I1mr I2mr Dr D1mr D2mr Dw D1mw D2mw\n");
1144 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1145
nethercote9313ac42004-07-06 21:54:20 +00001146 // Six loops here: three for the hash table arrays, and three for the
1147 // chains hanging off the hash table arrays.
njn4f9c9342002-04-29 16:03:24 +00001148 for (i = 0; i < N_FILE_ENTRIES; i++) {
nethercote9313ac42004-07-06 21:54:20 +00001149 curr_fileCC = CC_table[i];
1150 while (curr_fileCC != NULL) {
1151 VG_(sprintf)(buf, "fl=%s\n", curr_fileCC->file);
njn4f9c9342002-04-29 16:03:24 +00001152 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1153
1154 for (j = 0; j < N_FN_ENTRIES; j++) {
nethercote9313ac42004-07-06 21:54:20 +00001155 curr_fnCC = curr_fileCC->fns[j];
1156 while (curr_fnCC != NULL) {
1157 VG_(sprintf)(buf, "fn=%s\n", curr_fnCC->fn);
njn4f9c9342002-04-29 16:03:24 +00001158 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1159
nethercote9313ac42004-07-06 21:54:20 +00001160 for (k = 0; k < N_LINE_ENTRIES; k++) {
1161 curr_lineCC = curr_fnCC->lines[k];
1162 while (curr_lineCC != NULL) {
1163 fprint_lineCC(fd, curr_lineCC);
1164 curr_lineCC = curr_lineCC->next;
njn4f9c9342002-04-29 16:03:24 +00001165 }
1166 }
nethercote9313ac42004-07-06 21:54:20 +00001167 curr_fnCC = curr_fnCC->next;
njn4f9c9342002-04-29 16:03:24 +00001168 }
1169 }
nethercote9313ac42004-07-06 21:54:20 +00001170 curr_fileCC = curr_fileCC->next;
njn4f9c9342002-04-29 16:03:24 +00001171 }
1172 }
1173
nethercote9313ac42004-07-06 21:54:20 +00001174 // Summary stats must come after rest of table, since we calculate them
1175 // during traversal. */
njn4f9c9342002-04-29 16:03:24 +00001176 VG_(sprintf)(buf, "summary: "
nethercote9313ac42004-07-06 21:54:20 +00001177 "%llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
njn4f9c9342002-04-29 16:03:24 +00001178 Ir_total.a, Ir_total.m1, Ir_total.m2,
1179 Dr_total.a, Dr_total.m1, Dr_total.m2,
1180 Dw_total.a, Dw_total.m1, Dw_total.m2);
1181 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1182 VG_(close)(fd);
1183}
1184
njn607adfc2003-09-30 14:15:44 +00001185static UInt ULong_width(ULong n)
njn4f9c9342002-04-29 16:03:24 +00001186{
njn607adfc2003-09-30 14:15:44 +00001187 UInt w = 0;
1188 while (n > 0) {
1189 n = n / 10;
1190 w++;
njn4f9c9342002-04-29 16:03:24 +00001191 }
njn607adfc2003-09-30 14:15:44 +00001192 return w + (w-1)/3; // add space for commas
njn4f9c9342002-04-29 16:03:24 +00001193}
1194
njn51d827b2005-05-09 01:02:08 +00001195static void cg_fini(Int exitcode)
njn4f9c9342002-04-29 16:03:24 +00001196{
njn0103de52005-10-10 16:49:01 +00001197 static Char buf1[128], buf2[128], buf3[128], fmt [128];
njn607adfc2003-09-30 14:15:44 +00001198
njn4f9c9342002-04-29 16:03:24 +00001199 CC D_total;
njn1d021fa2002-05-02 13:56:34 +00001200 ULong L2_total_m, L2_total_mr, L2_total_mw,
1201 L2_total, L2_total_r, L2_total_w;
njn4f9c9342002-04-29 16:03:24 +00001202 Int l1, l2, l3;
1203 Int p;
1204
nethercote9313ac42004-07-06 21:54:20 +00001205 fprint_CC_table_and_calc_totals();
njn4f9c9342002-04-29 16:03:24 +00001206
njn7cf0bd32002-06-08 13:36:03 +00001207 if (VG_(clo_verbosity) == 0)
1208 return;
1209
njn4f9c9342002-04-29 16:03:24 +00001210 /* I cache results. Use the I_refs value to determine the first column
1211 * width. */
njn607adfc2003-09-30 14:15:44 +00001212 l1 = ULong_width(Ir_total.a);
1213 l2 = ULong_width(Dr_total.a);
1214 l3 = ULong_width(Dw_total.a);
njn4f9c9342002-04-29 16:03:24 +00001215
njn607adfc2003-09-30 14:15:44 +00001216 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001217 VG_(sprintf)(fmt, "%%s %%,%dllu", l1);
njn607adfc2003-09-30 14:15:44 +00001218
1219 VG_(message)(Vg_UserMsg, fmt, "I refs: ", Ir_total.a);
1220 VG_(message)(Vg_UserMsg, fmt, "I1 misses: ", Ir_total.m1);
1221 VG_(message)(Vg_UserMsg, fmt, "L2i misses: ", Ir_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001222
1223 p = 100;
1224
njn25e49d8e72002-09-23 09:36:25 +00001225 if (0 == Ir_total.a) Ir_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001226 VG_(percentify)(Ir_total.m1, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001227 VG_(message)(Vg_UserMsg, "I1 miss rate: %s", buf1);
1228
njn856c54e2005-06-26 18:43:40 +00001229 VG_(percentify)(Ir_total.m2, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001230 VG_(message)(Vg_UserMsg, "L2i miss rate: %s", buf1);
1231 VG_(message)(Vg_UserMsg, "");
1232
1233 /* D cache results. Use the D_refs.rd and D_refs.wr values to determine the
1234 * width of columns 2 & 3. */
1235 D_total.a = Dr_total.a + Dw_total.a;
1236 D_total.m1 = Dr_total.m1 + Dw_total.m1;
1237 D_total.m2 = Dr_total.m2 + Dw_total.m2;
1238
njn607adfc2003-09-30 14:15:44 +00001239 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001240 VG_(sprintf)(fmt, "%%s %%,%dllu (%%,%dllu rd + %%,%dllu wr)", l1, l2, l3);
njn4f9c9342002-04-29 16:03:24 +00001241
njn607adfc2003-09-30 14:15:44 +00001242 VG_(message)(Vg_UserMsg, fmt, "D refs: ",
1243 D_total.a, Dr_total.a, Dw_total.a);
1244 VG_(message)(Vg_UserMsg, fmt, "D1 misses: ",
1245 D_total.m1, Dr_total.m1, Dw_total.m1);
1246 VG_(message)(Vg_UserMsg, fmt, "L2d misses: ",
1247 D_total.m2, Dr_total.m2, Dw_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001248
1249 p = 10;
1250
njn25e49d8e72002-09-23 09:36:25 +00001251 if (0 == D_total.a) D_total.a = 1;
1252 if (0 == Dr_total.a) Dr_total.a = 1;
1253 if (0 == Dw_total.a) Dw_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001254 VG_(percentify)( D_total.m1, D_total.a, 1, l1+1, buf1);
1255 VG_(percentify)(Dr_total.m1, Dr_total.a, 1, l2+1, buf2);
1256 VG_(percentify)(Dw_total.m1, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001257 VG_(message)(Vg_UserMsg, "D1 miss rate: %s (%s + %s )", buf1, buf2,buf3);
1258
njn856c54e2005-06-26 18:43:40 +00001259 VG_(percentify)( D_total.m2, D_total.a, 1, l1+1, buf1);
1260 VG_(percentify)(Dr_total.m2, Dr_total.a, 1, l2+1, buf2);
1261 VG_(percentify)(Dw_total.m2, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001262 VG_(message)(Vg_UserMsg, "L2d miss rate: %s (%s + %s )", buf1, buf2,buf3);
1263 VG_(message)(Vg_UserMsg, "");
1264
1265 /* L2 overall results */
njn1d021fa2002-05-02 13:56:34 +00001266
1267 L2_total = Dr_total.m1 + Dw_total.m1 + Ir_total.m1;
1268 L2_total_r = Dr_total.m1 + Ir_total.m1;
1269 L2_total_w = Dw_total.m1;
njn607adfc2003-09-30 14:15:44 +00001270 VG_(message)(Vg_UserMsg, fmt, "L2 refs: ",
1271 L2_total, L2_total_r, L2_total_w);
njn1d021fa2002-05-02 13:56:34 +00001272
njn4f9c9342002-04-29 16:03:24 +00001273 L2_total_m = Dr_total.m2 + Dw_total.m2 + Ir_total.m2;
1274 L2_total_mr = Dr_total.m2 + Ir_total.m2;
1275 L2_total_mw = Dw_total.m2;
njn607adfc2003-09-30 14:15:44 +00001276 VG_(message)(Vg_UserMsg, fmt, "L2 misses: ",
1277 L2_total_m, L2_total_mr, L2_total_mw);
njn4f9c9342002-04-29 16:03:24 +00001278
njn856c54e2005-06-26 18:43:40 +00001279 VG_(percentify)(L2_total_m, (Ir_total.a + D_total.a), 1, l1+1, buf1);
1280 VG_(percentify)(L2_total_mr, (Ir_total.a + Dr_total.a), 1, l2+1, buf2);
1281 VG_(percentify)(L2_total_mw, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001282 VG_(message)(Vg_UserMsg, "L2 miss rate: %s (%s + %s )", buf1, buf2,buf3);
1283
1284
nethercote9313ac42004-07-06 21:54:20 +00001285 // Various stats
njn4f9c9342002-04-29 16:03:24 +00001286 if (VG_(clo_verbosity) > 1) {
njn0103de52005-10-10 16:49:01 +00001287 Int BB_lookups = full_debug_BBs + fn_debug_BBs +
njn4f9c9342002-04-29 16:03:24 +00001288 file_line_debug_BBs + no_debug_BBs;
1289
1290 VG_(message)(Vg_DebugMsg, "");
1291 VG_(message)(Vg_DebugMsg, "Distinct files: %d", distinct_files);
1292 VG_(message)(Vg_DebugMsg, "Distinct fns: %d", distinct_fns);
nethercote9313ac42004-07-06 21:54:20 +00001293 VG_(message)(Vg_DebugMsg, "Distinct lines: %d", distinct_lines);
1294 VG_(message)(Vg_DebugMsg, "Distinct instrs: %d", distinct_instrs);
njn4f9c9342002-04-29 16:03:24 +00001295 VG_(message)(Vg_DebugMsg, "BB lookups: %d", BB_lookups);
1296 VG_(message)(Vg_DebugMsg, "With full debug info:%3d%% (%d)",
1297 full_debug_BBs * 100 / BB_lookups,
1298 full_debug_BBs);
1299 VG_(message)(Vg_DebugMsg, "With file/line debug info:%3d%% (%d)",
1300 file_line_debug_BBs * 100 / BB_lookups,
1301 file_line_debug_BBs);
1302 VG_(message)(Vg_DebugMsg, "With fn name debug info:%3d%% (%d)",
nethercote9313ac42004-07-06 21:54:20 +00001303 fn_debug_BBs * 100 / BB_lookups,
1304 fn_debug_BBs);
njn4f9c9342002-04-29 16:03:24 +00001305 VG_(message)(Vg_DebugMsg, "With no debug info:%3d%% (%d)",
1306 no_debug_BBs * 100 / BB_lookups,
1307 no_debug_BBs);
1308 VG_(message)(Vg_DebugMsg, "BBs Retranslated: %d", BB_retranslations);
njn4f9c9342002-04-29 16:03:24 +00001309 }
njn25e49d8e72002-09-23 09:36:25 +00001310 VGP_POPCC(VgpCacheResults);
njn4f9c9342002-04-29 16:03:24 +00001311}
1312
nethercote9313ac42004-07-06 21:54:20 +00001313/*--------------------------------------------------------------------*/
1314/*--- Discarding BB info ---*/
1315/*--------------------------------------------------------------------*/
sewardj18d75132002-05-16 11:06:21 +00001316
sewardja3a29a52005-10-12 16:16:03 +00001317// Called when a translation is removed from the translation cache for
1318// any reason at all: to free up space, because the guest code was
1319// unmapped or modified, or for any arbitrary reason.
sewardj5155dec2005-10-12 10:09:23 +00001320static void cg_discard_basic_block_info ( VexGuestExtents vge )
sewardj18d75132002-05-16 11:06:21 +00001321{
sewardj5155dec2005-10-12 10:09:23 +00001322 VgHashNode* bbInfo;
njn4294fd42002-06-05 14:41:10 +00001323
sewardj5155dec2005-10-12 10:09:23 +00001324 tl_assert(vge.n_used > 0);
1325
1326 if (DEBUG_CG)
1327 VG_(printf)( "discard_basic_block_info: %p, %llu\n",
1328 (void*)(Addr)vge.base[0], (ULong)vge.len[0]);
njn4294fd42002-06-05 14:41:10 +00001329
nethercote9313ac42004-07-06 21:54:20 +00001330 // Get BB info, remove from table, free BB info. Simple!
sewardj5155dec2005-10-12 10:09:23 +00001331 bbInfo = VG_(HT_remove)(instr_info_table, (UWord)vge.base[0]);
njn6a3009b2005-03-20 00:20:06 +00001332 tl_assert(NULL != bbInfo);
sewardj5155dec2005-10-12 10:09:23 +00001333
njn6a3009b2005-03-20 00:20:06 +00001334 VG_(free)(bbInfo);
sewardj18d75132002-05-16 11:06:21 +00001335}
1336
1337/*--------------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001338/*--- Command line processing ---*/
1339/*--------------------------------------------------------------------*/
1340
njn0103de52005-10-10 16:49:01 +00001341static void parse_cache_opt ( cache_t* cache, Char* opt )
njn25e49d8e72002-09-23 09:36:25 +00001342{
njn0103de52005-10-10 16:49:01 +00001343 Int i = 0, i2, i3;
njn25e49d8e72002-09-23 09:36:25 +00001344
nethercote9313ac42004-07-06 21:54:20 +00001345 // Option argument looks like "65536,2,64".
1346 // Find commas, replace with NULs to make three independent
1347 // strings, then extract numbers, put NULs back. Yuck.
njn25e49d8e72002-09-23 09:36:25 +00001348 while (VG_(isdigit)(opt[i])) i++;
1349 if (',' == opt[i]) {
1350 opt[i++] = '\0';
1351 i2 = i;
1352 } else goto bad;
1353 while (VG_(isdigit)(opt[i])) i++;
1354 if (',' == opt[i]) {
1355 opt[i++] = '\0';
1356 i3 = i;
1357 } else goto bad;
1358 while (VG_(isdigit)(opt[i])) i++;
1359 if ('\0' != opt[i]) goto bad;
1360
nethercote9313ac42004-07-06 21:54:20 +00001361 cache->size = (Int)VG_(atoll)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001362 cache->assoc = (Int)VG_(atoll)(opt + i2);
1363 cache->line_size = (Int)VG_(atoll)(opt + i3);
1364
nethercote9313ac42004-07-06 21:54:20 +00001365 opt[i2-1] = ',';
1366 opt[i3-1] = ',';
njn25e49d8e72002-09-23 09:36:25 +00001367 return;
1368
1369 bad:
nethercote9313ac42004-07-06 21:54:20 +00001370 VG_(bad_option)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001371}
1372
njn51d827b2005-05-09 01:02:08 +00001373static Bool cg_process_cmd_line_option(Char* arg)
njn25e49d8e72002-09-23 09:36:25 +00001374{
nethercote9313ac42004-07-06 21:54:20 +00001375 // 5 is length of "--I1="
njn39c86652003-05-21 10:13:39 +00001376 if (VG_CLO_STREQN(5, arg, "--I1="))
nethercote9313ac42004-07-06 21:54:20 +00001377 parse_cache_opt(&clo_I1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001378 else if (VG_CLO_STREQN(5, arg, "--D1="))
nethercote9313ac42004-07-06 21:54:20 +00001379 parse_cache_opt(&clo_D1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001380 else if (VG_CLO_STREQN(5, arg, "--L2="))
nethercote9313ac42004-07-06 21:54:20 +00001381 parse_cache_opt(&clo_L2_cache, &arg[5]);
njn25e49d8e72002-09-23 09:36:25 +00001382 else
1383 return False;
1384
1385 return True;
1386}
1387
njn51d827b2005-05-09 01:02:08 +00001388static void cg_print_usage(void)
njn25e49d8e72002-09-23 09:36:25 +00001389{
njn3e884182003-04-15 13:03:23 +00001390 VG_(printf)(
njn25e49d8e72002-09-23 09:36:25 +00001391" --I1=<size>,<assoc>,<line_size> set I1 cache manually\n"
1392" --D1=<size>,<assoc>,<line_size> set D1 cache manually\n"
njn3e884182003-04-15 13:03:23 +00001393" --L2=<size>,<assoc>,<line_size> set L2 cache manually\n"
1394 );
1395}
1396
njn51d827b2005-05-09 01:02:08 +00001397static void cg_print_debug_usage(void)
njn3e884182003-04-15 13:03:23 +00001398{
1399 VG_(printf)(
1400" (none)\n"
1401 );
njn25e49d8e72002-09-23 09:36:25 +00001402}
1403
1404/*--------------------------------------------------------------------*/
1405/*--- Setup ---*/
1406/*--------------------------------------------------------------------*/
1407
njn51d827b2005-05-09 01:02:08 +00001408static void cg_post_clo_init(void)
njn25e49d8e72002-09-23 09:36:25 +00001409{
1410 cache_t I1c, D1c, L2c;
njn25e49d8e72002-09-23 09:36:25 +00001411
nethercoteb35a8b92004-09-11 16:45:27 +00001412 configure_caches(&I1c, &D1c, &L2c);
njn25e49d8e72002-09-23 09:36:25 +00001413
1414 cachesim_I1_initcache(I1c);
1415 cachesim_D1_initcache(D1c);
1416 cachesim_L2_initcache(L2c);
1417
njn31066fd2005-03-26 00:42:02 +00001418 VG_(register_profile_event)(VgpGetLineCC, "get-lineCC");
1419 VG_(register_profile_event)(VgpCacheSimulate, "cache-simulate");
1420 VG_(register_profile_event)(VgpCacheResults, "cache-results");
njn25e49d8e72002-09-23 09:36:25 +00001421}
1422
njn57ca7ab2005-06-21 23:44:58 +00001423static Char base_dir[VKI_PATH_MAX];
1424
njn51d827b2005-05-09 01:02:08 +00001425static void cg_pre_clo_init(void)
1426{
njn51d827b2005-05-09 01:02:08 +00001427 VG_(details_name) ("Cachegrind");
1428 VG_(details_version) (NULL);
1429 VG_(details_description) ("an I1/D1/L2 cache profiler");
1430 VG_(details_copyright_author)(
1431 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote et al.");
1432 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj5155dec2005-10-12 10:09:23 +00001433 VG_(details_avg_translation_sizeB) ( 245 );
njn51d827b2005-05-09 01:02:08 +00001434
1435 VG_(basic_tool_funcs) (cg_post_clo_init,
1436 cg_instrument,
1437 cg_fini);
1438
1439 VG_(needs_basic_block_discards)(cg_discard_basic_block_info);
1440 VG_(needs_command_line_options)(cg_process_cmd_line_option,
1441 cg_print_usage,
1442 cg_print_debug_usage);
1443
1444 /* Get working directory */
njn57ca7ab2005-06-21 23:44:58 +00001445 tl_assert( VG_(getcwd)(base_dir, VKI_PATH_MAX) );
njn51d827b2005-05-09 01:02:08 +00001446
1447 /* Block is big enough for dir name + cachegrind.out.<pid> */
1448 cachegrind_out_file = VG_(malloc)((VG_(strlen)(base_dir) + 32)*sizeof(Char));
1449 VG_(sprintf)(cachegrind_out_file, "%s/cachegrind.out.%d",
1450 base_dir, VG_(getpid)());
njn51d827b2005-05-09 01:02:08 +00001451
njnf69f9452005-07-03 17:53:11 +00001452 instr_info_table = VG_(HT_construct)( 4999 ); // prime, biggish
njn51d827b2005-05-09 01:02:08 +00001453}
1454
sewardj45f4e7c2005-09-27 19:20:21 +00001455VG_DETERMINE_INTERFACE_VERSION(cg_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00001456
njn25e49d8e72002-09-23 09:36:25 +00001457/*--------------------------------------------------------------------*/
njnf69f9452005-07-03 17:53:11 +00001458/*--- end ---*/
sewardj18d75132002-05-16 11:06:21 +00001459/*--------------------------------------------------------------------*/