blob: a617f88c8e7dfe7930de3c10b521078f410d297c [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"
njn97405b22005-06-02 03:39:33 +000034#include "pub_tool_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000035#include "pub_tool_libcassert.h"
njneb8896b2005-06-04 20:03:55 +000036#include "pub_tool_libcfile.h"
njn36a20fa2005-06-03 03:08:39 +000037#include "pub_tool_libcprint.h"
njnf39e9a32005-06-12 02:43:17 +000038#include "pub_tool_libcproc.h"
njnf536bbb2005-06-13 04:21:38 +000039#include "pub_tool_machine.h"
njn717cde52005-05-10 02:47:21 +000040#include "pub_tool_mallocfree.h"
njn20242342005-05-16 23:31:24 +000041#include "pub_tool_options.h"
njnd3bef4f2005-10-15 17:46:18 +000042#include "pub_tool_oset.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
njnd3bef4f2005-10-15 17:46:18 +000058#define FILE_LEN VKI_PATH_MAX
nethercote9313ac42004-07-06 21:54:20 +000059#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.
njnd3bef4f2005-10-15 17:46:18 +000087// - an ordered set of CCs. CC indexing done by file/function/line (as
88// determined from the instrAddr).
nethercote9313ac42004-07-06 21:54:20 +000089// - Traversed for dumping stats at end in file/func/line hierarchy.
njn4f9c9342002-04-29 16:03:24 +000090
njnd3bef4f2005-10-15 17:46:18 +000091typedef struct {
92 Char* file;
93 Char* fn;
94 Int line;
95}
96CodeLoc;
njn4f9c9342002-04-29 16:03:24 +000097
njnd3bef4f2005-10-15 17:46:18 +000098typedef struct _LineCC LineCC;
99struct _LineCC {
100 CodeLoc loc;
101 CC Ir;
102 CC Dr;
103 CC Dw;
njn4f9c9342002-04-29 16:03:24 +0000104};
105
njnd3bef4f2005-10-15 17:46:18 +0000106// First compare file, then fn, then line.
107static Int cmp_CodeLoc_LineCC(void *vloc, void *vcc)
108{
109 Int res;
110 CodeLoc* a = (CodeLoc*)vloc;
111 CodeLoc* b = &(((LineCC*)vcc)->loc);
njn4f9c9342002-04-29 16:03:24 +0000112
njnd3bef4f2005-10-15 17:46:18 +0000113 res = VG_(strcmp)(a->file, b->file);
114 if (0 != res)
115 return res;
njn4f9c9342002-04-29 16:03:24 +0000116
njnd3bef4f2005-10-15 17:46:18 +0000117 res = VG_(strcmp)(a->fn, b->fn);
118 if (0 != res)
119 return res;
120
121 return a->line - b->line;
122}
123
124static OSet* CC_table;
njn4f9c9342002-04-29 16:03:24 +0000125
nethercote9313ac42004-07-06 21:54:20 +0000126//------------------------------------------------------------
njnd3bef4f2005-10-15 17:46:18 +0000127// Primary data structure #2: InstrInfo table
nethercote9313ac42004-07-06 21:54:20 +0000128// - Holds the cached info about each instr that is used for simulation.
njnd3bef4f2005-10-15 17:46:18 +0000129// - table(BB_start_addr, list(InstrInfo))
130// - For each BB, each InstrInfo in the list holds info about the
131// instruction (instrLen, instrAddr, etc), plus a pointer to its line
nethercote9313ac42004-07-06 21:54:20 +0000132// CC. This node is what's passed to the simulation function.
133// - When BBs are discarded the relevant list(instr_details) is freed.
134
njnd3bef4f2005-10-15 17:46:18 +0000135typedef struct _InstrInfo InstrInfo;
136struct _InstrInfo {
nethercoteca1f2dc2004-07-21 08:49:02 +0000137 Addr instr_addr;
njn6a3009b2005-03-20 00:20:06 +0000138 UChar instr_len;
njnd3bef4f2005-10-15 17:46:18 +0000139 LineCC* parent; // parent line-CC
nethercote9313ac42004-07-06 21:54:20 +0000140};
141
142typedef struct _BB_info BB_info;
143struct _BB_info {
njnd3bef4f2005-10-15 17:46:18 +0000144 Addr BB_addr; // key
145 Int n_instrs;
146 InstrInfo instrs[0];
nethercote9313ac42004-07-06 21:54:20 +0000147};
148
njnd3bef4f2005-10-15 17:46:18 +0000149static OSet* instrInfoTable;
150
151//------------------------------------------------------------
152// Secondary data structure: string table
153// - holds strings, avoiding dups
154// - used for filenames and function names, each of which will be
155// pointed to by one or more CCs.
156// - it also allows equality checks just by pointer comparison, which
157// is good when printing the output file at the end.
158
159static OSet* stringTable;
nethercote9313ac42004-07-06 21:54:20 +0000160
161//------------------------------------------------------------
162// Stats
sewardj4f29ddf2002-05-03 22:29:04 +0000163static Int distinct_files = 0;
164static Int distinct_fns = 0;
nethercote9313ac42004-07-06 21:54:20 +0000165static Int distinct_lines = 0;
sewardj4f29ddf2002-05-03 22:29:04 +0000166static Int distinct_instrs = 0;
nethercote9313ac42004-07-06 21:54:20 +0000167
njnd3bef4f2005-10-15 17:46:18 +0000168static Int full_debugs = 0;
169static Int file_line_debugs = 0;
170static Int fn_debugs = 0;
171static Int no_debugs = 0;
njn4f9c9342002-04-29 16:03:24 +0000172
sewardj4f29ddf2002-05-03 22:29:04 +0000173static Int BB_retranslations = 0;
njn4f9c9342002-04-29 16:03:24 +0000174
nethercote9313ac42004-07-06 21:54:20 +0000175/*------------------------------------------------------------*/
njnd3bef4f2005-10-15 17:46:18 +0000176/*--- String table operations ---*/
177/*------------------------------------------------------------*/
178
179static Int stringCmp( void* key, void* elem )
180{
181 return VG_(strcmp)(*(Char**)key, *(Char**)elem);
182}
183
184// Get a permanent string; either pull it out of the string table if it's
185// been encountered before, or dup it and put it into the string table.
186static Char* get_perm_string(Char* s)
187{
188 Char** s_ptr = VG_(OSet_Lookup)(stringTable, &s);
189 if (s_ptr) {
190 return *s_ptr;
191 } else {
192 Char** s_node = VG_(OSet_AllocNode)(stringTable, sizeof(Char*));
193 *s_node = VG_(strdup)(s);
194 VG_(OSet_Insert)(stringTable, s_node);
195 return *s_node;
196 }
197}
198
199/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +0000200/*--- CC table operations ---*/
201/*------------------------------------------------------------*/
njn4294fd42002-06-05 14:41:10 +0000202
nethercote9313ac42004-07-06 21:54:20 +0000203static void get_debug_info(Addr instr_addr, Char file[FILE_LEN],
204 Char fn[FN_LEN], Int* line)
njn4f9c9342002-04-29 16:03:24 +0000205{
sewardj7cee6f92005-06-13 17:39:06 +0000206 Bool found_file_line = VG_(get_filename_linenum)(
207 instr_addr,
208 file, FILE_LEN,
209 NULL, 0, NULL,
210 line
211 );
nethercote9313ac42004-07-06 21:54:20 +0000212 Bool found_fn = VG_(get_fnname)(instr_addr, fn, FN_LEN);
njn4f9c9342002-04-29 16:03:24 +0000213
nethercote9313ac42004-07-06 21:54:20 +0000214 if (!found_file_line) {
215 VG_(strcpy)(file, "???");
216 *line = 0;
217 }
218 if (!found_fn) {
219 VG_(strcpy)(fn, "???");
220 }
221 if (found_file_line) {
njnd3bef4f2005-10-15 17:46:18 +0000222 if (found_fn) full_debugs++;
223 else file_line_debugs++;
nethercote9313ac42004-07-06 21:54:20 +0000224 } else {
njnd3bef4f2005-10-15 17:46:18 +0000225 if (found_fn) fn_debugs++;
226 else no_debugs++;
njn4f9c9342002-04-29 16:03:24 +0000227 }
228}
229
nethercote9313ac42004-07-06 21:54:20 +0000230// Do a three step traversal: by file, then fn, then line.
njnd3bef4f2005-10-15 17:46:18 +0000231// Returns a pointer to the line CC, creates a new one if necessary.
232static LineCC* get_lineCC(Addr origAddr)
nethercote9313ac42004-07-06 21:54:20 +0000233{
nethercote9313ac42004-07-06 21:54:20 +0000234 Char file[FILE_LEN], fn[FN_LEN];
235 Int line;
njnd3bef4f2005-10-15 17:46:18 +0000236 CodeLoc loc;
237 LineCC* lineCC;
nethercote9313ac42004-07-06 21:54:20 +0000238
njn6a3009b2005-03-20 00:20:06 +0000239 get_debug_info(origAddr, file, fn, &line);
nethercote9313ac42004-07-06 21:54:20 +0000240
241 VGP_PUSHCC(VgpGetLineCC);
242
njnd3bef4f2005-10-15 17:46:18 +0000243 loc.file = file;
244 loc.fn = fn;
245 loc.line = line;
njn4f9c9342002-04-29 16:03:24 +0000246
njnd3bef4f2005-10-15 17:46:18 +0000247 lineCC = VG_(OSet_Lookup)(CC_table, &loc);
248 if (!lineCC) {
249 // Allocate and zero a new node.
250 lineCC = VG_(OSet_AllocNode)(CC_table, sizeof(LineCC));
251 lineCC->loc.file = get_perm_string(loc.file);
252 lineCC->loc.fn = get_perm_string(loc.fn);
253 lineCC->loc.line = loc.line;
254 VG_(OSet_Insert)(CC_table, lineCC);
njn4f9c9342002-04-29 16:03:24 +0000255 }
nethercote9313ac42004-07-06 21:54:20 +0000256
257 VGP_POPCC(VgpGetLineCC);
njnd3bef4f2005-10-15 17:46:18 +0000258 return lineCC;
njn4f9c9342002-04-29 16:03:24 +0000259}
260
261/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +0000262/*--- Cache simulation functions ---*/
njn4f9c9342002-04-29 16:03:24 +0000263/*------------------------------------------------------------*/
264
njnaf839f52005-06-23 03:27:57 +0000265static VG_REGPARM(1)
njnd3bef4f2005-10-15 17:46:18 +0000266void log_1I_0D_cache_access(InstrInfo* n)
njn25e49d8e72002-09-23 09:36:25 +0000267{
sewardj5155dec2005-10-12 10:09:23 +0000268 //VG_(printf)("1I_0D : CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n",
269 // n, n->instr_addr, n->instr_len);
njn25e49d8e72002-09-23 09:36:25 +0000270 VGP_PUSHCC(VgpCacheSimulate);
njn6a3009b2005-03-20 00:20:06 +0000271 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000272 &n->parent->Ir.m1, &n->parent->Ir.m2);
273 n->parent->Ir.a++;
njn25e49d8e72002-09-23 09:36:25 +0000274 VGP_POPCC(VgpCacheSimulate);
275}
276
njnaf839f52005-06-23 03:27:57 +0000277static VG_REGPARM(2)
njnd3bef4f2005-10-15 17:46:18 +0000278void log_2I_0D_cache_access(InstrInfo* n, InstrInfo* n2)
njn25e49d8e72002-09-23 09:36:25 +0000279{
sewardj5155dec2005-10-12 10:09:23 +0000280 //VG_(printf)("2I_0D : CC1addr=0x%010lx, i1addr=0x%010lx, i1size=%lu\n"
281 // " CC2addr=0x%010lx, i2addr=0x%010lx, i2size=%lu\n",
282 // n, n->instr_addr, n->instr_len,
283 // n2, n2->instr_addr, n2->instr_len);
284 VGP_PUSHCC(VgpCacheSimulate);
285 cachesim_I1_doref(n->instr_addr, n->instr_len,
286 &n->parent->Ir.m1, &n->parent->Ir.m2);
287 n->parent->Ir.a++;
288 cachesim_I1_doref(n2->instr_addr, n2->instr_len,
289 &n2->parent->Ir.m1, &n2->parent->Ir.m2);
290 n2->parent->Ir.a++;
291 VGP_POPCC(VgpCacheSimulate);
292}
293
294static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000295void log_3I_0D_cache_access(InstrInfo* n, InstrInfo* n2, InstrInfo* n3)
sewardj5155dec2005-10-12 10:09:23 +0000296{
297 //VG_(printf)("3I_0D : CC1addr=0x%010lx, i1addr=0x%010lx, i1size=%lu\n"
298 // " CC2addr=0x%010lx, i2addr=0x%010lx, i2size=%lu\n"
299 // " CC3addr=0x%010lx, i3addr=0x%010lx, i3size=%lu\n",
300 // n, n->instr_addr, n->instr_len,
301 // n2, n2->instr_addr, n2->instr_len,
302 // n3, n3->instr_addr, n3->instr_len);
303 VGP_PUSHCC(VgpCacheSimulate);
304 cachesim_I1_doref(n->instr_addr, n->instr_len,
305 &n->parent->Ir.m1, &n->parent->Ir.m2);
306 n->parent->Ir.a++;
307 cachesim_I1_doref(n2->instr_addr, n2->instr_len,
308 &n2->parent->Ir.m1, &n2->parent->Ir.m2);
309 n2->parent->Ir.a++;
310 cachesim_I1_doref(n3->instr_addr, n3->instr_len,
311 &n3->parent->Ir.m1, &n3->parent->Ir.m2);
312 n3->parent->Ir.a++;
313 VGP_POPCC(VgpCacheSimulate);
314}
315
316static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000317void log_1I_1Dr_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
sewardj5155dec2005-10-12 10:09:23 +0000318{
319 //VG_(printf)("1I_1Dr: CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n"
320 // " daddr=0x%010lx, dsize=%lu\n",
321 // n, n->instr_addr, n->instr_len, data_addr, data_size);
njn25e49d8e72002-09-23 09:36:25 +0000322 VGP_PUSHCC(VgpCacheSimulate);
njn6a3009b2005-03-20 00:20:06 +0000323 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000324 &n->parent->Ir.m1, &n->parent->Ir.m2);
325 n->parent->Ir.a++;
njn25e49d8e72002-09-23 09:36:25 +0000326
sewardj5155dec2005-10-12 10:09:23 +0000327 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000328 &n->parent->Dr.m1, &n->parent->Dr.m2);
329 n->parent->Dr.a++;
njn25e49d8e72002-09-23 09:36:25 +0000330 VGP_POPCC(VgpCacheSimulate);
331}
332
sewardj5155dec2005-10-12 10:09:23 +0000333static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000334void log_1I_1Dw_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
njn25e49d8e72002-09-23 09:36:25 +0000335{
sewardj5155dec2005-10-12 10:09:23 +0000336 //VG_(printf)("1I_1Dw: CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n"
337 // " daddr=0x%010lx, dsize=%lu\n",
338 // n, n->instr_addr, n->instr_len, data_addr, data_size);
njn25e49d8e72002-09-23 09:36:25 +0000339 VGP_PUSHCC(VgpCacheSimulate);
njn6a3009b2005-03-20 00:20:06 +0000340 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000341 &n->parent->Ir.m1, &n->parent->Ir.m2);
342 n->parent->Ir.a++;
343
sewardj5155dec2005-10-12 10:09:23 +0000344 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000345 &n->parent->Dw.m1, &n->parent->Dw.m2);
346 n->parent->Dw.a++;
njn25e49d8e72002-09-23 09:36:25 +0000347 VGP_POPCC(VgpCacheSimulate);
348}
349
njnaf839f52005-06-23 03:27:57 +0000350static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000351void log_0I_1Dr_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
njn25e49d8e72002-09-23 09:36:25 +0000352{
sewardj5155dec2005-10-12 10:09:23 +0000353 //VG_(printf)("0I_1Dr: CCaddr=0x%010lx, daddr=0x%010lx, dsize=%lu\n",
354 // n, data_addr, data_size);
njn25e49d8e72002-09-23 09:36:25 +0000355 VGP_PUSHCC(VgpCacheSimulate);
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++;
sewardj5155dec2005-10-12 10:09:23 +0000359 VGP_POPCC(VgpCacheSimulate);
360}
361
362static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000363void log_0I_1Dw_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
sewardj5155dec2005-10-12 10:09:23 +0000364{
365 //VG_(printf)("0I_1Dw: CCaddr=0x%010lx, daddr=0x%010lx, dsize=%lu\n",
366 // n, data_addr, data_size);
367 VGP_PUSHCC(VgpCacheSimulate);
368 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000369 &n->parent->Dw.m1, &n->parent->Dw.m2);
370 n->parent->Dw.a++;
njn25e49d8e72002-09-23 09:36:25 +0000371 VGP_POPCC(VgpCacheSimulate);
372}
373
nethercote9313ac42004-07-06 21:54:20 +0000374/*------------------------------------------------------------*/
sewardj5155dec2005-10-12 10:09:23 +0000375/*--- Instrumentation types and structures ---*/
376/*------------------------------------------------------------*/
377
378/* Maintain an ordered list of memory events which are outstanding, in
379 the sense that no IR has yet been generated to do the relevant
380 helper calls. The BB is scanned top to bottom and memory events
381 are added to the end of the list, merging with the most recent
382 notified event where possible (Dw immediately following Dr and
383 having the same size and EA can be merged).
384
385 This merging is done so that for architectures which have
386 load-op-store instructions (x86, amd64), the insn is treated as if
387 it makes just one memory reference (a modify), rather than two (a
388 read followed by a write at the same address).
389
390 At various points the list will need to be flushed, that is, IR
391 generated from it. That must happen before any possible exit from
392 the block (the end, or an IRStmt_Exit). Flushing also takes place
393 when there is no space to add a new event.
394
395 If we require the simulation statistics to be up to date with
396 respect to possible memory exceptions, then the list would have to
397 be flushed before each memory reference. That would however lose
398 performance by inhibiting event-merging during flushing.
399
400 Flushing the list consists of walking it start to end and emitting
401 instrumentation IR for each event, in the order in which they
402 appear. It may be possible to emit a single call for two adjacent
403 events in order to reduce the number of helper function calls made.
404 For example, it could well be profitable to handle two adjacent Ir
405 events with a single helper call. */
406
407typedef
408 IRExpr
409 IRAtom;
410
411typedef
sewardj20edebf2005-10-12 10:29:40 +0000412 enum { Event_Ir, Event_Dr, Event_Dw, Event_Dm }
sewardj5155dec2005-10-12 10:09:23 +0000413 EventKind;
414
415typedef
416 struct {
417 EventKind ekind;
418 Int size; /* ALL */
419 Addr64 iaddr; /* ALL. For Dr/Dw/Dm is & of parent insn. */
420 IRAtom* dataEA; /* Dr/Dw/Dm only */ /* IR ATOM ONLY */
421 }
422 Event;
423
424/* Up to this many unnotified events are allowed. Number is
425 arbitrary. Larger numbers allow more event merging to occur, but
426 potentially induce more spilling due to extending live ranges of
427 address temporaries. */
428#define N_EVENTS 16
429
430
431/* A struct which holds all the running state during instrumentation.
432 Mostly to avoid passing loads of parameters everywhere. */
433typedef
434 struct {
435 /* The current outstanding-memory-event list. */
436 Event events[N_EVENTS];
437 Int events_used;
438
njnd3bef4f2005-10-15 17:46:18 +0000439 /* The array of InstrInfo bins for the BB. */
sewardj5155dec2005-10-12 10:09:23 +0000440 BB_info* bbInfo;
441
njnd3bef4f2005-10-15 17:46:18 +0000442 /* Number InstrInfo bins 'used' so far. */
sewardj5155dec2005-10-12 10:09:23 +0000443 Int bbInfo_i;
444
sewardj5155dec2005-10-12 10:09:23 +0000445 /* The output BB being constructed. */
446 IRBB* bbOut;
447 }
448 CgState;
449
450
sewardj5155dec2005-10-12 10:09:23 +0000451/*------------------------------------------------------------*/
452/*--- Instrumentation main ---*/
nethercote9313ac42004-07-06 21:54:20 +0000453/*------------------------------------------------------------*/
454
nethercote564b2b02004-08-07 15:54:53 +0000455static
sewardja3a29a52005-10-12 16:16:03 +0000456BB_info* get_BB_info(IRBB* bbIn, Addr origAddr)
nethercote9313ac42004-07-06 21:54:20 +0000457{
njn4bd67b52005-08-11 00:47:10 +0000458 Int i, n_instrs;
459 IRStmt* st;
460 BB_info* bbInfo;
njnd3bef4f2005-10-15 17:46:18 +0000461
njn6a3009b2005-03-20 00:20:06 +0000462 // Count number of original instrs in BB
463 n_instrs = 0;
464 for (i = 0; i < bbIn->stmts_used; i++) {
465 st = bbIn->stmts[i];
466 if (Ist_IMark == st->tag) n_instrs++;
nethercote9313ac42004-07-06 21:54:20 +0000467 }
468
njnf7d26092005-10-12 16:45:17 +0000469 // Check that we don't have an entry for this BB in the instr-info table.
470 // If this assertion fails, there has been some screwup: some
471 // translations must have been discarded but Cachegrind hasn't discarded
472 // the corresponding entries in the instr-info table.
njnd3bef4f2005-10-15 17:46:18 +0000473 bbInfo = VG_(OSet_Lookup)(instrInfoTable, &origAddr);
sewardja3a29a52005-10-12 16:16:03 +0000474 tl_assert(NULL == bbInfo);
475
njnd3bef4f2005-10-15 17:46:18 +0000476 // BB never translated before (at this address, at least; could have
477 // been unloaded and then reloaded elsewhere in memory)
478 bbInfo = VG_(OSet_AllocNode)(instrInfoTable,
479 sizeof(BB_info) + n_instrs*sizeof(InstrInfo));
480 bbInfo->BB_addr = origAddr;
sewardja3a29a52005-10-12 16:16:03 +0000481 bbInfo->n_instrs = n_instrs;
njnd3bef4f2005-10-15 17:46:18 +0000482 VG_(OSet_Insert)( instrInfoTable, bbInfo );
sewardja3a29a52005-10-12 16:16:03 +0000483 distinct_instrs++;
484
njn6a3009b2005-03-20 00:20:06 +0000485 return bbInfo;
nethercote9313ac42004-07-06 21:54:20 +0000486}
njn6a3009b2005-03-20 00:20:06 +0000487
nethercote9313ac42004-07-06 21:54:20 +0000488
nethercote564b2b02004-08-07 15:54:53 +0000489static
njnd3bef4f2005-10-15 17:46:18 +0000490void init_InstrInfo( InstrInfo* n, Addr instr_addr, Int instr_len )
nethercote9313ac42004-07-06 21:54:20 +0000491{
njnf7d26092005-10-12 16:45:17 +0000492 n->instr_addr = instr_addr;
493 n->instr_len = instr_len;
494 n->parent = get_lineCC(instr_addr);
nethercote9313ac42004-07-06 21:54:20 +0000495}
496
sewardj5155dec2005-10-12 10:09:23 +0000497static void showEvent ( Event* ev )
nethercote9313ac42004-07-06 21:54:20 +0000498{
sewardj5155dec2005-10-12 10:09:23 +0000499 switch (ev->ekind) {
500 case Event_Ir:
501 VG_(printf)("Ir %d 0x%llx\n", ev->size, ev->iaddr);
502 break;
503 case Event_Dr:
504 VG_(printf)("Dr %d 0x%llx EA=", ev->size, ev->iaddr);
505 ppIRExpr(ev->dataEA);
506 VG_(printf)("\n");
507 break;
508 case Event_Dw:
509 VG_(printf)("Dw %d 0x%llx EA=", ev->size, ev->iaddr);
510 ppIRExpr(ev->dataEA);
511 VG_(printf)("\n");
512 break;
513 case Event_Dm:
514 VG_(printf)("Dm %d 0x%llx EA=", ev->size, ev->iaddr);
515 ppIRExpr(ev->dataEA);
516 VG_(printf)("\n");
517 break;
518 default:
519 tl_assert(0);
520 break;
521 }
njn6a3009b2005-03-20 00:20:06 +0000522}
523
njnd3bef4f2005-10-15 17:46:18 +0000524/* Reserve InstrInfo for the first mention of a new insn. */
sewardj5155dec2005-10-12 10:09:23 +0000525
njnd3bef4f2005-10-15 17:46:18 +0000526static InstrInfo* reserve_InstrInfo ( CgState* cgs )
njn6a3009b2005-03-20 00:20:06 +0000527{
njnd3bef4f2005-10-15 17:46:18 +0000528 InstrInfo* i_node;
sewardj5155dec2005-10-12 10:09:23 +0000529 tl_assert(cgs->bbInfo_i >= 0);
530 tl_assert(cgs->bbInfo_i < cgs->bbInfo->n_instrs);
531 i_node = &cgs->bbInfo->instrs[ cgs->bbInfo_i ];
532 cgs->bbInfo_i++;
533 return i_node;
534}
sewardj17a56bf2005-03-21 01:35:02 +0000535
sewardj17a56bf2005-03-21 01:35:02 +0000536
njnd3bef4f2005-10-15 17:46:18 +0000537/* Find the most recently allocated InstrInfo. */
sewardj17a56bf2005-03-21 01:35:02 +0000538
njnd3bef4f2005-10-15 17:46:18 +0000539static InstrInfo* find_most_recent_InstrInfo ( CgState* cgs )
sewardj5155dec2005-10-12 10:09:23 +0000540{
541 tl_assert(cgs->bbInfo_i >= 0);
542 tl_assert(cgs->bbInfo_i <= cgs->bbInfo->n_instrs);
543 if (cgs->bbInfo_i == 0)
544 return NULL;
545 else
546 return &cgs->bbInfo->instrs[ cgs->bbInfo_i - 1 ];
547}
njn016712a2005-04-04 02:52:16 +0000548
njn6a3009b2005-03-20 00:20:06 +0000549
sewardj5155dec2005-10-12 10:09:23 +0000550/* Generate code for all outstanding memory events, and mark the queue
551 empty. Code is generated into cgs->bbOut, and this activity
552 'consumes' slots in cgs->bbInfo. */
njn6a3009b2005-03-20 00:20:06 +0000553
sewardj5155dec2005-10-12 10:09:23 +0000554static void flushEvents ( CgState* cgs )
555{
njnd3bef4f2005-10-15 17:46:18 +0000556 Int i, regparms;
557 Char* helperName;
558 void* helperAddr;
559 IRExpr** argv;
560 IRExpr* i_node_expr;
561 IRExpr* i_node2_expr;
562 IRExpr* i_node3_expr;
563 IRDirty* di;
564 InstrInfo* i_node;
565 InstrInfo* i_node2;
566 InstrInfo* i_node3;
njn6a3009b2005-03-20 00:20:06 +0000567
sewardj5155dec2005-10-12 10:09:23 +0000568 i = 0;
569 while (i < cgs->events_used) {
njn6a3009b2005-03-20 00:20:06 +0000570
sewardj5155dec2005-10-12 10:09:23 +0000571 helperName = NULL;
572 helperAddr = NULL;
573 argv = NULL;
574 regparms = 0;
575
576 /* generate IR to notify event i and possibly the ones
577 immediately following it. */
578 tl_assert(i >= 0 && i < cgs->events_used);
579 if (DEBUG_CG) {
580 VG_(printf)(" flush ");
581 showEvent( &cgs->events[i] );
njn4f9c9342002-04-29 16:03:24 +0000582 }
sewardj5155dec2005-10-12 10:09:23 +0000583
njnd3bef4f2005-10-15 17:46:18 +0000584 /* For any event we find the relevant InstrInfo. The following
sewardj5155dec2005-10-12 10:09:23 +0000585 assumes that Event_Ir is the first event to refer to any
586 specific insn, and so a new entry in the cgs->bbInfo->instrs
587 is allocated. All other events (Dr,Dw,Dm) must refer to the
588 most recently encountered IMark and so we use the
589 most-recently allocated instrs[] entry, which must exist. */
590
591 if (cgs->events[i].ekind == Event_Ir) {
njnd3bef4f2005-10-15 17:46:18 +0000592 /* allocate an InstrInfo and fill in its addr/size. */
593 i_node = reserve_InstrInfo( cgs );
sewardj5155dec2005-10-12 10:09:23 +0000594 tl_assert(i_node);
njnd3bef4f2005-10-15 17:46:18 +0000595 init_InstrInfo( i_node,
596 (Addr)cgs->events[i].iaddr, /* i addr */
597 cgs->events[i].size /* i size */);
sewardj5155dec2005-10-12 10:09:23 +0000598 } else {
599 /* use the most-recently allocated i_node but don't mess with
600 its internals */
njnd3bef4f2005-10-15 17:46:18 +0000601 i_node = find_most_recent_InstrInfo( cgs );
sewardj5155dec2005-10-12 10:09:23 +0000602 /* it must actually exist */
603 tl_assert(i_node);
604 /* it must match the declared parent instruction of this
605 event. */
606 tl_assert(i_node->instr_addr == cgs->events[i].iaddr);
607 }
608
609 i_node_expr = mkIRExpr_HWord( (HWord)i_node );
610
611 /* Decide on helper fn to call and args to pass it, and advance
612 i appropriately. */
613 switch (cgs->events[i].ekind) {
614 case Event_Ir:
615 /* Merge with a following Dr/Dm if it is from this insn. */
616 if (i < cgs->events_used-1
617 && cgs->events[i+1].iaddr == cgs->events[i].iaddr
618 && (cgs->events[i+1].ekind == Event_Dr
619 || cgs->events[i+1].ekind == Event_Dm)) {
620 helperName = "log_1I_1Dr_cache_access";
621 helperAddr = &log_1I_1Dr_cache_access;
622 argv = mkIRExprVec_3( i_node_expr,
623 cgs->events[i+1].dataEA,
624 mkIRExpr_HWord( cgs->events[i+1].size ) );
625 regparms = 3;
626 i += 2;
627 }
628 /* Merge with a following Dw if it is from this insn. */
629 else
630 if (i < cgs->events_used-1
631 && cgs->events[i+1].iaddr == cgs->events[i].iaddr
632 && cgs->events[i+1].ekind == Event_Dw) {
633 helperName = "log_1I_1Dw_cache_access";
634 helperAddr = &log_1I_1Dw_cache_access;
635 argv = mkIRExprVec_3( i_node_expr,
636 cgs->events[i+1].dataEA,
637 mkIRExpr_HWord( cgs->events[i+1].size ) );
638 regparms = 3;
639 i += 2;
640 }
641 /* Merge with two following Irs if possible. */
642 else
643 if (i < cgs->events_used-2
644 && cgs->events[i+1].ekind == Event_Ir
645 && cgs->events[i+2].ekind == Event_Ir) {
646 helperName = "log_3I_0D_cache_access";
647 helperAddr = &log_3I_0D_cache_access;
648
njnd3bef4f2005-10-15 17:46:18 +0000649 i_node2 = reserve_InstrInfo( cgs );
sewardj5155dec2005-10-12 10:09:23 +0000650 tl_assert(i_node2);
njnd3bef4f2005-10-15 17:46:18 +0000651 init_InstrInfo( i_node2,
652 (Addr)cgs->events[i+1].iaddr, /* i addr */
653 cgs->events[i+1].size /* i size */);
sewardj5155dec2005-10-12 10:09:23 +0000654 i_node2_expr = mkIRExpr_HWord( (HWord)i_node2 );
655
njnd3bef4f2005-10-15 17:46:18 +0000656 i_node3 = reserve_InstrInfo( cgs );
sewardj5155dec2005-10-12 10:09:23 +0000657 tl_assert(i_node3);
njnd3bef4f2005-10-15 17:46:18 +0000658 init_InstrInfo( i_node3,
659 (Addr)cgs->events[i+2].iaddr, /* i addr */
660 cgs->events[i+2].size /* i size */);
sewardj5155dec2005-10-12 10:09:23 +0000661 i_node3_expr = mkIRExpr_HWord( (HWord)i_node3 );
662
663 argv = mkIRExprVec_3( i_node_expr, i_node2_expr, i_node3_expr );
664 regparms = 3;
665 i += 3;
666 }
667 /* Merge with a following Ir if possible. */
668 else
669 if (i < cgs->events_used-1
670 && cgs->events[i+1].ekind == Event_Ir) {
671 helperName = "log_2I_0D_cache_access";
672 helperAddr = &log_2I_0D_cache_access;
njnd3bef4f2005-10-15 17:46:18 +0000673 i_node2 = reserve_InstrInfo( cgs );
sewardj5155dec2005-10-12 10:09:23 +0000674 tl_assert(i_node2);
njnd3bef4f2005-10-15 17:46:18 +0000675 init_InstrInfo( i_node2,
676 (Addr)cgs->events[i+1].iaddr, /* i addr */
677 cgs->events[i+1].size /* i size */);
sewardj5155dec2005-10-12 10:09:23 +0000678 i_node2_expr = mkIRExpr_HWord( (HWord)i_node2 );
679 argv = mkIRExprVec_2( i_node_expr, i_node2_expr );
680 regparms = 2;
681 i += 2;
682 }
683 /* No merging possible; emit as-is. */
684 else {
685 helperName = "log_1I_0D_cache_access";
686 helperAddr = &log_1I_0D_cache_access;
687 argv = mkIRExprVec_1( i_node_expr );
688 regparms = 1;
689 i++;
690 }
691 break;
692 case Event_Dr:
693 case Event_Dm:
694 helperName = "log_0I_1Dr_cache_access";
695 helperAddr = &log_0I_1Dr_cache_access;
696 argv = mkIRExprVec_3( i_node_expr,
697 cgs->events[i].dataEA,
698 mkIRExpr_HWord( cgs->events[i].size ) );
699 regparms = 3;
700 i++;
701 break;
702 case Event_Dw:
703 helperName = "log_0I_1Dw_cache_access";
704 helperAddr = &log_0I_1Dw_cache_access;
705 argv = mkIRExprVec_3( i_node_expr,
706 cgs->events[i].dataEA,
707 mkIRExpr_HWord( cgs->events[i].size ) );
708 regparms = 3;
709 i++;
710 break;
711 default:
712 tl_assert(0);
713 }
714
715 /* Add the helper. */
716 tl_assert(helperName);
717 tl_assert(helperAddr);
718 tl_assert(argv);
719 di = unsafeIRDirty_0_N( regparms, helperName, helperAddr, argv);
720 addStmtToIRBB( cgs->bbOut, IRStmt_Dirty(di) );
njn4f9c9342002-04-29 16:03:24 +0000721 }
722
sewardj5155dec2005-10-12 10:09:23 +0000723 cgs->events_used = 0;
njn4f9c9342002-04-29 16:03:24 +0000724}
njn14d01ce2004-11-26 11:30:14 +0000725
sewardj5155dec2005-10-12 10:09:23 +0000726
727static void addEvent_Ir ( CgState* cgs, Int size, Addr64 iaddr )
728{
729 Event* evt;
730 tl_assert(size >= 0 && size <= MIN_LINE_SIZE);
731 if (cgs->events_used == N_EVENTS)
732 flushEvents(cgs);
733 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
734 /* If vex fails to decode an insn, the size will be zero, but that
735 can't really be true -- the cpu couldn't have determined the
736 insn was undecodable without looking at it. Hence: */
737 if (size == 0)
738 size = 1;
739 evt = &cgs->events[cgs->events_used];
740 evt->ekind = Event_Ir;
741 evt->size = size;
742 evt->iaddr = iaddr;
743 evt->dataEA = NULL; /*paranoia*/
744 cgs->events_used++;
745}
746
747static void addEvent_Dr ( CgState* cgs, Int size, Addr64 iaddr, IRAtom* ea )
748{
749 Event* evt;
750 tl_assert(isIRAtom(ea));
751 tl_assert(size >= 1 && size <= MIN_LINE_SIZE);
752 if (cgs->events_used == N_EVENTS)
753 flushEvents(cgs);
754 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
755 evt = &cgs->events[cgs->events_used];
756 evt->ekind = Event_Dr;
757 evt->size = size;
758 evt->iaddr = iaddr;
759 evt->dataEA = ea;
760 cgs->events_used++;
761}
762
763static void addEvent_Dw ( CgState* cgs, Int size, Addr64 iaddr, IRAtom* ea )
764{
765 tl_assert(isIRAtom(ea));
766 tl_assert(size >= 1 && size <= MIN_LINE_SIZE);
767
768 /* Is it possible to merge this write into an immediately preceding
769 read? */
770 if (cgs->events_used > 0
771 && cgs->events[cgs->events_used-1].ekind == Event_Dr
772 && cgs->events[cgs->events_used-1].size == size
773 && cgs->events[cgs->events_used-1].iaddr == iaddr
774 && eqIRAtom(cgs->events[cgs->events_used-1].dataEA, ea)) {
775 cgs->events[cgs->events_used-1].ekind = Event_Dm;
776 return;
777 }
778
779 /* No. Add as normal. */
780 if (cgs->events_used == N_EVENTS)
781 flushEvents(cgs);
782 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
783 cgs->events[cgs->events_used].ekind = Event_Dw;
784 cgs->events[cgs->events_used].size = size;
785 cgs->events[cgs->events_used].iaddr = iaddr;
786 cgs->events[cgs->events_used].dataEA = ea;
787 cgs->events_used++;
788}
789
790////////////////////////////////////////////////////////////
791
792
njn51d827b2005-05-09 01:02:08 +0000793static IRBB* cg_instrument ( IRBB* bbIn, VexGuestLayout* layout,
794 IRType gWordTy, IRType hWordTy )
njn14d01ce2004-11-26 11:30:14 +0000795{
sewardj5155dec2005-10-12 10:09:23 +0000796 Int i;
797 IRStmt* st;
798 Addr64 cia; /* address of current insn */
799 CgState cgs;
800 IRTypeEnv* tyenv = bbIn->tyenv;
801
njn6a3009b2005-03-20 00:20:06 +0000802
sewardjd54babf2005-03-21 00:55:49 +0000803 if (gWordTy != hWordTy) {
804 /* We don't currently support this case. */
805 VG_(tool_panic)("host/guest word size mismatch");
806 }
807
njn6a3009b2005-03-20 00:20:06 +0000808 /* Set up BB */
sewardj5155dec2005-10-12 10:09:23 +0000809 cgs.bbOut = emptyIRBB();
810 cgs.bbOut->tyenv = dopyIRTypeEnv(tyenv);
njn6a3009b2005-03-20 00:20:06 +0000811
sewardj5155dec2005-10-12 10:09:23 +0000812 // Get the first statement, and initial cia from it
njn6a3009b2005-03-20 00:20:06 +0000813 i = 0;
814 tl_assert(bbIn->stmts_used > 0);
815 st = bbIn->stmts[0];
816 tl_assert(Ist_IMark == st->tag);
sewardj5155dec2005-10-12 10:09:23 +0000817 cia = st->Ist.IMark.addr;
njn6a3009b2005-03-20 00:20:06 +0000818
sewardj5155dec2005-10-12 10:09:23 +0000819 // Set up running state and get block info
820 cgs.events_used = 0;
sewardja3a29a52005-10-12 16:16:03 +0000821 cgs.bbInfo = get_BB_info(bbIn, (Addr)cia);
sewardj5155dec2005-10-12 10:09:23 +0000822 cgs.bbInfo_i = 0;
njn6a3009b2005-03-20 00:20:06 +0000823
sewardj5155dec2005-10-12 10:09:23 +0000824 if (DEBUG_CG)
825 VG_(printf)("\n\n---------- cg_instrument ----------\n");
njn6a3009b2005-03-20 00:20:06 +0000826
sewardj5155dec2005-10-12 10:09:23 +0000827 // Traverse the block, adding events and flushing as necessary.
828 for (i = 0; i < bbIn->stmts_used; i++) {
njn6a3009b2005-03-20 00:20:06 +0000829
sewardj5155dec2005-10-12 10:09:23 +0000830 st = bbIn->stmts[i];
831 tl_assert(isFlatIRStmt(st));
njnb3507ea2005-08-02 23:07:02 +0000832
sewardj5155dec2005-10-12 10:09:23 +0000833 switch (st->tag) {
834 case Ist_NoOp:
835 case Ist_AbiHint:
836 case Ist_Put:
837 case Ist_PutI:
838 case Ist_MFence:
839 break;
njn20677cc2005-08-12 23:47:51 +0000840
sewardj5155dec2005-10-12 10:09:23 +0000841 case Ist_IMark:
842 cia = st->Ist.IMark.addr;
843 addEvent_Ir( &cgs, st->Ist.IMark.len, cia );
844 break;
845
846 case Ist_Tmp: {
847 IRExpr* data = st->Ist.Tmp.data;
848 if (data->tag == Iex_Load) {
849 IRExpr* aexpr = data->Iex.Load.addr;
850 tl_assert( isIRAtom(aexpr) );
851 // Note also, endianness info is ignored. I guess
852 // that's not interesting.
853 addEvent_Dr( &cgs, sizeofIRType(data->Iex.Load.ty),
854 cia, aexpr );
855 }
856 break;
njnb3507ea2005-08-02 23:07:02 +0000857 }
858
sewardj5155dec2005-10-12 10:09:23 +0000859 case Ist_Store: {
860 IRExpr* data = st->Ist.Store.data;
861 IRExpr* aexpr = st->Ist.Store.addr;
862 tl_assert( isIRAtom(aexpr) );
863 addEvent_Dw( &cgs,
864 sizeofIRType(typeOfIRExpr(tyenv, data)),
865 cia, aexpr );
866 break;
867 }
njnb3507ea2005-08-02 23:07:02 +0000868
sewardj5155dec2005-10-12 10:09:23 +0000869 case Ist_Dirty: {
870 Int dataSize;
871 IRDirty* d = st->Ist.Dirty.details;
872 if (d->mFx != Ifx_None) {
873 /* This dirty helper accesses memory. Collect the
874 details. */
875 tl_assert(d->mAddr != NULL);
876 tl_assert(d->mSize != 0);
877 dataSize = d->mSize;
878 // Large (eg. 28B, 108B, 512B on x86) data-sized
879 // instructions will be done inaccurately, but they're
880 // very rare and this avoids errors from hitting more
881 // than two cache lines in the simulation.
882 if (dataSize > MIN_LINE_SIZE)
883 dataSize = MIN_LINE_SIZE;
884 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
885 addEvent_Dr( &cgs, dataSize, cia, d->mAddr );
886 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
887 addEvent_Dw( &cgs, dataSize, cia, d->mAddr );
888 } else {
889 tl_assert(d->mAddr == NULL);
890 tl_assert(d->mSize == 0);
891 }
892 break;
893 }
njn6a3009b2005-03-20 00:20:06 +0000894
sewardj5155dec2005-10-12 10:09:23 +0000895 case Ist_Exit:
896 /* We may never reach the next statement, so need to flush
897 all outstanding transactions now. */
898 flushEvents( &cgs );
899 break;
900
901 default:
902 tl_assert(0);
903 break;
njnb3507ea2005-08-02 23:07:02 +0000904 }
njn6a3009b2005-03-20 00:20:06 +0000905
sewardj5155dec2005-10-12 10:09:23 +0000906 /* Copy the original statement */
907 addStmtToIRBB( cgs.bbOut, st );
njn6a3009b2005-03-20 00:20:06 +0000908
sewardj5155dec2005-10-12 10:09:23 +0000909 if (DEBUG_CG) {
910 ppIRStmt(st);
911 VG_(printf)("\n");
912 }
913 }
914
915 /* At the end of the bb. Flush outstandings. */
916 tl_assert(isIRAtom(bbIn->next));
917 flushEvents( &cgs );
918
919 /* copy where-next stuff. */
920 cgs.bbOut->next = dopyIRExpr(bbIn->next);
921 cgs.bbOut->jumpkind = bbIn->jumpkind;
922
923 /* done. stay sane ... */
924 tl_assert(cgs.bbInfo_i == cgs.bbInfo->n_instrs);
925
926 if (DEBUG_CG) {
927 VG_(printf)( "goto {");
928 ppIRJumpKind(bbIn->jumpkind);
929 VG_(printf)( "} ");
930 ppIRExpr( bbIn->next );
931 VG_(printf)( "}\n");
932 }
933
934 return cgs.bbOut;
njn14d01ce2004-11-26 11:30:14 +0000935}
njn4f9c9342002-04-29 16:03:24 +0000936
937/*------------------------------------------------------------*/
nethercoteb35a8b92004-09-11 16:45:27 +0000938/*--- Cache configuration ---*/
njn4f9c9342002-04-29 16:03:24 +0000939/*------------------------------------------------------------*/
940
sewardjb5f6f512005-03-10 23:59:00 +0000941#define UNDEFINED_CACHE { -1, -1, -1 }
njn25e49d8e72002-09-23 09:36:25 +0000942
943static cache_t clo_I1_cache = UNDEFINED_CACHE;
944static cache_t clo_D1_cache = UNDEFINED_CACHE;
945static cache_t clo_L2_cache = UNDEFINED_CACHE;
946
njn7cf0bd32002-06-08 13:36:03 +0000947/* Checks cache config is ok; makes it so if not. */
sewardj07133bf2002-06-13 10:25:56 +0000948static
njna1d1a642004-11-26 18:36:02 +0000949void check_cache(cache_t* cache, Char *name)
njn7cf0bd32002-06-08 13:36:03 +0000950{
951 /* First check they're all powers of two */
sewardj07133bf2002-06-13 10:25:56 +0000952 if (-1 == VG_(log2)(cache->size)) {
njn7cf0bd32002-06-08 13:36:03 +0000953 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000954 "error: %s size of %dB not a power of two; aborting.",
955 name, cache->size);
956 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000957 }
958
sewardj07133bf2002-06-13 10:25:56 +0000959 if (-1 == VG_(log2)(cache->assoc)) {
njn7cf0bd32002-06-08 13:36:03 +0000960 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000961 "error: %s associativity of %d not a power of two; aborting.",
962 name, cache->assoc);
963 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000964 }
965
sewardj07133bf2002-06-13 10:25:56 +0000966 if (-1 == VG_(log2)(cache->line_size)) {
njn7cf0bd32002-06-08 13:36:03 +0000967 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000968 "error: %s line size of %dB not a power of two; aborting.",
969 name, cache->line_size);
970 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000971 }
972
njn6a3009b2005-03-20 00:20:06 +0000973 // Then check line size >= 16 -- any smaller and a single instruction could
974 // straddle three cache lines, which breaks a simulation assertion and is
975 // stupid anyway.
njn7cf0bd32002-06-08 13:36:03 +0000976 if (cache->line_size < MIN_LINE_SIZE) {
977 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000978 "error: %s line size of %dB too small; aborting.",
979 name, cache->line_size);
980 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000981 }
982
983 /* Then check cache size > line size (causes seg faults if not). */
984 if (cache->size <= cache->line_size) {
985 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000986 "error: %s cache size of %dB <= line size of %dB; aborting.",
987 name, cache->size, cache->line_size);
988 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000989 }
990
991 /* Then check assoc <= (size / line size) (seg faults otherwise). */
992 if (cache->assoc > (cache->size / cache->line_size)) {
993 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000994 "warning: %s associativity > (size / line size); aborting.", name);
995 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000996 }
997}
998
sewardj07133bf2002-06-13 10:25:56 +0000999static
nethercoteb35a8b92004-09-11 16:45:27 +00001000void configure_caches(cache_t* I1c, cache_t* D1c, cache_t* L2c)
njn7cf0bd32002-06-08 13:36:03 +00001001{
nethercote9313ac42004-07-06 21:54:20 +00001002#define DEFINED(L) (-1 != L.size || -1 != L.assoc || -1 != L.line_size)
1003
nethercoteb35a8b92004-09-11 16:45:27 +00001004 Int n_clos = 0;
nethercote9313ac42004-07-06 21:54:20 +00001005
nethercoteb35a8b92004-09-11 16:45:27 +00001006 // Count how many were defined on the command line.
1007 if (DEFINED(clo_I1_cache)) { n_clos++; }
1008 if (DEFINED(clo_D1_cache)) { n_clos++; }
1009 if (DEFINED(clo_L2_cache)) { n_clos++; }
njn7cf0bd32002-06-08 13:36:03 +00001010
njna1d1a642004-11-26 18:36:02 +00001011 // Set the cache config (using auto-detection, if supported by the
1012 // architecture)
njnaf839f52005-06-23 03:27:57 +00001013 VG_(configure_caches)( I1c, D1c, L2c, (3 == n_clos) );
sewardjb1a77a42002-07-13 13:31:20 +00001014
nethercote9313ac42004-07-06 21:54:20 +00001015 // Then replace with any defined on the command line.
nethercoteb35a8b92004-09-11 16:45:27 +00001016 if (DEFINED(clo_I1_cache)) { *I1c = clo_I1_cache; }
1017 if (DEFINED(clo_D1_cache)) { *D1c = clo_D1_cache; }
1018 if (DEFINED(clo_L2_cache)) { *L2c = clo_L2_cache; }
njn7cf0bd32002-06-08 13:36:03 +00001019
nethercote9313ac42004-07-06 21:54:20 +00001020 // Then check values and fix if not acceptable.
njna1d1a642004-11-26 18:36:02 +00001021 check_cache(I1c, "I1");
1022 check_cache(D1c, "D1");
1023 check_cache(L2c, "L2");
njn7cf0bd32002-06-08 13:36:03 +00001024
1025 if (VG_(clo_verbosity) > 1) {
1026 VG_(message)(Vg_UserMsg, "Cache configuration used:");
1027 VG_(message)(Vg_UserMsg, " I1: %dB, %d-way, %dB lines",
1028 I1c->size, I1c->assoc, I1c->line_size);
1029 VG_(message)(Vg_UserMsg, " D1: %dB, %d-way, %dB lines",
1030 D1c->size, D1c->assoc, D1c->line_size);
1031 VG_(message)(Vg_UserMsg, " L2: %dB, %d-way, %dB lines",
1032 L2c->size, L2c->assoc, L2c->line_size);
1033 }
nethercote9313ac42004-07-06 21:54:20 +00001034#undef CMD_LINE_DEFINED
njn7cf0bd32002-06-08 13:36:03 +00001035}
1036
njn4f9c9342002-04-29 16:03:24 +00001037/*------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +00001038/*--- cg_fini() and related function ---*/
njn4f9c9342002-04-29 16:03:24 +00001039/*------------------------------------------------------------*/
1040
nethercote9313ac42004-07-06 21:54:20 +00001041// Total reads/writes/misses. Calculated during CC traversal at the end.
1042// All auto-zeroed.
1043static CC Ir_total;
1044static CC Dr_total;
1045static CC Dw_total;
1046
1047static Char* cachegrind_out_file;
1048
nethercote9313ac42004-07-06 21:54:20 +00001049static void fprint_CC_table_and_calc_totals(void)
1050{
njnd3bef4f2005-10-15 17:46:18 +00001051 Int i, fd;
sewardj92645592005-07-23 09:18:34 +00001052 SysRes sres;
njnd3bef4f2005-10-15 17:46:18 +00001053 Char buf[512], *currFile = NULL, *currFn = NULL;
1054 LineCC* lineCC;
njn4f9c9342002-04-29 16:03:24 +00001055
njn25e49d8e72002-09-23 09:36:25 +00001056 VGP_PUSHCC(VgpCacheResults);
njn13f02932003-04-30 20:23:58 +00001057
sewardj92645592005-07-23 09:18:34 +00001058 sres = VG_(open)(cachegrind_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
1059 VKI_S_IRUSR|VKI_S_IWUSR);
1060 if (sres.isError) {
nethercote9313ac42004-07-06 21:54:20 +00001061 // If the file can't be opened for whatever reason (conflict
1062 // between multiple cachegrinded processes?), give up now.
njnee0e6a32005-04-24 00:21:01 +00001063 VG_(message)(Vg_UserMsg,
njn02bc4b82005-05-15 17:28:26 +00001064 "error: can't open cache simulation output file '%s'",
njnee0e6a32005-04-24 00:21:01 +00001065 cachegrind_out_file );
1066 VG_(message)(Vg_UserMsg,
1067 " ... so simulation results will be missing.");
sewardj0744b6c2002-12-11 00:45:42 +00001068 return;
sewardj92645592005-07-23 09:18:34 +00001069 } else {
1070 fd = sres.val;
sewardj0744b6c2002-12-11 00:45:42 +00001071 }
njn4f9c9342002-04-29 16:03:24 +00001072
nethercote9313ac42004-07-06 21:54:20 +00001073 // "desc:" lines (giving I1/D1/L2 cache configuration). The spaces after
1074 // the 2nd colon makes cg_annotate's output look nicer.
1075 VG_(sprintf)(buf, "desc: I1 cache: %s\n"
1076 "desc: D1 cache: %s\n"
1077 "desc: L2 cache: %s\n",
1078 I1.desc_line, D1.desc_line, L2.desc_line);
njn7cf0bd32002-06-08 13:36:03 +00001079 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njn4f9c9342002-04-29 16:03:24 +00001080
nethercote9313ac42004-07-06 21:54:20 +00001081 // "cmd:" line
njn4f9c9342002-04-29 16:03:24 +00001082 VG_(strcpy)(buf, "cmd:");
1083 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
sewardj45f4e7c2005-09-27 19:20:21 +00001084 if (VG_(args_the_exename)) {
1085 VG_(write)(fd, " ", 1);
1086 VG_(write)(fd, VG_(args_the_exename),
1087 VG_(strlen)( VG_(args_the_exename) ));
1088 }
1089 for (i = 0; i < VG_(args_for_client).used; i++) {
1090 if (VG_(args_for_client).strs[i]) {
1091 VG_(write)(fd, " ", 1);
1092 VG_(write)(fd, VG_(args_for_client).strs[i],
1093 VG_(strlen)(VG_(args_for_client).strs[i]));
1094 }
njn4f9c9342002-04-29 16:03:24 +00001095 }
nethercote9313ac42004-07-06 21:54:20 +00001096 // "events:" line
njn4f9c9342002-04-29 16:03:24 +00001097 VG_(sprintf)(buf, "\nevents: Ir I1mr I2mr Dr D1mr D2mr Dw D1mw D2mw\n");
1098 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1099
njnd3bef4f2005-10-15 17:46:18 +00001100 // Traverse every lineCC
1101 VG_(OSet_ResetIter)(CC_table);
1102 while ( (lineCC = VG_(OSet_Next)(CC_table)) ) {
1103 // If we've hit a new file, print a "fl=" line. Note that because
1104 // each string is stored exactly once in the string table, we can use
1105 // pointer comparison rather than strcmp() to test for equality, which
1106 // is good because most of the time the comparisons are equal and so
1107 // the whole strings would have to be traversed.
1108 if ( lineCC->loc.file != currFile ) {
1109 currFile = lineCC->loc.file;
1110 VG_(sprintf)(buf, "fl=%s\n", currFile);
njn4f9c9342002-04-29 16:03:24 +00001111 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njnd3bef4f2005-10-15 17:46:18 +00001112 distinct_files++;
njn4f9c9342002-04-29 16:03:24 +00001113 }
njnd3bef4f2005-10-15 17:46:18 +00001114 // If we've hit a new function, print a "fn=" line.
1115 if ( lineCC->loc.fn != currFn ) {
1116 currFn = lineCC->loc.fn;
1117 VG_(sprintf)(buf, "fn=%s\n", currFn);
1118 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1119 distinct_fns++;
1120 }
1121
1122 // Print the LineCC
1123 VG_(sprintf)(buf, "%u %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
1124 lineCC->loc.line,
1125 lineCC->Ir.a, lineCC->Ir.m1, lineCC->Ir.m2,
1126 lineCC->Dr.a, lineCC->Dr.m1, lineCC->Dr.m2,
1127 lineCC->Dw.a, lineCC->Dw.m1, lineCC->Dw.m2);
1128 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1129
1130 // Update summary stats
1131 Ir_total.a += lineCC->Ir.a;
1132 Ir_total.m1 += lineCC->Ir.m1;
1133 Ir_total.m2 += lineCC->Ir.m2;
1134 Dr_total.a += lineCC->Dr.a;
1135 Dr_total.m1 += lineCC->Dr.m1;
1136 Dr_total.m2 += lineCC->Dr.m2;
1137 Dw_total.a += lineCC->Dw.a;
1138 Dw_total.m1 += lineCC->Dw.m1;
1139 Dw_total.m2 += lineCC->Dw.m2;
1140
1141 distinct_lines++;
njn4f9c9342002-04-29 16:03:24 +00001142 }
1143
nethercote9313ac42004-07-06 21:54:20 +00001144 // Summary stats must come after rest of table, since we calculate them
1145 // during traversal. */
njn4f9c9342002-04-29 16:03:24 +00001146 VG_(sprintf)(buf, "summary: "
nethercote9313ac42004-07-06 21:54:20 +00001147 "%llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
njn4f9c9342002-04-29 16:03:24 +00001148 Ir_total.a, Ir_total.m1, Ir_total.m2,
1149 Dr_total.a, Dr_total.m1, Dr_total.m2,
1150 Dw_total.a, Dw_total.m1, Dw_total.m2);
1151 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1152 VG_(close)(fd);
1153}
1154
njn607adfc2003-09-30 14:15:44 +00001155static UInt ULong_width(ULong n)
njn4f9c9342002-04-29 16:03:24 +00001156{
njn607adfc2003-09-30 14:15:44 +00001157 UInt w = 0;
1158 while (n > 0) {
1159 n = n / 10;
1160 w++;
njn4f9c9342002-04-29 16:03:24 +00001161 }
njn607adfc2003-09-30 14:15:44 +00001162 return w + (w-1)/3; // add space for commas
njn4f9c9342002-04-29 16:03:24 +00001163}
1164
njn51d827b2005-05-09 01:02:08 +00001165static void cg_fini(Int exitcode)
njn4f9c9342002-04-29 16:03:24 +00001166{
njn0103de52005-10-10 16:49:01 +00001167 static Char buf1[128], buf2[128], buf3[128], fmt [128];
njn607adfc2003-09-30 14:15:44 +00001168
njn4f9c9342002-04-29 16:03:24 +00001169 CC D_total;
njn1d021fa2002-05-02 13:56:34 +00001170 ULong L2_total_m, L2_total_mr, L2_total_mw,
1171 L2_total, L2_total_r, L2_total_w;
njn4f9c9342002-04-29 16:03:24 +00001172 Int l1, l2, l3;
1173 Int p;
1174
nethercote9313ac42004-07-06 21:54:20 +00001175 fprint_CC_table_and_calc_totals();
njn4f9c9342002-04-29 16:03:24 +00001176
njn7cf0bd32002-06-08 13:36:03 +00001177 if (VG_(clo_verbosity) == 0)
1178 return;
1179
njn4f9c9342002-04-29 16:03:24 +00001180 /* I cache results. Use the I_refs value to determine the first column
1181 * width. */
njn607adfc2003-09-30 14:15:44 +00001182 l1 = ULong_width(Ir_total.a);
1183 l2 = ULong_width(Dr_total.a);
1184 l3 = ULong_width(Dw_total.a);
njn4f9c9342002-04-29 16:03:24 +00001185
njn607adfc2003-09-30 14:15:44 +00001186 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001187 VG_(sprintf)(fmt, "%%s %%,%dllu", l1);
njnd3bef4f2005-10-15 17:46:18 +00001188
njn607adfc2003-09-30 14:15:44 +00001189 VG_(message)(Vg_UserMsg, fmt, "I refs: ", Ir_total.a);
1190 VG_(message)(Vg_UserMsg, fmt, "I1 misses: ", Ir_total.m1);
1191 VG_(message)(Vg_UserMsg, fmt, "L2i misses: ", Ir_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001192
1193 p = 100;
1194
njn25e49d8e72002-09-23 09:36:25 +00001195 if (0 == Ir_total.a) Ir_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001196 VG_(percentify)(Ir_total.m1, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001197 VG_(message)(Vg_UserMsg, "I1 miss rate: %s", buf1);
njnd3bef4f2005-10-15 17:46:18 +00001198
njn856c54e2005-06-26 18:43:40 +00001199 VG_(percentify)(Ir_total.m2, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001200 VG_(message)(Vg_UserMsg, "L2i miss rate: %s", buf1);
1201 VG_(message)(Vg_UserMsg, "");
1202
1203 /* D cache results. Use the D_refs.rd and D_refs.wr values to determine the
1204 * width of columns 2 & 3. */
1205 D_total.a = Dr_total.a + Dw_total.a;
1206 D_total.m1 = Dr_total.m1 + Dw_total.m1;
1207 D_total.m2 = Dr_total.m2 + Dw_total.m2;
njnd3bef4f2005-10-15 17:46:18 +00001208
njn607adfc2003-09-30 14:15:44 +00001209 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001210 VG_(sprintf)(fmt, "%%s %%,%dllu (%%,%dllu rd + %%,%dllu wr)", l1, l2, l3);
njn4f9c9342002-04-29 16:03:24 +00001211
njn607adfc2003-09-30 14:15:44 +00001212 VG_(message)(Vg_UserMsg, fmt, "D refs: ",
1213 D_total.a, Dr_total.a, Dw_total.a);
1214 VG_(message)(Vg_UserMsg, fmt, "D1 misses: ",
1215 D_total.m1, Dr_total.m1, Dw_total.m1);
1216 VG_(message)(Vg_UserMsg, fmt, "L2d misses: ",
1217 D_total.m2, Dr_total.m2, Dw_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001218
1219 p = 10;
njnd3bef4f2005-10-15 17:46:18 +00001220
njn25e49d8e72002-09-23 09:36:25 +00001221 if (0 == D_total.a) D_total.a = 1;
1222 if (0 == Dr_total.a) Dr_total.a = 1;
1223 if (0 == Dw_total.a) Dw_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001224 VG_(percentify)( D_total.m1, D_total.a, 1, l1+1, buf1);
1225 VG_(percentify)(Dr_total.m1, Dr_total.a, 1, l2+1, buf2);
1226 VG_(percentify)(Dw_total.m1, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001227 VG_(message)(Vg_UserMsg, "D1 miss rate: %s (%s + %s )", buf1, buf2,buf3);
1228
njn856c54e2005-06-26 18:43:40 +00001229 VG_(percentify)( D_total.m2, D_total.a, 1, l1+1, buf1);
1230 VG_(percentify)(Dr_total.m2, Dr_total.a, 1, l2+1, buf2);
1231 VG_(percentify)(Dw_total.m2, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001232 VG_(message)(Vg_UserMsg, "L2d miss rate: %s (%s + %s )", buf1, buf2,buf3);
1233 VG_(message)(Vg_UserMsg, "");
1234
1235 /* L2 overall results */
njn1d021fa2002-05-02 13:56:34 +00001236
1237 L2_total = Dr_total.m1 + Dw_total.m1 + Ir_total.m1;
1238 L2_total_r = Dr_total.m1 + Ir_total.m1;
1239 L2_total_w = Dw_total.m1;
njn607adfc2003-09-30 14:15:44 +00001240 VG_(message)(Vg_UserMsg, fmt, "L2 refs: ",
1241 L2_total, L2_total_r, L2_total_w);
njn1d021fa2002-05-02 13:56:34 +00001242
njn4f9c9342002-04-29 16:03:24 +00001243 L2_total_m = Dr_total.m2 + Dw_total.m2 + Ir_total.m2;
1244 L2_total_mr = Dr_total.m2 + Ir_total.m2;
1245 L2_total_mw = Dw_total.m2;
njn607adfc2003-09-30 14:15:44 +00001246 VG_(message)(Vg_UserMsg, fmt, "L2 misses: ",
1247 L2_total_m, L2_total_mr, L2_total_mw);
njn4f9c9342002-04-29 16:03:24 +00001248
njn856c54e2005-06-26 18:43:40 +00001249 VG_(percentify)(L2_total_m, (Ir_total.a + D_total.a), 1, l1+1, buf1);
1250 VG_(percentify)(L2_total_mr, (Ir_total.a + Dr_total.a), 1, l2+1, buf2);
1251 VG_(percentify)(L2_total_mw, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001252 VG_(message)(Vg_UserMsg, "L2 miss rate: %s (%s + %s )", buf1, buf2,buf3);
njnd3bef4f2005-10-15 17:46:18 +00001253
njn4f9c9342002-04-29 16:03:24 +00001254
nethercote9313ac42004-07-06 21:54:20 +00001255 // Various stats
njn4f9c9342002-04-29 16:03:24 +00001256 if (VG_(clo_verbosity) > 1) {
njnd3bef4f2005-10-15 17:46:18 +00001257 Int debug_lookups = full_debugs + fn_debugs +
1258 file_line_debugs + no_debugs;
1259
njn4f9c9342002-04-29 16:03:24 +00001260 VG_(message)(Vg_DebugMsg, "");
njnd3bef4f2005-10-15 17:46:18 +00001261 VG_(message)(Vg_DebugMsg, "cachegrind: distinct files: %d", distinct_files);
1262 VG_(message)(Vg_DebugMsg, "cachegrind: distinct fns: %d", distinct_fns);
1263 VG_(message)(Vg_DebugMsg, "cachegrind: distinct lines: %d", distinct_lines);
1264 VG_(message)(Vg_DebugMsg, "cachegrind: distinct instrs:%d", distinct_instrs);
1265 VG_(message)(Vg_DebugMsg, "cachegrind: debug lookups : %d", debug_lookups);
1266 VG_(message)(Vg_DebugMsg, "cachegrind: with full info:%3d%% (%d)",
1267 full_debugs * 100 / debug_lookups, full_debugs);
1268 VG_(message)(Vg_DebugMsg, "cachegrind: with file/line info:%3d%% (%d)",
1269 file_line_debugs * 100 / debug_lookups, file_line_debugs);
1270 VG_(message)(Vg_DebugMsg, "cachegrind: with fn name info:%3d%% (%d)",
1271 fn_debugs * 100 / debug_lookups, fn_debugs);
1272 VG_(message)(Vg_DebugMsg, "cachegrind: with zero info:%3d%% (%d)",
1273 no_debugs * 100 / debug_lookups, no_debugs);
1274 VG_(message)(Vg_DebugMsg, "cachegrind: BBs Retranslated: %d",
1275 BB_retranslations);
1276 VG_(message)(Vg_DebugMsg, "cachegrind: string table size: %u",
1277 VG_(OSet_Size)(stringTable));
1278 VG_(message)(Vg_DebugMsg, "cachegrind: CC table size: %u",
1279 VG_(OSet_Size)(CC_table));
1280 VG_(message)(Vg_DebugMsg, "cachegrind: InstrInfo table size: %u",
1281 VG_(OSet_Size)(instrInfoTable));
njn4f9c9342002-04-29 16:03:24 +00001282 }
njn25e49d8e72002-09-23 09:36:25 +00001283 VGP_POPCC(VgpCacheResults);
njn4f9c9342002-04-29 16:03:24 +00001284}
1285
nethercote9313ac42004-07-06 21:54:20 +00001286/*--------------------------------------------------------------------*/
1287/*--- Discarding BB info ---*/
1288/*--------------------------------------------------------------------*/
sewardj18d75132002-05-16 11:06:21 +00001289
sewardja3a29a52005-10-12 16:16:03 +00001290// Called when a translation is removed from the translation cache for
1291// any reason at all: to free up space, because the guest code was
1292// unmapped or modified, or for any arbitrary reason.
sewardj5155dec2005-10-12 10:09:23 +00001293static void cg_discard_basic_block_info ( VexGuestExtents vge )
sewardj18d75132002-05-16 11:06:21 +00001294{
njnd3bef4f2005-10-15 17:46:18 +00001295 BB_info* bbInfo;
njn4294fd42002-06-05 14:41:10 +00001296
sewardj5155dec2005-10-12 10:09:23 +00001297 tl_assert(vge.n_used > 0);
1298
1299 if (DEBUG_CG)
1300 VG_(printf)( "discard_basic_block_info: %p, %llu\n",
1301 (void*)(Addr)vge.base[0], (ULong)vge.len[0]);
njn4294fd42002-06-05 14:41:10 +00001302
nethercote9313ac42004-07-06 21:54:20 +00001303 // Get BB info, remove from table, free BB info. Simple!
njnd3bef4f2005-10-15 17:46:18 +00001304 bbInfo = VG_(OSet_Remove)(instrInfoTable, &(vge.base[0]));
njn6a3009b2005-03-20 00:20:06 +00001305 tl_assert(NULL != bbInfo);
njnd3bef4f2005-10-15 17:46:18 +00001306 VG_(OSet_FreeNode)(instrInfoTable, bbInfo);
sewardj18d75132002-05-16 11:06:21 +00001307}
1308
1309/*--------------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001310/*--- Command line processing ---*/
1311/*--------------------------------------------------------------------*/
1312
njn0103de52005-10-10 16:49:01 +00001313static void parse_cache_opt ( cache_t* cache, Char* opt )
njn25e49d8e72002-09-23 09:36:25 +00001314{
njn0103de52005-10-10 16:49:01 +00001315 Int i = 0, i2, i3;
njn25e49d8e72002-09-23 09:36:25 +00001316
nethercote9313ac42004-07-06 21:54:20 +00001317 // Option argument looks like "65536,2,64".
1318 // Find commas, replace with NULs to make three independent
1319 // strings, then extract numbers, put NULs back. Yuck.
njn25e49d8e72002-09-23 09:36:25 +00001320 while (VG_(isdigit)(opt[i])) i++;
1321 if (',' == opt[i]) {
1322 opt[i++] = '\0';
1323 i2 = i;
1324 } else goto bad;
1325 while (VG_(isdigit)(opt[i])) i++;
1326 if (',' == opt[i]) {
1327 opt[i++] = '\0';
1328 i3 = i;
1329 } else goto bad;
1330 while (VG_(isdigit)(opt[i])) i++;
1331 if ('\0' != opt[i]) goto bad;
1332
nethercote9313ac42004-07-06 21:54:20 +00001333 cache->size = (Int)VG_(atoll)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001334 cache->assoc = (Int)VG_(atoll)(opt + i2);
1335 cache->line_size = (Int)VG_(atoll)(opt + i3);
1336
nethercote9313ac42004-07-06 21:54:20 +00001337 opt[i2-1] = ',';
1338 opt[i3-1] = ',';
njn25e49d8e72002-09-23 09:36:25 +00001339 return;
1340
1341 bad:
nethercote9313ac42004-07-06 21:54:20 +00001342 VG_(bad_option)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001343}
1344
njn51d827b2005-05-09 01:02:08 +00001345static Bool cg_process_cmd_line_option(Char* arg)
njn25e49d8e72002-09-23 09:36:25 +00001346{
nethercote9313ac42004-07-06 21:54:20 +00001347 // 5 is length of "--I1="
njn39c86652003-05-21 10:13:39 +00001348 if (VG_CLO_STREQN(5, arg, "--I1="))
nethercote9313ac42004-07-06 21:54:20 +00001349 parse_cache_opt(&clo_I1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001350 else if (VG_CLO_STREQN(5, arg, "--D1="))
nethercote9313ac42004-07-06 21:54:20 +00001351 parse_cache_opt(&clo_D1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001352 else if (VG_CLO_STREQN(5, arg, "--L2="))
nethercote9313ac42004-07-06 21:54:20 +00001353 parse_cache_opt(&clo_L2_cache, &arg[5]);
njn25e49d8e72002-09-23 09:36:25 +00001354 else
1355 return False;
1356
1357 return True;
1358}
1359
njn51d827b2005-05-09 01:02:08 +00001360static void cg_print_usage(void)
njn25e49d8e72002-09-23 09:36:25 +00001361{
njn3e884182003-04-15 13:03:23 +00001362 VG_(printf)(
njn25e49d8e72002-09-23 09:36:25 +00001363" --I1=<size>,<assoc>,<line_size> set I1 cache manually\n"
1364" --D1=<size>,<assoc>,<line_size> set D1 cache manually\n"
njn3e884182003-04-15 13:03:23 +00001365" --L2=<size>,<assoc>,<line_size> set L2 cache manually\n"
1366 );
1367}
1368
njn51d827b2005-05-09 01:02:08 +00001369static void cg_print_debug_usage(void)
njn3e884182003-04-15 13:03:23 +00001370{
1371 VG_(printf)(
1372" (none)\n"
1373 );
njn25e49d8e72002-09-23 09:36:25 +00001374}
1375
1376/*--------------------------------------------------------------------*/
1377/*--- Setup ---*/
1378/*--------------------------------------------------------------------*/
1379
njn51d827b2005-05-09 01:02:08 +00001380static void cg_post_clo_init(void)
njn25e49d8e72002-09-23 09:36:25 +00001381{
1382 cache_t I1c, D1c, L2c;
njn25e49d8e72002-09-23 09:36:25 +00001383
nethercoteb35a8b92004-09-11 16:45:27 +00001384 configure_caches(&I1c, &D1c, &L2c);
njn25e49d8e72002-09-23 09:36:25 +00001385
1386 cachesim_I1_initcache(I1c);
1387 cachesim_D1_initcache(D1c);
1388 cachesim_L2_initcache(L2c);
1389
njn31066fd2005-03-26 00:42:02 +00001390 VG_(register_profile_event)(VgpGetLineCC, "get-lineCC");
1391 VG_(register_profile_event)(VgpCacheSimulate, "cache-simulate");
1392 VG_(register_profile_event)(VgpCacheResults, "cache-results");
njn25e49d8e72002-09-23 09:36:25 +00001393}
1394
njn57ca7ab2005-06-21 23:44:58 +00001395static Char base_dir[VKI_PATH_MAX];
1396
njn51d827b2005-05-09 01:02:08 +00001397static void cg_pre_clo_init(void)
1398{
njn51d827b2005-05-09 01:02:08 +00001399 VG_(details_name) ("Cachegrind");
1400 VG_(details_version) (NULL);
1401 VG_(details_description) ("an I1/D1/L2 cache profiler");
1402 VG_(details_copyright_author)(
1403 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote et al.");
1404 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj5155dec2005-10-12 10:09:23 +00001405 VG_(details_avg_translation_sizeB) ( 245 );
njn51d827b2005-05-09 01:02:08 +00001406
1407 VG_(basic_tool_funcs) (cg_post_clo_init,
1408 cg_instrument,
1409 cg_fini);
1410
1411 VG_(needs_basic_block_discards)(cg_discard_basic_block_info);
1412 VG_(needs_command_line_options)(cg_process_cmd_line_option,
1413 cg_print_usage,
1414 cg_print_debug_usage);
1415
1416 /* Get working directory */
njn57ca7ab2005-06-21 23:44:58 +00001417 tl_assert( VG_(getcwd)(base_dir, VKI_PATH_MAX) );
njn51d827b2005-05-09 01:02:08 +00001418
1419 /* Block is big enough for dir name + cachegrind.out.<pid> */
1420 cachegrind_out_file = VG_(malloc)((VG_(strlen)(base_dir) + 32)*sizeof(Char));
1421 VG_(sprintf)(cachegrind_out_file, "%s/cachegrind.out.%d",
1422 base_dir, VG_(getpid)());
njn51d827b2005-05-09 01:02:08 +00001423
njnd3bef4f2005-10-15 17:46:18 +00001424 CC_table = VG_(OSet_Create)(offsetof(LineCC, loc),
1425 cmp_CodeLoc_LineCC,
1426 VG_(malloc), VG_(free));
1427 instrInfoTable = VG_(OSet_Create)(offsetof(BB_info, BB_addr),
1428 NULL,
1429 VG_(malloc), VG_(free));
1430 stringTable = VG_(OSet_Create)(/*keyOff*/0,
1431 stringCmp,
1432 VG_(malloc), VG_(free));
njn51d827b2005-05-09 01:02:08 +00001433}
1434
sewardj45f4e7c2005-09-27 19:20:21 +00001435VG_DETERMINE_INTERFACE_VERSION(cg_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00001436
njn25e49d8e72002-09-23 09:36:25 +00001437/*--------------------------------------------------------------------*/
njnf69f9452005-07-03 17:53:11 +00001438/*--- end ---*/
sewardj18d75132002-05-16 11:06:21 +00001439/*--------------------------------------------------------------------*/
njnd3bef4f2005-10-15 17:46:18 +00001440