blob: 13f7cc3ba55338a05a5643479de4296644e3bfa1 [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
sewardja3a29a52005-10-12 16:16:03 +0000498 // Check that the BB has never been translated before. If this
499 // assertion fails, there has been some screwup in translation
500 // discard/invalidation management.
njn4bd67b52005-08-11 00:47:10 +0000501 bbInfo = (BB_info*)VG_(HT_lookup)(instr_info_table, origAddr);
sewardja3a29a52005-10-12 16:16:03 +0000502 tl_assert(NULL == bbInfo);
503
504 // BB has never translated before (at this address, at least; could
505 // have been unloaded and then reloaded elsewhere in memory).
506 bbInfo = VG_(calloc)(1, sizeof(BB_info) + n_instrs*sizeof(instr_info));
507 bbInfo->BB_addr = origAddr;
508 bbInfo->n_instrs = n_instrs;
509 VG_(HT_add_node)( instr_info_table, (VgHashNode*)bbInfo );
510 distinct_instrs++;
511
njn6a3009b2005-03-20 00:20:06 +0000512 return bbInfo;
nethercote9313ac42004-07-06 21:54:20 +0000513}
njn6a3009b2005-03-20 00:20:06 +0000514
nethercote9313ac42004-07-06 21:54:20 +0000515
nethercote564b2b02004-08-07 15:54:53 +0000516static
sewardja3a29a52005-10-12 16:16:03 +0000517void init_instr_info( /*OUT*/instr_info* n,
sewardj5155dec2005-10-12 10:09:23 +0000518 Addr instr_addr, Int instr_len )
nethercote9313ac42004-07-06 21:54:20 +0000519{
sewardja3a29a52005-10-12 16:16:03 +0000520 lineCC* parent = get_lineCC(instr_addr);
521 n->instr_addr = instr_addr;
522 n->instr_len = instr_len;
523 n->parent = parent;
nethercote9313ac42004-07-06 21:54:20 +0000524}
525
sewardj5155dec2005-10-12 10:09:23 +0000526static void showEvent ( Event* ev )
nethercote9313ac42004-07-06 21:54:20 +0000527{
sewardj5155dec2005-10-12 10:09:23 +0000528 switch (ev->ekind) {
529 case Event_Ir:
530 VG_(printf)("Ir %d 0x%llx\n", ev->size, ev->iaddr);
531 break;
532 case Event_Dr:
533 VG_(printf)("Dr %d 0x%llx EA=", ev->size, ev->iaddr);
534 ppIRExpr(ev->dataEA);
535 VG_(printf)("\n");
536 break;
537 case Event_Dw:
538 VG_(printf)("Dw %d 0x%llx EA=", ev->size, ev->iaddr);
539 ppIRExpr(ev->dataEA);
540 VG_(printf)("\n");
541 break;
542 case Event_Dm:
543 VG_(printf)("Dm %d 0x%llx EA=", ev->size, ev->iaddr);
544 ppIRExpr(ev->dataEA);
545 VG_(printf)("\n");
546 break;
547 default:
548 tl_assert(0);
549 break;
550 }
njn6a3009b2005-03-20 00:20:06 +0000551}
552
sewardj5155dec2005-10-12 10:09:23 +0000553/* Reserve instr_info for the first mention of a new insn. */
554
555static instr_info* reserve_instr_info ( CgState* cgs )
njn6a3009b2005-03-20 00:20:06 +0000556{
sewardj5155dec2005-10-12 10:09:23 +0000557 instr_info* i_node;
558 tl_assert(cgs->bbInfo_i >= 0);
559 tl_assert(cgs->bbInfo_i < cgs->bbInfo->n_instrs);
560 i_node = &cgs->bbInfo->instrs[ cgs->bbInfo_i ];
561 cgs->bbInfo_i++;
562 return i_node;
563}
sewardj17a56bf2005-03-21 01:35:02 +0000564
sewardj17a56bf2005-03-21 01:35:02 +0000565
sewardj5155dec2005-10-12 10:09:23 +0000566/* Find the most recently allocated instr_info. */
sewardj17a56bf2005-03-21 01:35:02 +0000567
sewardj5155dec2005-10-12 10:09:23 +0000568static instr_info* find_most_recent_instr_info ( CgState* cgs )
569{
570 tl_assert(cgs->bbInfo_i >= 0);
571 tl_assert(cgs->bbInfo_i <= cgs->bbInfo->n_instrs);
572 if (cgs->bbInfo_i == 0)
573 return NULL;
574 else
575 return &cgs->bbInfo->instrs[ cgs->bbInfo_i - 1 ];
576}
njn016712a2005-04-04 02:52:16 +0000577
njn6a3009b2005-03-20 00:20:06 +0000578
sewardj5155dec2005-10-12 10:09:23 +0000579/* Generate code for all outstanding memory events, and mark the queue
580 empty. Code is generated into cgs->bbOut, and this activity
581 'consumes' slots in cgs->bbInfo. */
njn6a3009b2005-03-20 00:20:06 +0000582
sewardj5155dec2005-10-12 10:09:23 +0000583static void flushEvents ( CgState* cgs )
584{
585 Int i, regparms;
586 Char* helperName;
587 void* helperAddr;
588 IRExpr** argv;
589 IRExpr* i_node_expr;
590 IRExpr* i_node2_expr;
591 IRExpr* i_node3_expr;
592 IRDirty* di;
593 instr_info* i_node;
594 instr_info* i_node2;
595 instr_info* i_node3;
njn6a3009b2005-03-20 00:20:06 +0000596
sewardj5155dec2005-10-12 10:09:23 +0000597 i = 0;
598 while (i < cgs->events_used) {
njn6a3009b2005-03-20 00:20:06 +0000599
sewardj5155dec2005-10-12 10:09:23 +0000600 helperName = NULL;
601 helperAddr = NULL;
602 argv = NULL;
603 regparms = 0;
604
605 /* generate IR to notify event i and possibly the ones
606 immediately following it. */
607 tl_assert(i >= 0 && i < cgs->events_used);
608 if (DEBUG_CG) {
609 VG_(printf)(" flush ");
610 showEvent( &cgs->events[i] );
njn4f9c9342002-04-29 16:03:24 +0000611 }
sewardj5155dec2005-10-12 10:09:23 +0000612
613 /* For any event we find the relevant instr_info. The following
614 assumes that Event_Ir is the first event to refer to any
615 specific insn, and so a new entry in the cgs->bbInfo->instrs
616 is allocated. All other events (Dr,Dw,Dm) must refer to the
617 most recently encountered IMark and so we use the
618 most-recently allocated instrs[] entry, which must exist. */
619
620 if (cgs->events[i].ekind == Event_Ir) {
621 /* allocate an instr_info and fill in its addr/size. */
622 i_node = reserve_instr_info( cgs );
623 tl_assert(i_node);
sewardja3a29a52005-10-12 16:16:03 +0000624 init_instr_info( i_node,
sewardj5155dec2005-10-12 10:09:23 +0000625 (Addr)cgs->events[i].iaddr, /* i addr */
626 cgs->events[i].size /* i size */);
627 } else {
628 /* use the most-recently allocated i_node but don't mess with
629 its internals */
630 i_node = find_most_recent_instr_info( cgs );
631 /* it must actually exist */
632 tl_assert(i_node);
633 /* it must match the declared parent instruction of this
634 event. */
635 tl_assert(i_node->instr_addr == cgs->events[i].iaddr);
636 }
637
638 i_node_expr = mkIRExpr_HWord( (HWord)i_node );
639
640 /* Decide on helper fn to call and args to pass it, and advance
641 i appropriately. */
642 switch (cgs->events[i].ekind) {
643 case Event_Ir:
644 /* Merge with a following Dr/Dm if it is from this insn. */
645 if (i < cgs->events_used-1
646 && cgs->events[i+1].iaddr == cgs->events[i].iaddr
647 && (cgs->events[i+1].ekind == Event_Dr
648 || cgs->events[i+1].ekind == Event_Dm)) {
649 helperName = "log_1I_1Dr_cache_access";
650 helperAddr = &log_1I_1Dr_cache_access;
651 argv = mkIRExprVec_3( i_node_expr,
652 cgs->events[i+1].dataEA,
653 mkIRExpr_HWord( cgs->events[i+1].size ) );
654 regparms = 3;
655 i += 2;
656 }
657 /* Merge with a following Dw if it is from this insn. */
658 else
659 if (i < cgs->events_used-1
660 && cgs->events[i+1].iaddr == cgs->events[i].iaddr
661 && cgs->events[i+1].ekind == Event_Dw) {
662 helperName = "log_1I_1Dw_cache_access";
663 helperAddr = &log_1I_1Dw_cache_access;
664 argv = mkIRExprVec_3( i_node_expr,
665 cgs->events[i+1].dataEA,
666 mkIRExpr_HWord( cgs->events[i+1].size ) );
667 regparms = 3;
668 i += 2;
669 }
670 /* Merge with two following Irs if possible. */
671 else
672 if (i < cgs->events_used-2
673 && cgs->events[i+1].ekind == Event_Ir
674 && cgs->events[i+2].ekind == Event_Ir) {
675 helperName = "log_3I_0D_cache_access";
676 helperAddr = &log_3I_0D_cache_access;
677
678 i_node2 = reserve_instr_info( cgs );
679 tl_assert(i_node2);
sewardja3a29a52005-10-12 16:16:03 +0000680 init_instr_info( i_node2,
sewardj5155dec2005-10-12 10:09:23 +0000681 (Addr)cgs->events[i+1].iaddr, /* i addr */
682 cgs->events[i+1].size /* i size */);
683 i_node2_expr = mkIRExpr_HWord( (HWord)i_node2 );
684
685 i_node3 = reserve_instr_info( cgs );
686 tl_assert(i_node3);
sewardja3a29a52005-10-12 16:16:03 +0000687 init_instr_info( i_node3,
sewardj5155dec2005-10-12 10:09:23 +0000688 (Addr)cgs->events[i+2].iaddr, /* i addr */
689 cgs->events[i+2].size /* i size */);
690 i_node3_expr = mkIRExpr_HWord( (HWord)i_node3 );
691
692 argv = mkIRExprVec_3( i_node_expr, i_node2_expr, i_node3_expr );
693 regparms = 3;
694 i += 3;
695 }
696 /* Merge with a following Ir if possible. */
697 else
698 if (i < cgs->events_used-1
699 && cgs->events[i+1].ekind == Event_Ir) {
700 helperName = "log_2I_0D_cache_access";
701 helperAddr = &log_2I_0D_cache_access;
702 i_node2 = reserve_instr_info( cgs );
703 tl_assert(i_node2);
sewardja3a29a52005-10-12 16:16:03 +0000704 init_instr_info( i_node2,
sewardj5155dec2005-10-12 10:09:23 +0000705 (Addr)cgs->events[i+1].iaddr, /* i addr */
706 cgs->events[i+1].size /* i size */);
707 i_node2_expr = mkIRExpr_HWord( (HWord)i_node2 );
708 argv = mkIRExprVec_2( i_node_expr, i_node2_expr );
709 regparms = 2;
710 i += 2;
711 }
712 /* No merging possible; emit as-is. */
713 else {
714 helperName = "log_1I_0D_cache_access";
715 helperAddr = &log_1I_0D_cache_access;
716 argv = mkIRExprVec_1( i_node_expr );
717 regparms = 1;
718 i++;
719 }
720 break;
721 case Event_Dr:
722 case Event_Dm:
723 helperName = "log_0I_1Dr_cache_access";
724 helperAddr = &log_0I_1Dr_cache_access;
725 argv = mkIRExprVec_3( i_node_expr,
726 cgs->events[i].dataEA,
727 mkIRExpr_HWord( cgs->events[i].size ) );
728 regparms = 3;
729 i++;
730 break;
731 case Event_Dw:
732 helperName = "log_0I_1Dw_cache_access";
733 helperAddr = &log_0I_1Dw_cache_access;
734 argv = mkIRExprVec_3( i_node_expr,
735 cgs->events[i].dataEA,
736 mkIRExpr_HWord( cgs->events[i].size ) );
737 regparms = 3;
738 i++;
739 break;
740 default:
741 tl_assert(0);
742 }
743
744 /* Add the helper. */
745 tl_assert(helperName);
746 tl_assert(helperAddr);
747 tl_assert(argv);
748 di = unsafeIRDirty_0_N( regparms, helperName, helperAddr, argv);
749 addStmtToIRBB( cgs->bbOut, IRStmt_Dirty(di) );
njn4f9c9342002-04-29 16:03:24 +0000750 }
751
sewardj5155dec2005-10-12 10:09:23 +0000752 cgs->events_used = 0;
njn4f9c9342002-04-29 16:03:24 +0000753}
njn14d01ce2004-11-26 11:30:14 +0000754
sewardj5155dec2005-10-12 10:09:23 +0000755
756static void addEvent_Ir ( CgState* cgs, Int size, Addr64 iaddr )
757{
758 Event* evt;
759 tl_assert(size >= 0 && size <= MIN_LINE_SIZE);
760 if (cgs->events_used == N_EVENTS)
761 flushEvents(cgs);
762 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
763 /* If vex fails to decode an insn, the size will be zero, but that
764 can't really be true -- the cpu couldn't have determined the
765 insn was undecodable without looking at it. Hence: */
766 if (size == 0)
767 size = 1;
768 evt = &cgs->events[cgs->events_used];
769 evt->ekind = Event_Ir;
770 evt->size = size;
771 evt->iaddr = iaddr;
772 evt->dataEA = NULL; /*paranoia*/
773 cgs->events_used++;
774}
775
776static void addEvent_Dr ( CgState* cgs, Int size, Addr64 iaddr, IRAtom* ea )
777{
778 Event* evt;
779 tl_assert(isIRAtom(ea));
780 tl_assert(size >= 1 && size <= MIN_LINE_SIZE);
781 if (cgs->events_used == N_EVENTS)
782 flushEvents(cgs);
783 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
784 evt = &cgs->events[cgs->events_used];
785 evt->ekind = Event_Dr;
786 evt->size = size;
787 evt->iaddr = iaddr;
788 evt->dataEA = ea;
789 cgs->events_used++;
790}
791
792static void addEvent_Dw ( CgState* cgs, Int size, Addr64 iaddr, IRAtom* ea )
793{
794 tl_assert(isIRAtom(ea));
795 tl_assert(size >= 1 && size <= MIN_LINE_SIZE);
796
797 /* Is it possible to merge this write into an immediately preceding
798 read? */
799 if (cgs->events_used > 0
800 && cgs->events[cgs->events_used-1].ekind == Event_Dr
801 && cgs->events[cgs->events_used-1].size == size
802 && cgs->events[cgs->events_used-1].iaddr == iaddr
803 && eqIRAtom(cgs->events[cgs->events_used-1].dataEA, ea)) {
804 cgs->events[cgs->events_used-1].ekind = Event_Dm;
805 return;
806 }
807
808 /* No. Add as normal. */
809 if (cgs->events_used == N_EVENTS)
810 flushEvents(cgs);
811 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
812 cgs->events[cgs->events_used].ekind = Event_Dw;
813 cgs->events[cgs->events_used].size = size;
814 cgs->events[cgs->events_used].iaddr = iaddr;
815 cgs->events[cgs->events_used].dataEA = ea;
816 cgs->events_used++;
817}
818
819////////////////////////////////////////////////////////////
820
821
njn51d827b2005-05-09 01:02:08 +0000822static IRBB* cg_instrument ( IRBB* bbIn, VexGuestLayout* layout,
823 IRType gWordTy, IRType hWordTy )
njn14d01ce2004-11-26 11:30:14 +0000824{
sewardj5155dec2005-10-12 10:09:23 +0000825 Int i;
826 IRStmt* st;
827 Addr64 cia; /* address of current insn */
828 CgState cgs;
829 IRTypeEnv* tyenv = bbIn->tyenv;
830
njn6a3009b2005-03-20 00:20:06 +0000831
sewardjd54babf2005-03-21 00:55:49 +0000832 if (gWordTy != hWordTy) {
833 /* We don't currently support this case. */
834 VG_(tool_panic)("host/guest word size mismatch");
835 }
836
njn6a3009b2005-03-20 00:20:06 +0000837 /* Set up BB */
sewardj5155dec2005-10-12 10:09:23 +0000838 cgs.bbOut = emptyIRBB();
839 cgs.bbOut->tyenv = dopyIRTypeEnv(tyenv);
njn6a3009b2005-03-20 00:20:06 +0000840
sewardj5155dec2005-10-12 10:09:23 +0000841 // Get the first statement, and initial cia from it
njn6a3009b2005-03-20 00:20:06 +0000842 i = 0;
843 tl_assert(bbIn->stmts_used > 0);
844 st = bbIn->stmts[0];
845 tl_assert(Ist_IMark == st->tag);
sewardj5155dec2005-10-12 10:09:23 +0000846 cia = st->Ist.IMark.addr;
njn6a3009b2005-03-20 00:20:06 +0000847
sewardj5155dec2005-10-12 10:09:23 +0000848 // Set up running state and get block info
849 cgs.events_used = 0;
sewardja3a29a52005-10-12 16:16:03 +0000850 cgs.bbInfo = get_BB_info(bbIn, (Addr)cia);
sewardj5155dec2005-10-12 10:09:23 +0000851 cgs.bbInfo_i = 0;
njn6a3009b2005-03-20 00:20:06 +0000852
sewardj5155dec2005-10-12 10:09:23 +0000853 if (DEBUG_CG)
854 VG_(printf)("\n\n---------- cg_instrument ----------\n");
njn6a3009b2005-03-20 00:20:06 +0000855
sewardj5155dec2005-10-12 10:09:23 +0000856 // Traverse the block, adding events and flushing as necessary.
857 for (i = 0; i < bbIn->stmts_used; i++) {
njn6a3009b2005-03-20 00:20:06 +0000858
sewardj5155dec2005-10-12 10:09:23 +0000859 st = bbIn->stmts[i];
860 tl_assert(isFlatIRStmt(st));
njnb3507ea2005-08-02 23:07:02 +0000861
sewardj5155dec2005-10-12 10:09:23 +0000862 switch (st->tag) {
863 case Ist_NoOp:
864 case Ist_AbiHint:
865 case Ist_Put:
866 case Ist_PutI:
867 case Ist_MFence:
868 break;
njn20677cc2005-08-12 23:47:51 +0000869
sewardj5155dec2005-10-12 10:09:23 +0000870 case Ist_IMark:
871 cia = st->Ist.IMark.addr;
872 addEvent_Ir( &cgs, st->Ist.IMark.len, cia );
873 break;
874
875 case Ist_Tmp: {
876 IRExpr* data = st->Ist.Tmp.data;
877 if (data->tag == Iex_Load) {
878 IRExpr* aexpr = data->Iex.Load.addr;
879 tl_assert( isIRAtom(aexpr) );
880 // Note also, endianness info is ignored. I guess
881 // that's not interesting.
882 addEvent_Dr( &cgs, sizeofIRType(data->Iex.Load.ty),
883 cia, aexpr );
884 }
885 break;
njnb3507ea2005-08-02 23:07:02 +0000886 }
887
sewardj5155dec2005-10-12 10:09:23 +0000888 case Ist_Store: {
889 IRExpr* data = st->Ist.Store.data;
890 IRExpr* aexpr = st->Ist.Store.addr;
891 tl_assert( isIRAtom(aexpr) );
892 addEvent_Dw( &cgs,
893 sizeofIRType(typeOfIRExpr(tyenv, data)),
894 cia, aexpr );
895 break;
896 }
njnb3507ea2005-08-02 23:07:02 +0000897
sewardj5155dec2005-10-12 10:09:23 +0000898 case Ist_Dirty: {
899 Int dataSize;
900 IRDirty* d = st->Ist.Dirty.details;
901 if (d->mFx != Ifx_None) {
902 /* This dirty helper accesses memory. Collect the
903 details. */
904 tl_assert(d->mAddr != NULL);
905 tl_assert(d->mSize != 0);
906 dataSize = d->mSize;
907 // Large (eg. 28B, 108B, 512B on x86) data-sized
908 // instructions will be done inaccurately, but they're
909 // very rare and this avoids errors from hitting more
910 // than two cache lines in the simulation.
911 if (dataSize > MIN_LINE_SIZE)
912 dataSize = MIN_LINE_SIZE;
913 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
914 addEvent_Dr( &cgs, dataSize, cia, d->mAddr );
915 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
916 addEvent_Dw( &cgs, dataSize, cia, d->mAddr );
917 } else {
918 tl_assert(d->mAddr == NULL);
919 tl_assert(d->mSize == 0);
920 }
921 break;
922 }
njn6a3009b2005-03-20 00:20:06 +0000923
sewardj5155dec2005-10-12 10:09:23 +0000924 case Ist_Exit:
925 /* We may never reach the next statement, so need to flush
926 all outstanding transactions now. */
927 flushEvents( &cgs );
928 break;
929
930 default:
931 tl_assert(0);
932 break;
njnb3507ea2005-08-02 23:07:02 +0000933 }
njn6a3009b2005-03-20 00:20:06 +0000934
sewardj5155dec2005-10-12 10:09:23 +0000935 /* Copy the original statement */
936 addStmtToIRBB( cgs.bbOut, st );
njn6a3009b2005-03-20 00:20:06 +0000937
sewardj5155dec2005-10-12 10:09:23 +0000938 if (DEBUG_CG) {
939 ppIRStmt(st);
940 VG_(printf)("\n");
941 }
942 }
943
944 /* At the end of the bb. Flush outstandings. */
945 tl_assert(isIRAtom(bbIn->next));
946 flushEvents( &cgs );
947
948 /* copy where-next stuff. */
949 cgs.bbOut->next = dopyIRExpr(bbIn->next);
950 cgs.bbOut->jumpkind = bbIn->jumpkind;
951
952 /* done. stay sane ... */
953 tl_assert(cgs.bbInfo_i == cgs.bbInfo->n_instrs);
954
955 if (DEBUG_CG) {
956 VG_(printf)( "goto {");
957 ppIRJumpKind(bbIn->jumpkind);
958 VG_(printf)( "} ");
959 ppIRExpr( bbIn->next );
960 VG_(printf)( "}\n");
961 }
962
963 return cgs.bbOut;
njn14d01ce2004-11-26 11:30:14 +0000964}
njn4f9c9342002-04-29 16:03:24 +0000965
966/*------------------------------------------------------------*/
nethercoteb35a8b92004-09-11 16:45:27 +0000967/*--- Cache configuration ---*/
njn4f9c9342002-04-29 16:03:24 +0000968/*------------------------------------------------------------*/
969
sewardjb5f6f512005-03-10 23:59:00 +0000970#define UNDEFINED_CACHE { -1, -1, -1 }
njn25e49d8e72002-09-23 09:36:25 +0000971
972static cache_t clo_I1_cache = UNDEFINED_CACHE;
973static cache_t clo_D1_cache = UNDEFINED_CACHE;
974static cache_t clo_L2_cache = UNDEFINED_CACHE;
975
njn7cf0bd32002-06-08 13:36:03 +0000976/* Checks cache config is ok; makes it so if not. */
sewardj07133bf2002-06-13 10:25:56 +0000977static
njna1d1a642004-11-26 18:36:02 +0000978void check_cache(cache_t* cache, Char *name)
njn7cf0bd32002-06-08 13:36:03 +0000979{
980 /* First check they're all powers of two */
sewardj07133bf2002-06-13 10:25:56 +0000981 if (-1 == VG_(log2)(cache->size)) {
njn7cf0bd32002-06-08 13:36:03 +0000982 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000983 "error: %s size of %dB not a power of two; aborting.",
984 name, cache->size);
985 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000986 }
987
sewardj07133bf2002-06-13 10:25:56 +0000988 if (-1 == VG_(log2)(cache->assoc)) {
njn7cf0bd32002-06-08 13:36:03 +0000989 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000990 "error: %s associativity of %d not a power of two; aborting.",
991 name, cache->assoc);
992 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000993 }
994
sewardj07133bf2002-06-13 10:25:56 +0000995 if (-1 == VG_(log2)(cache->line_size)) {
njn7cf0bd32002-06-08 13:36:03 +0000996 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000997 "error: %s line size of %dB not a power of two; aborting.",
998 name, cache->line_size);
999 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +00001000 }
1001
njn6a3009b2005-03-20 00:20:06 +00001002 // Then check line size >= 16 -- any smaller and a single instruction could
1003 // straddle three cache lines, which breaks a simulation assertion and is
1004 // stupid anyway.
njn7cf0bd32002-06-08 13:36:03 +00001005 if (cache->line_size < MIN_LINE_SIZE) {
1006 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +00001007 "error: %s line size of %dB too small; aborting.",
1008 name, cache->line_size);
1009 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +00001010 }
1011
1012 /* Then check cache size > line size (causes seg faults if not). */
1013 if (cache->size <= cache->line_size) {
1014 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +00001015 "error: %s cache size of %dB <= line size of %dB; aborting.",
1016 name, cache->size, cache->line_size);
1017 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +00001018 }
1019
1020 /* Then check assoc <= (size / line size) (seg faults otherwise). */
1021 if (cache->assoc > (cache->size / cache->line_size)) {
1022 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +00001023 "warning: %s associativity > (size / line size); aborting.", name);
1024 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +00001025 }
1026}
1027
sewardj07133bf2002-06-13 10:25:56 +00001028static
nethercoteb35a8b92004-09-11 16:45:27 +00001029void configure_caches(cache_t* I1c, cache_t* D1c, cache_t* L2c)
njn7cf0bd32002-06-08 13:36:03 +00001030{
nethercote9313ac42004-07-06 21:54:20 +00001031#define DEFINED(L) (-1 != L.size || -1 != L.assoc || -1 != L.line_size)
1032
nethercoteb35a8b92004-09-11 16:45:27 +00001033 Int n_clos = 0;
nethercote9313ac42004-07-06 21:54:20 +00001034
nethercoteb35a8b92004-09-11 16:45:27 +00001035 // Count how many were defined on the command line.
1036 if (DEFINED(clo_I1_cache)) { n_clos++; }
1037 if (DEFINED(clo_D1_cache)) { n_clos++; }
1038 if (DEFINED(clo_L2_cache)) { n_clos++; }
njn7cf0bd32002-06-08 13:36:03 +00001039
njna1d1a642004-11-26 18:36:02 +00001040 // Set the cache config (using auto-detection, if supported by the
1041 // architecture)
njnaf839f52005-06-23 03:27:57 +00001042 VG_(configure_caches)( I1c, D1c, L2c, (3 == n_clos) );
sewardjb1a77a42002-07-13 13:31:20 +00001043
nethercote9313ac42004-07-06 21:54:20 +00001044 // Then replace with any defined on the command line.
nethercoteb35a8b92004-09-11 16:45:27 +00001045 if (DEFINED(clo_I1_cache)) { *I1c = clo_I1_cache; }
1046 if (DEFINED(clo_D1_cache)) { *D1c = clo_D1_cache; }
1047 if (DEFINED(clo_L2_cache)) { *L2c = clo_L2_cache; }
njn7cf0bd32002-06-08 13:36:03 +00001048
nethercote9313ac42004-07-06 21:54:20 +00001049 // Then check values and fix if not acceptable.
njna1d1a642004-11-26 18:36:02 +00001050 check_cache(I1c, "I1");
1051 check_cache(D1c, "D1");
1052 check_cache(L2c, "L2");
njn7cf0bd32002-06-08 13:36:03 +00001053
1054 if (VG_(clo_verbosity) > 1) {
1055 VG_(message)(Vg_UserMsg, "Cache configuration used:");
1056 VG_(message)(Vg_UserMsg, " I1: %dB, %d-way, %dB lines",
1057 I1c->size, I1c->assoc, I1c->line_size);
1058 VG_(message)(Vg_UserMsg, " D1: %dB, %d-way, %dB lines",
1059 D1c->size, D1c->assoc, D1c->line_size);
1060 VG_(message)(Vg_UserMsg, " L2: %dB, %d-way, %dB lines",
1061 L2c->size, L2c->assoc, L2c->line_size);
1062 }
nethercote9313ac42004-07-06 21:54:20 +00001063#undef CMD_LINE_DEFINED
njn7cf0bd32002-06-08 13:36:03 +00001064}
1065
njn4f9c9342002-04-29 16:03:24 +00001066/*------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +00001067/*--- cg_fini() and related function ---*/
njn4f9c9342002-04-29 16:03:24 +00001068/*------------------------------------------------------------*/
1069
nethercote9313ac42004-07-06 21:54:20 +00001070// Total reads/writes/misses. Calculated during CC traversal at the end.
1071// All auto-zeroed.
1072static CC Ir_total;
1073static CC Dr_total;
1074static CC Dw_total;
1075
1076static Char* cachegrind_out_file;
1077
nethercote9313ac42004-07-06 21:54:20 +00001078static void fprint_lineCC(Int fd, lineCC* n)
njn4f9c9342002-04-29 16:03:24 +00001079{
nethercote9313ac42004-07-06 21:54:20 +00001080 Char buf[512];
1081 VG_(sprintf)(buf, "%u %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
1082 n->line,
1083 n->Ir.a, n->Ir.m1, n->Ir.m2,
1084 n->Dr.a, n->Dr.m1, n->Dr.m2,
1085 n->Dw.a, n->Dw.m1, n->Dw.m2);
1086 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1087
1088 Ir_total.a += n->Ir.a; Ir_total.m1 += n->Ir.m1; Ir_total.m2 += n->Ir.m2;
1089 Dr_total.a += n->Dr.a; Dr_total.m1 += n->Dr.m1; Dr_total.m2 += n->Dr.m2;
1090 Dw_total.a += n->Dw.a; Dw_total.m1 += n->Dw.m1; Dw_total.m2 += n->Dw.m2;
1091}
1092
1093static void fprint_CC_table_and_calc_totals(void)
1094{
1095 Int fd;
sewardj92645592005-07-23 09:18:34 +00001096 SysRes sres;
nethercote9313ac42004-07-06 21:54:20 +00001097 Char buf[512];
1098 fileCC *curr_fileCC;
1099 fnCC *curr_fnCC;
1100 lineCC *curr_lineCC;
1101 Int i, j, k;
njn4f9c9342002-04-29 16:03:24 +00001102
njn25e49d8e72002-09-23 09:36:25 +00001103 VGP_PUSHCC(VgpCacheResults);
njn13f02932003-04-30 20:23:58 +00001104
sewardj92645592005-07-23 09:18:34 +00001105 sres = VG_(open)(cachegrind_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
1106 VKI_S_IRUSR|VKI_S_IWUSR);
1107 if (sres.isError) {
nethercote9313ac42004-07-06 21:54:20 +00001108 // If the file can't be opened for whatever reason (conflict
1109 // between multiple cachegrinded processes?), give up now.
njnee0e6a32005-04-24 00:21:01 +00001110 VG_(message)(Vg_UserMsg,
njn02bc4b82005-05-15 17:28:26 +00001111 "error: can't open cache simulation output file '%s'",
njnee0e6a32005-04-24 00:21:01 +00001112 cachegrind_out_file );
1113 VG_(message)(Vg_UserMsg,
1114 " ... so simulation results will be missing.");
sewardj0744b6c2002-12-11 00:45:42 +00001115 return;
sewardj92645592005-07-23 09:18:34 +00001116 } else {
1117 fd = sres.val;
sewardj0744b6c2002-12-11 00:45:42 +00001118 }
njn4f9c9342002-04-29 16:03:24 +00001119
nethercote9313ac42004-07-06 21:54:20 +00001120 // "desc:" lines (giving I1/D1/L2 cache configuration). The spaces after
1121 // the 2nd colon makes cg_annotate's output look nicer.
1122 VG_(sprintf)(buf, "desc: I1 cache: %s\n"
1123 "desc: D1 cache: %s\n"
1124 "desc: L2 cache: %s\n",
1125 I1.desc_line, D1.desc_line, L2.desc_line);
njn7cf0bd32002-06-08 13:36:03 +00001126 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njn4f9c9342002-04-29 16:03:24 +00001127
nethercote9313ac42004-07-06 21:54:20 +00001128 // "cmd:" line
njn4f9c9342002-04-29 16:03:24 +00001129 VG_(strcpy)(buf, "cmd:");
1130 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
sewardj45f4e7c2005-09-27 19:20:21 +00001131 if (VG_(args_the_exename)) {
1132 VG_(write)(fd, " ", 1);
1133 VG_(write)(fd, VG_(args_the_exename),
1134 VG_(strlen)( VG_(args_the_exename) ));
1135 }
1136 for (i = 0; i < VG_(args_for_client).used; i++) {
1137 if (VG_(args_for_client).strs[i]) {
1138 VG_(write)(fd, " ", 1);
1139 VG_(write)(fd, VG_(args_for_client).strs[i],
1140 VG_(strlen)(VG_(args_for_client).strs[i]));
1141 }
njn4f9c9342002-04-29 16:03:24 +00001142 }
nethercote9313ac42004-07-06 21:54:20 +00001143 // "events:" line
njn4f9c9342002-04-29 16:03:24 +00001144 VG_(sprintf)(buf, "\nevents: Ir I1mr I2mr Dr D1mr D2mr Dw D1mw D2mw\n");
1145 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1146
nethercote9313ac42004-07-06 21:54:20 +00001147 // Six loops here: three for the hash table arrays, and three for the
1148 // chains hanging off the hash table arrays.
njn4f9c9342002-04-29 16:03:24 +00001149 for (i = 0; i < N_FILE_ENTRIES; i++) {
nethercote9313ac42004-07-06 21:54:20 +00001150 curr_fileCC = CC_table[i];
1151 while (curr_fileCC != NULL) {
1152 VG_(sprintf)(buf, "fl=%s\n", curr_fileCC->file);
njn4f9c9342002-04-29 16:03:24 +00001153 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1154
1155 for (j = 0; j < N_FN_ENTRIES; j++) {
nethercote9313ac42004-07-06 21:54:20 +00001156 curr_fnCC = curr_fileCC->fns[j];
1157 while (curr_fnCC != NULL) {
1158 VG_(sprintf)(buf, "fn=%s\n", curr_fnCC->fn);
njn4f9c9342002-04-29 16:03:24 +00001159 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1160
nethercote9313ac42004-07-06 21:54:20 +00001161 for (k = 0; k < N_LINE_ENTRIES; k++) {
1162 curr_lineCC = curr_fnCC->lines[k];
1163 while (curr_lineCC != NULL) {
1164 fprint_lineCC(fd, curr_lineCC);
1165 curr_lineCC = curr_lineCC->next;
njn4f9c9342002-04-29 16:03:24 +00001166 }
1167 }
nethercote9313ac42004-07-06 21:54:20 +00001168 curr_fnCC = curr_fnCC->next;
njn4f9c9342002-04-29 16:03:24 +00001169 }
1170 }
nethercote9313ac42004-07-06 21:54:20 +00001171 curr_fileCC = curr_fileCC->next;
njn4f9c9342002-04-29 16:03:24 +00001172 }
1173 }
1174
nethercote9313ac42004-07-06 21:54:20 +00001175 // Summary stats must come after rest of table, since we calculate them
1176 // during traversal. */
njn4f9c9342002-04-29 16:03:24 +00001177 VG_(sprintf)(buf, "summary: "
nethercote9313ac42004-07-06 21:54:20 +00001178 "%llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
njn4f9c9342002-04-29 16:03:24 +00001179 Ir_total.a, Ir_total.m1, Ir_total.m2,
1180 Dr_total.a, Dr_total.m1, Dr_total.m2,
1181 Dw_total.a, Dw_total.m1, Dw_total.m2);
1182 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1183 VG_(close)(fd);
1184}
1185
njn607adfc2003-09-30 14:15:44 +00001186static UInt ULong_width(ULong n)
njn4f9c9342002-04-29 16:03:24 +00001187{
njn607adfc2003-09-30 14:15:44 +00001188 UInt w = 0;
1189 while (n > 0) {
1190 n = n / 10;
1191 w++;
njn4f9c9342002-04-29 16:03:24 +00001192 }
njn607adfc2003-09-30 14:15:44 +00001193 return w + (w-1)/3; // add space for commas
njn4f9c9342002-04-29 16:03:24 +00001194}
1195
njn51d827b2005-05-09 01:02:08 +00001196static void cg_fini(Int exitcode)
njn4f9c9342002-04-29 16:03:24 +00001197{
njn0103de52005-10-10 16:49:01 +00001198 static Char buf1[128], buf2[128], buf3[128], fmt [128];
njn607adfc2003-09-30 14:15:44 +00001199
njn4f9c9342002-04-29 16:03:24 +00001200 CC D_total;
njn1d021fa2002-05-02 13:56:34 +00001201 ULong L2_total_m, L2_total_mr, L2_total_mw,
1202 L2_total, L2_total_r, L2_total_w;
njn4f9c9342002-04-29 16:03:24 +00001203 Int l1, l2, l3;
1204 Int p;
1205
nethercote9313ac42004-07-06 21:54:20 +00001206 fprint_CC_table_and_calc_totals();
njn4f9c9342002-04-29 16:03:24 +00001207
njn7cf0bd32002-06-08 13:36:03 +00001208 if (VG_(clo_verbosity) == 0)
1209 return;
1210
njn4f9c9342002-04-29 16:03:24 +00001211 /* I cache results. Use the I_refs value to determine the first column
1212 * width. */
njn607adfc2003-09-30 14:15:44 +00001213 l1 = ULong_width(Ir_total.a);
1214 l2 = ULong_width(Dr_total.a);
1215 l3 = ULong_width(Dw_total.a);
njn4f9c9342002-04-29 16:03:24 +00001216
njn607adfc2003-09-30 14:15:44 +00001217 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001218 VG_(sprintf)(fmt, "%%s %%,%dllu", l1);
njn607adfc2003-09-30 14:15:44 +00001219
1220 VG_(message)(Vg_UserMsg, fmt, "I refs: ", Ir_total.a);
1221 VG_(message)(Vg_UserMsg, fmt, "I1 misses: ", Ir_total.m1);
1222 VG_(message)(Vg_UserMsg, fmt, "L2i misses: ", Ir_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001223
1224 p = 100;
1225
njn25e49d8e72002-09-23 09:36:25 +00001226 if (0 == Ir_total.a) Ir_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001227 VG_(percentify)(Ir_total.m1, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001228 VG_(message)(Vg_UserMsg, "I1 miss rate: %s", buf1);
1229
njn856c54e2005-06-26 18:43:40 +00001230 VG_(percentify)(Ir_total.m2, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001231 VG_(message)(Vg_UserMsg, "L2i miss rate: %s", buf1);
1232 VG_(message)(Vg_UserMsg, "");
1233
1234 /* D cache results. Use the D_refs.rd and D_refs.wr values to determine the
1235 * width of columns 2 & 3. */
1236 D_total.a = Dr_total.a + Dw_total.a;
1237 D_total.m1 = Dr_total.m1 + Dw_total.m1;
1238 D_total.m2 = Dr_total.m2 + Dw_total.m2;
1239
njn607adfc2003-09-30 14:15:44 +00001240 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001241 VG_(sprintf)(fmt, "%%s %%,%dllu (%%,%dllu rd + %%,%dllu wr)", l1, l2, l3);
njn4f9c9342002-04-29 16:03:24 +00001242
njn607adfc2003-09-30 14:15:44 +00001243 VG_(message)(Vg_UserMsg, fmt, "D refs: ",
1244 D_total.a, Dr_total.a, Dw_total.a);
1245 VG_(message)(Vg_UserMsg, fmt, "D1 misses: ",
1246 D_total.m1, Dr_total.m1, Dw_total.m1);
1247 VG_(message)(Vg_UserMsg, fmt, "L2d misses: ",
1248 D_total.m2, Dr_total.m2, Dw_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001249
1250 p = 10;
1251
njn25e49d8e72002-09-23 09:36:25 +00001252 if (0 == D_total.a) D_total.a = 1;
1253 if (0 == Dr_total.a) Dr_total.a = 1;
1254 if (0 == Dw_total.a) Dw_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001255 VG_(percentify)( D_total.m1, D_total.a, 1, l1+1, buf1);
1256 VG_(percentify)(Dr_total.m1, Dr_total.a, 1, l2+1, buf2);
1257 VG_(percentify)(Dw_total.m1, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001258 VG_(message)(Vg_UserMsg, "D1 miss rate: %s (%s + %s )", buf1, buf2,buf3);
1259
njn856c54e2005-06-26 18:43:40 +00001260 VG_(percentify)( D_total.m2, D_total.a, 1, l1+1, buf1);
1261 VG_(percentify)(Dr_total.m2, Dr_total.a, 1, l2+1, buf2);
1262 VG_(percentify)(Dw_total.m2, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001263 VG_(message)(Vg_UserMsg, "L2d miss rate: %s (%s + %s )", buf1, buf2,buf3);
1264 VG_(message)(Vg_UserMsg, "");
1265
1266 /* L2 overall results */
njn1d021fa2002-05-02 13:56:34 +00001267
1268 L2_total = Dr_total.m1 + Dw_total.m1 + Ir_total.m1;
1269 L2_total_r = Dr_total.m1 + Ir_total.m1;
1270 L2_total_w = Dw_total.m1;
njn607adfc2003-09-30 14:15:44 +00001271 VG_(message)(Vg_UserMsg, fmt, "L2 refs: ",
1272 L2_total, L2_total_r, L2_total_w);
njn1d021fa2002-05-02 13:56:34 +00001273
njn4f9c9342002-04-29 16:03:24 +00001274 L2_total_m = Dr_total.m2 + Dw_total.m2 + Ir_total.m2;
1275 L2_total_mr = Dr_total.m2 + Ir_total.m2;
1276 L2_total_mw = Dw_total.m2;
njn607adfc2003-09-30 14:15:44 +00001277 VG_(message)(Vg_UserMsg, fmt, "L2 misses: ",
1278 L2_total_m, L2_total_mr, L2_total_mw);
njn4f9c9342002-04-29 16:03:24 +00001279
njn856c54e2005-06-26 18:43:40 +00001280 VG_(percentify)(L2_total_m, (Ir_total.a + D_total.a), 1, l1+1, buf1);
1281 VG_(percentify)(L2_total_mr, (Ir_total.a + Dr_total.a), 1, l2+1, buf2);
1282 VG_(percentify)(L2_total_mw, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001283 VG_(message)(Vg_UserMsg, "L2 miss rate: %s (%s + %s )", buf1, buf2,buf3);
1284
1285
nethercote9313ac42004-07-06 21:54:20 +00001286 // Various stats
njn4f9c9342002-04-29 16:03:24 +00001287 if (VG_(clo_verbosity) > 1) {
njn0103de52005-10-10 16:49:01 +00001288 Int BB_lookups = full_debug_BBs + fn_debug_BBs +
njn4f9c9342002-04-29 16:03:24 +00001289 file_line_debug_BBs + no_debug_BBs;
1290
1291 VG_(message)(Vg_DebugMsg, "");
1292 VG_(message)(Vg_DebugMsg, "Distinct files: %d", distinct_files);
1293 VG_(message)(Vg_DebugMsg, "Distinct fns: %d", distinct_fns);
nethercote9313ac42004-07-06 21:54:20 +00001294 VG_(message)(Vg_DebugMsg, "Distinct lines: %d", distinct_lines);
1295 VG_(message)(Vg_DebugMsg, "Distinct instrs: %d", distinct_instrs);
njn4f9c9342002-04-29 16:03:24 +00001296 VG_(message)(Vg_DebugMsg, "BB lookups: %d", BB_lookups);
1297 VG_(message)(Vg_DebugMsg, "With full debug info:%3d%% (%d)",
1298 full_debug_BBs * 100 / BB_lookups,
1299 full_debug_BBs);
1300 VG_(message)(Vg_DebugMsg, "With file/line debug info:%3d%% (%d)",
1301 file_line_debug_BBs * 100 / BB_lookups,
1302 file_line_debug_BBs);
1303 VG_(message)(Vg_DebugMsg, "With fn name debug info:%3d%% (%d)",
nethercote9313ac42004-07-06 21:54:20 +00001304 fn_debug_BBs * 100 / BB_lookups,
1305 fn_debug_BBs);
njn4f9c9342002-04-29 16:03:24 +00001306 VG_(message)(Vg_DebugMsg, "With no debug info:%3d%% (%d)",
1307 no_debug_BBs * 100 / BB_lookups,
1308 no_debug_BBs);
1309 VG_(message)(Vg_DebugMsg, "BBs Retranslated: %d", BB_retranslations);
njn4f9c9342002-04-29 16:03:24 +00001310 }
njn25e49d8e72002-09-23 09:36:25 +00001311 VGP_POPCC(VgpCacheResults);
njn4f9c9342002-04-29 16:03:24 +00001312}
1313
nethercote9313ac42004-07-06 21:54:20 +00001314/*--------------------------------------------------------------------*/
1315/*--- Discarding BB info ---*/
1316/*--------------------------------------------------------------------*/
sewardj18d75132002-05-16 11:06:21 +00001317
sewardja3a29a52005-10-12 16:16:03 +00001318// Called when a translation is removed from the translation cache for
1319// any reason at all: to free up space, because the guest code was
1320// unmapped or modified, or for any arbitrary reason.
sewardj5155dec2005-10-12 10:09:23 +00001321static void cg_discard_basic_block_info ( VexGuestExtents vge )
sewardj18d75132002-05-16 11:06:21 +00001322{
sewardj5155dec2005-10-12 10:09:23 +00001323 VgHashNode* bbInfo;
njn4294fd42002-06-05 14:41:10 +00001324
sewardj5155dec2005-10-12 10:09:23 +00001325 tl_assert(vge.n_used > 0);
1326
1327 if (DEBUG_CG)
1328 VG_(printf)( "discard_basic_block_info: %p, %llu\n",
1329 (void*)(Addr)vge.base[0], (ULong)vge.len[0]);
njn4294fd42002-06-05 14:41:10 +00001330
nethercote9313ac42004-07-06 21:54:20 +00001331 // Get BB info, remove from table, free BB info. Simple!
sewardj5155dec2005-10-12 10:09:23 +00001332 bbInfo = VG_(HT_remove)(instr_info_table, (UWord)vge.base[0]);
njn6a3009b2005-03-20 00:20:06 +00001333 tl_assert(NULL != bbInfo);
sewardj5155dec2005-10-12 10:09:23 +00001334
njn6a3009b2005-03-20 00:20:06 +00001335 VG_(free)(bbInfo);
sewardj18d75132002-05-16 11:06:21 +00001336}
1337
1338/*--------------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001339/*--- Command line processing ---*/
1340/*--------------------------------------------------------------------*/
1341
njn0103de52005-10-10 16:49:01 +00001342static void parse_cache_opt ( cache_t* cache, Char* opt )
njn25e49d8e72002-09-23 09:36:25 +00001343{
njn0103de52005-10-10 16:49:01 +00001344 Int i = 0, i2, i3;
njn25e49d8e72002-09-23 09:36:25 +00001345
nethercote9313ac42004-07-06 21:54:20 +00001346 // Option argument looks like "65536,2,64".
1347 // Find commas, replace with NULs to make three independent
1348 // strings, then extract numbers, put NULs back. Yuck.
njn25e49d8e72002-09-23 09:36:25 +00001349 while (VG_(isdigit)(opt[i])) i++;
1350 if (',' == opt[i]) {
1351 opt[i++] = '\0';
1352 i2 = i;
1353 } else goto bad;
1354 while (VG_(isdigit)(opt[i])) i++;
1355 if (',' == opt[i]) {
1356 opt[i++] = '\0';
1357 i3 = i;
1358 } else goto bad;
1359 while (VG_(isdigit)(opt[i])) i++;
1360 if ('\0' != opt[i]) goto bad;
1361
nethercote9313ac42004-07-06 21:54:20 +00001362 cache->size = (Int)VG_(atoll)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001363 cache->assoc = (Int)VG_(atoll)(opt + i2);
1364 cache->line_size = (Int)VG_(atoll)(opt + i3);
1365
nethercote9313ac42004-07-06 21:54:20 +00001366 opt[i2-1] = ',';
1367 opt[i3-1] = ',';
njn25e49d8e72002-09-23 09:36:25 +00001368 return;
1369
1370 bad:
nethercote9313ac42004-07-06 21:54:20 +00001371 VG_(bad_option)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001372}
1373
njn51d827b2005-05-09 01:02:08 +00001374static Bool cg_process_cmd_line_option(Char* arg)
njn25e49d8e72002-09-23 09:36:25 +00001375{
nethercote9313ac42004-07-06 21:54:20 +00001376 // 5 is length of "--I1="
njn39c86652003-05-21 10:13:39 +00001377 if (VG_CLO_STREQN(5, arg, "--I1="))
nethercote9313ac42004-07-06 21:54:20 +00001378 parse_cache_opt(&clo_I1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001379 else if (VG_CLO_STREQN(5, arg, "--D1="))
nethercote9313ac42004-07-06 21:54:20 +00001380 parse_cache_opt(&clo_D1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001381 else if (VG_CLO_STREQN(5, arg, "--L2="))
nethercote9313ac42004-07-06 21:54:20 +00001382 parse_cache_opt(&clo_L2_cache, &arg[5]);
njn25e49d8e72002-09-23 09:36:25 +00001383 else
1384 return False;
1385
1386 return True;
1387}
1388
njn51d827b2005-05-09 01:02:08 +00001389static void cg_print_usage(void)
njn25e49d8e72002-09-23 09:36:25 +00001390{
njn3e884182003-04-15 13:03:23 +00001391 VG_(printf)(
njn25e49d8e72002-09-23 09:36:25 +00001392" --I1=<size>,<assoc>,<line_size> set I1 cache manually\n"
1393" --D1=<size>,<assoc>,<line_size> set D1 cache manually\n"
njn3e884182003-04-15 13:03:23 +00001394" --L2=<size>,<assoc>,<line_size> set L2 cache manually\n"
1395 );
1396}
1397
njn51d827b2005-05-09 01:02:08 +00001398static void cg_print_debug_usage(void)
njn3e884182003-04-15 13:03:23 +00001399{
1400 VG_(printf)(
1401" (none)\n"
1402 );
njn25e49d8e72002-09-23 09:36:25 +00001403}
1404
1405/*--------------------------------------------------------------------*/
1406/*--- Setup ---*/
1407/*--------------------------------------------------------------------*/
1408
njn51d827b2005-05-09 01:02:08 +00001409static void cg_post_clo_init(void)
njn25e49d8e72002-09-23 09:36:25 +00001410{
1411 cache_t I1c, D1c, L2c;
njn25e49d8e72002-09-23 09:36:25 +00001412
nethercoteb35a8b92004-09-11 16:45:27 +00001413 configure_caches(&I1c, &D1c, &L2c);
njn25e49d8e72002-09-23 09:36:25 +00001414
1415 cachesim_I1_initcache(I1c);
1416 cachesim_D1_initcache(D1c);
1417 cachesim_L2_initcache(L2c);
1418
njn31066fd2005-03-26 00:42:02 +00001419 VG_(register_profile_event)(VgpGetLineCC, "get-lineCC");
1420 VG_(register_profile_event)(VgpCacheSimulate, "cache-simulate");
1421 VG_(register_profile_event)(VgpCacheResults, "cache-results");
njn25e49d8e72002-09-23 09:36:25 +00001422}
1423
njn57ca7ab2005-06-21 23:44:58 +00001424static Char base_dir[VKI_PATH_MAX];
1425
njn51d827b2005-05-09 01:02:08 +00001426static void cg_pre_clo_init(void)
1427{
njn51d827b2005-05-09 01:02:08 +00001428 VG_(details_name) ("Cachegrind");
1429 VG_(details_version) (NULL);
1430 VG_(details_description) ("an I1/D1/L2 cache profiler");
1431 VG_(details_copyright_author)(
1432 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote et al.");
1433 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj5155dec2005-10-12 10:09:23 +00001434 VG_(details_avg_translation_sizeB) ( 245 );
njn51d827b2005-05-09 01:02:08 +00001435
1436 VG_(basic_tool_funcs) (cg_post_clo_init,
1437 cg_instrument,
1438 cg_fini);
1439
1440 VG_(needs_basic_block_discards)(cg_discard_basic_block_info);
1441 VG_(needs_command_line_options)(cg_process_cmd_line_option,
1442 cg_print_usage,
1443 cg_print_debug_usage);
1444
1445 /* Get working directory */
njn57ca7ab2005-06-21 23:44:58 +00001446 tl_assert( VG_(getcwd)(base_dir, VKI_PATH_MAX) );
njn51d827b2005-05-09 01:02:08 +00001447
1448 /* Block is big enough for dir name + cachegrind.out.<pid> */
1449 cachegrind_out_file = VG_(malloc)((VG_(strlen)(base_dir) + 32)*sizeof(Char));
1450 VG_(sprintf)(cachegrind_out_file, "%s/cachegrind.out.%d",
1451 base_dir, VG_(getpid)());
njn51d827b2005-05-09 01:02:08 +00001452
njnf69f9452005-07-03 17:53:11 +00001453 instr_info_table = VG_(HT_construct)( 4999 ); // prime, biggish
njn51d827b2005-05-09 01:02:08 +00001454}
1455
sewardj45f4e7c2005-09-27 19:20:21 +00001456VG_DETERMINE_INTERFACE_VERSION(cg_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00001457
njn25e49d8e72002-09-23 09:36:25 +00001458/*--------------------------------------------------------------------*/
njnf69f9452005-07-03 17:53:11 +00001459/*--- end ---*/
sewardj18d75132002-05-16 11:06:21 +00001460/*--------------------------------------------------------------------*/