blob: d84603363792c1e7dba50a5cc22544214a2acf18 [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);
njnc285dca2005-10-15 22:07:28 +0000543 return &cgs->bbInfo->instrs[ cgs->bbInfo_i - 1 ];
sewardj5155dec2005-10-12 10:09:23 +0000544}
njn016712a2005-04-04 02:52:16 +0000545
njn6a3009b2005-03-20 00:20:06 +0000546
sewardj5155dec2005-10-12 10:09:23 +0000547/* Generate code for all outstanding memory events, and mark the queue
548 empty. Code is generated into cgs->bbOut, and this activity
549 'consumes' slots in cgs->bbInfo. */
njn6a3009b2005-03-20 00:20:06 +0000550
sewardj5155dec2005-10-12 10:09:23 +0000551static void flushEvents ( CgState* cgs )
552{
njnd3bef4f2005-10-15 17:46:18 +0000553 Int i, regparms;
554 Char* helperName;
555 void* helperAddr;
556 IRExpr** argv;
557 IRExpr* i_node_expr;
558 IRExpr* i_node2_expr;
559 IRExpr* i_node3_expr;
560 IRDirty* di;
561 InstrInfo* i_node;
562 InstrInfo* i_node2;
563 InstrInfo* i_node3;
njnc285dca2005-10-15 22:07:28 +0000564 Event* ev;
565 Event* ev2;
566 Event* ev3;
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);
njnc285dca2005-10-15 22:07:28 +0000579
580 ev = &cgs->events[i];
581 ev2 = ( i < cgs->events_used-1 ? &cgs->events[i+1] : NULL );
582 ev3 = ( i < cgs->events_used-2 ? &cgs->events[i+2] : NULL );
583
sewardj5155dec2005-10-12 10:09:23 +0000584 if (DEBUG_CG) {
585 VG_(printf)(" flush ");
njnc285dca2005-10-15 22:07:28 +0000586 showEvent( ev );
njn4f9c9342002-04-29 16:03:24 +0000587 }
sewardj5155dec2005-10-12 10:09:23 +0000588
njnd3bef4f2005-10-15 17:46:18 +0000589 /* For any event we find the relevant InstrInfo. The following
sewardj5155dec2005-10-12 10:09:23 +0000590 assumes that Event_Ir is the first event to refer to any
591 specific insn, and so a new entry in the cgs->bbInfo->instrs
592 is allocated. All other events (Dr,Dw,Dm) must refer to the
593 most recently encountered IMark and so we use the
594 most-recently allocated instrs[] entry, which must exist. */
595
njnc285dca2005-10-15 22:07:28 +0000596 if (ev->ekind == Event_Ir) {
njnd3bef4f2005-10-15 17:46:18 +0000597 /* allocate an InstrInfo and fill in its addr/size. */
598 i_node = reserve_InstrInfo( cgs );
njnd3bef4f2005-10-15 17:46:18 +0000599 init_InstrInfo( i_node,
njnc285dca2005-10-15 22:07:28 +0000600 (Addr)ev->iaddr, /* i addr */
601 ev->size /* i size */);
sewardj5155dec2005-10-12 10:09:23 +0000602 } else {
603 /* use the most-recently allocated i_node but don't mess with
604 its internals */
njnd3bef4f2005-10-15 17:46:18 +0000605 i_node = find_most_recent_InstrInfo( cgs );
njnc285dca2005-10-15 22:07:28 +0000606 /* it must match the declared parent instruction of this event. */
607 tl_assert(i_node->instr_addr == ev->iaddr);
sewardj5155dec2005-10-12 10:09:23 +0000608 }
609
610 i_node_expr = mkIRExpr_HWord( (HWord)i_node );
611
612 /* Decide on helper fn to call and args to pass it, and advance
613 i appropriately. */
njnc285dca2005-10-15 22:07:28 +0000614 switch (ev->ekind) {
sewardj5155dec2005-10-12 10:09:23 +0000615 case Event_Ir:
616 /* Merge with a following Dr/Dm if it is from this insn. */
njnc285dca2005-10-15 22:07:28 +0000617 if (ev2 && (ev2->ekind == Event_Dr || ev2->ekind == Event_Dm)) {
618 tl_assert(ev2->iaddr == ev->iaddr);
sewardj5155dec2005-10-12 10:09:23 +0000619 helperName = "log_1I_1Dr_cache_access";
620 helperAddr = &log_1I_1Dr_cache_access;
621 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000622 ev2->dataEA,
623 mkIRExpr_HWord( ev2->size ) );
sewardj5155dec2005-10-12 10:09:23 +0000624 regparms = 3;
625 i += 2;
626 }
627 /* Merge with a following Dw if it is from this insn. */
628 else
njnc285dca2005-10-15 22:07:28 +0000629 if (ev2 && ev2->ekind == Event_Dw) {
630 tl_assert(ev2->iaddr == ev->iaddr);
sewardj5155dec2005-10-12 10:09:23 +0000631 helperName = "log_1I_1Dw_cache_access";
632 helperAddr = &log_1I_1Dw_cache_access;
633 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000634 ev2->dataEA,
635 mkIRExpr_HWord( ev2->size ) );
sewardj5155dec2005-10-12 10:09:23 +0000636 regparms = 3;
637 i += 2;
638 }
639 /* Merge with two following Irs if possible. */
640 else
njnc285dca2005-10-15 22:07:28 +0000641 if (ev2 && ev3 && ev2->ekind == Event_Ir && ev3->ekind == Event_Ir)
642 {
sewardj5155dec2005-10-12 10:09:23 +0000643 helperName = "log_3I_0D_cache_access";
644 helperAddr = &log_3I_0D_cache_access;
645
njnd3bef4f2005-10-15 17:46:18 +0000646 i_node2 = reserve_InstrInfo( cgs );
njnd3bef4f2005-10-15 17:46:18 +0000647 init_InstrInfo( i_node2,
njnc285dca2005-10-15 22:07:28 +0000648 (Addr)ev2->iaddr, /* i addr */
649 ev2->size /* i size */);
sewardj5155dec2005-10-12 10:09:23 +0000650 i_node2_expr = mkIRExpr_HWord( (HWord)i_node2 );
651
njnd3bef4f2005-10-15 17:46:18 +0000652 i_node3 = reserve_InstrInfo( cgs );
njnd3bef4f2005-10-15 17:46:18 +0000653 init_InstrInfo( i_node3,
njnc285dca2005-10-15 22:07:28 +0000654 (Addr)ev3->iaddr, /* i addr */
655 ev3->size /* i size */);
sewardj5155dec2005-10-12 10:09:23 +0000656 i_node3_expr = mkIRExpr_HWord( (HWord)i_node3 );
657
658 argv = mkIRExprVec_3( i_node_expr, i_node2_expr, i_node3_expr );
659 regparms = 3;
660 i += 3;
661 }
662 /* Merge with a following Ir if possible. */
663 else
njnc285dca2005-10-15 22:07:28 +0000664 if (ev2 && ev2->ekind == Event_Ir) {
sewardj5155dec2005-10-12 10:09:23 +0000665 helperName = "log_2I_0D_cache_access";
666 helperAddr = &log_2I_0D_cache_access;
njnc285dca2005-10-15 22:07:28 +0000667
njnd3bef4f2005-10-15 17:46:18 +0000668 i_node2 = reserve_InstrInfo( cgs );
njnd3bef4f2005-10-15 17:46:18 +0000669 init_InstrInfo( i_node2,
njnc285dca2005-10-15 22:07:28 +0000670 (Addr)ev2->iaddr, /* i addr */
671 ev2->size /* i size */);
672
sewardj5155dec2005-10-12 10:09:23 +0000673 i_node2_expr = mkIRExpr_HWord( (HWord)i_node2 );
674 argv = mkIRExprVec_2( i_node_expr, i_node2_expr );
675 regparms = 2;
676 i += 2;
677 }
678 /* No merging possible; emit as-is. */
679 else {
njnc285dca2005-10-15 22:07:28 +0000680 // Assertion: this Event_Ir must be the last one in the
681 // events buffer, otherwise it would have been merged with a
682 // following event.
683 tl_assert(!ev2 && !ev3);
sewardj5155dec2005-10-12 10:09:23 +0000684 helperName = "log_1I_0D_cache_access";
685 helperAddr = &log_1I_0D_cache_access;
686 argv = mkIRExprVec_1( i_node_expr );
687 regparms = 1;
688 i++;
689 }
690 break;
691 case Event_Dr:
692 case Event_Dm:
693 helperName = "log_0I_1Dr_cache_access";
694 helperAddr = &log_0I_1Dr_cache_access;
695 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000696 ev->dataEA,
697 mkIRExpr_HWord( ev->size ) );
sewardj5155dec2005-10-12 10:09:23 +0000698 regparms = 3;
699 i++;
700 break;
701 case Event_Dw:
702 helperName = "log_0I_1Dw_cache_access";
703 helperAddr = &log_0I_1Dw_cache_access;
704 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000705 ev->dataEA,
706 mkIRExpr_HWord( ev->size ) );
sewardj5155dec2005-10-12 10:09:23 +0000707 regparms = 3;
708 i++;
709 break;
710 default:
711 tl_assert(0);
712 }
713
714 /* Add the helper. */
715 tl_assert(helperName);
716 tl_assert(helperAddr);
717 tl_assert(argv);
718 di = unsafeIRDirty_0_N( regparms, helperName, helperAddr, argv);
719 addStmtToIRBB( cgs->bbOut, IRStmt_Dirty(di) );
njn4f9c9342002-04-29 16:03:24 +0000720 }
721
sewardj5155dec2005-10-12 10:09:23 +0000722 cgs->events_used = 0;
njn4f9c9342002-04-29 16:03:24 +0000723}
njn14d01ce2004-11-26 11:30:14 +0000724
sewardj5155dec2005-10-12 10:09:23 +0000725
726static void addEvent_Ir ( CgState* cgs, Int size, Addr64 iaddr )
727{
728 Event* evt;
729 tl_assert(size >= 0 && size <= MIN_LINE_SIZE);
730 if (cgs->events_used == N_EVENTS)
731 flushEvents(cgs);
732 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
733 /* If vex fails to decode an insn, the size will be zero, but that
734 can't really be true -- the cpu couldn't have determined the
735 insn was undecodable without looking at it. Hence: */
736 if (size == 0)
737 size = 1;
738 evt = &cgs->events[cgs->events_used];
739 evt->ekind = Event_Ir;
740 evt->size = size;
741 evt->iaddr = iaddr;
742 evt->dataEA = NULL; /*paranoia*/
743 cgs->events_used++;
744}
745
746static void addEvent_Dr ( CgState* cgs, Int size, Addr64 iaddr, IRAtom* ea )
747{
748 Event* evt;
749 tl_assert(isIRAtom(ea));
750 tl_assert(size >= 1 && size <= MIN_LINE_SIZE);
751 if (cgs->events_used == N_EVENTS)
752 flushEvents(cgs);
753 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
754 evt = &cgs->events[cgs->events_used];
755 evt->ekind = Event_Dr;
756 evt->size = size;
757 evt->iaddr = iaddr;
758 evt->dataEA = ea;
759 cgs->events_used++;
760}
761
762static void addEvent_Dw ( CgState* cgs, Int size, Addr64 iaddr, IRAtom* ea )
763{
764 tl_assert(isIRAtom(ea));
765 tl_assert(size >= 1 && size <= MIN_LINE_SIZE);
766
767 /* Is it possible to merge this write into an immediately preceding
768 read? */
769 if (cgs->events_used > 0
770 && cgs->events[cgs->events_used-1].ekind == Event_Dr
771 && cgs->events[cgs->events_used-1].size == size
772 && cgs->events[cgs->events_used-1].iaddr == iaddr
773 && eqIRAtom(cgs->events[cgs->events_used-1].dataEA, ea)) {
774 cgs->events[cgs->events_used-1].ekind = Event_Dm;
775 return;
776 }
777
778 /* No. Add as normal. */
779 if (cgs->events_used == N_EVENTS)
780 flushEvents(cgs);
781 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
782 cgs->events[cgs->events_used].ekind = Event_Dw;
783 cgs->events[cgs->events_used].size = size;
784 cgs->events[cgs->events_used].iaddr = iaddr;
785 cgs->events[cgs->events_used].dataEA = ea;
786 cgs->events_used++;
787}
788
789////////////////////////////////////////////////////////////
790
791
njn51d827b2005-05-09 01:02:08 +0000792static IRBB* cg_instrument ( IRBB* bbIn, VexGuestLayout* layout,
793 IRType gWordTy, IRType hWordTy )
njn14d01ce2004-11-26 11:30:14 +0000794{
sewardj5155dec2005-10-12 10:09:23 +0000795 Int i;
796 IRStmt* st;
797 Addr64 cia; /* address of current insn */
798 CgState cgs;
799 IRTypeEnv* tyenv = bbIn->tyenv;
800
njn6a3009b2005-03-20 00:20:06 +0000801
sewardjd54babf2005-03-21 00:55:49 +0000802 if (gWordTy != hWordTy) {
803 /* We don't currently support this case. */
804 VG_(tool_panic)("host/guest word size mismatch");
805 }
806
njn6a3009b2005-03-20 00:20:06 +0000807 /* Set up BB */
sewardj5155dec2005-10-12 10:09:23 +0000808 cgs.bbOut = emptyIRBB();
809 cgs.bbOut->tyenv = dopyIRTypeEnv(tyenv);
njn6a3009b2005-03-20 00:20:06 +0000810
sewardj5155dec2005-10-12 10:09:23 +0000811 // Get the first statement, and initial cia from it
njn6a3009b2005-03-20 00:20:06 +0000812 i = 0;
813 tl_assert(bbIn->stmts_used > 0);
814 st = bbIn->stmts[0];
815 tl_assert(Ist_IMark == st->tag);
sewardj5155dec2005-10-12 10:09:23 +0000816 cia = st->Ist.IMark.addr;
njn6a3009b2005-03-20 00:20:06 +0000817
sewardj5155dec2005-10-12 10:09:23 +0000818 // Set up running state and get block info
819 cgs.events_used = 0;
sewardja3a29a52005-10-12 16:16:03 +0000820 cgs.bbInfo = get_BB_info(bbIn, (Addr)cia);
sewardj5155dec2005-10-12 10:09:23 +0000821 cgs.bbInfo_i = 0;
njn6a3009b2005-03-20 00:20:06 +0000822
sewardj5155dec2005-10-12 10:09:23 +0000823 if (DEBUG_CG)
824 VG_(printf)("\n\n---------- cg_instrument ----------\n");
njn6a3009b2005-03-20 00:20:06 +0000825
sewardj5155dec2005-10-12 10:09:23 +0000826 // Traverse the block, adding events and flushing as necessary.
827 for (i = 0; i < bbIn->stmts_used; i++) {
njn6a3009b2005-03-20 00:20:06 +0000828
sewardj5155dec2005-10-12 10:09:23 +0000829 st = bbIn->stmts[i];
830 tl_assert(isFlatIRStmt(st));
njnb3507ea2005-08-02 23:07:02 +0000831
sewardj5155dec2005-10-12 10:09:23 +0000832 switch (st->tag) {
833 case Ist_NoOp:
834 case Ist_AbiHint:
835 case Ist_Put:
836 case Ist_PutI:
837 case Ist_MFence:
838 break;
njn20677cc2005-08-12 23:47:51 +0000839
sewardj5155dec2005-10-12 10:09:23 +0000840 case Ist_IMark:
841 cia = st->Ist.IMark.addr;
842 addEvent_Ir( &cgs, st->Ist.IMark.len, cia );
843 break;
844
845 case Ist_Tmp: {
846 IRExpr* data = st->Ist.Tmp.data;
847 if (data->tag == Iex_Load) {
848 IRExpr* aexpr = data->Iex.Load.addr;
849 tl_assert( isIRAtom(aexpr) );
850 // Note also, endianness info is ignored. I guess
851 // that's not interesting.
852 addEvent_Dr( &cgs, sizeofIRType(data->Iex.Load.ty),
853 cia, aexpr );
854 }
855 break;
njnb3507ea2005-08-02 23:07:02 +0000856 }
857
sewardj5155dec2005-10-12 10:09:23 +0000858 case Ist_Store: {
859 IRExpr* data = st->Ist.Store.data;
860 IRExpr* aexpr = st->Ist.Store.addr;
861 tl_assert( isIRAtom(aexpr) );
862 addEvent_Dw( &cgs,
863 sizeofIRType(typeOfIRExpr(tyenv, data)),
864 cia, aexpr );
865 break;
866 }
njnb3507ea2005-08-02 23:07:02 +0000867
sewardj5155dec2005-10-12 10:09:23 +0000868 case Ist_Dirty: {
869 Int dataSize;
870 IRDirty* d = st->Ist.Dirty.details;
871 if (d->mFx != Ifx_None) {
872 /* This dirty helper accesses memory. Collect the
873 details. */
874 tl_assert(d->mAddr != NULL);
875 tl_assert(d->mSize != 0);
876 dataSize = d->mSize;
877 // Large (eg. 28B, 108B, 512B on x86) data-sized
878 // instructions will be done inaccurately, but they're
879 // very rare and this avoids errors from hitting more
880 // than two cache lines in the simulation.
881 if (dataSize > MIN_LINE_SIZE)
882 dataSize = MIN_LINE_SIZE;
883 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
884 addEvent_Dr( &cgs, dataSize, cia, d->mAddr );
885 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
886 addEvent_Dw( &cgs, dataSize, cia, d->mAddr );
887 } else {
888 tl_assert(d->mAddr == NULL);
889 tl_assert(d->mSize == 0);
890 }
891 break;
892 }
njn6a3009b2005-03-20 00:20:06 +0000893
sewardj5155dec2005-10-12 10:09:23 +0000894 case Ist_Exit:
895 /* We may never reach the next statement, so need to flush
896 all outstanding transactions now. */
897 flushEvents( &cgs );
898 break;
899
900 default:
901 tl_assert(0);
902 break;
njnb3507ea2005-08-02 23:07:02 +0000903 }
njn6a3009b2005-03-20 00:20:06 +0000904
sewardj5155dec2005-10-12 10:09:23 +0000905 /* Copy the original statement */
906 addStmtToIRBB( cgs.bbOut, st );
njn6a3009b2005-03-20 00:20:06 +0000907
sewardj5155dec2005-10-12 10:09:23 +0000908 if (DEBUG_CG) {
909 ppIRStmt(st);
910 VG_(printf)("\n");
911 }
912 }
913
914 /* At the end of the bb. Flush outstandings. */
915 tl_assert(isIRAtom(bbIn->next));
916 flushEvents( &cgs );
917
918 /* copy where-next stuff. */
919 cgs.bbOut->next = dopyIRExpr(bbIn->next);
920 cgs.bbOut->jumpkind = bbIn->jumpkind;
921
922 /* done. stay sane ... */
923 tl_assert(cgs.bbInfo_i == cgs.bbInfo->n_instrs);
924
925 if (DEBUG_CG) {
926 VG_(printf)( "goto {");
927 ppIRJumpKind(bbIn->jumpkind);
928 VG_(printf)( "} ");
929 ppIRExpr( bbIn->next );
930 VG_(printf)( "}\n");
931 }
932
933 return cgs.bbOut;
njn14d01ce2004-11-26 11:30:14 +0000934}
njn4f9c9342002-04-29 16:03:24 +0000935
936/*------------------------------------------------------------*/
nethercoteb35a8b92004-09-11 16:45:27 +0000937/*--- Cache configuration ---*/
njn4f9c9342002-04-29 16:03:24 +0000938/*------------------------------------------------------------*/
939
sewardjb5f6f512005-03-10 23:59:00 +0000940#define UNDEFINED_CACHE { -1, -1, -1 }
njn25e49d8e72002-09-23 09:36:25 +0000941
942static cache_t clo_I1_cache = UNDEFINED_CACHE;
943static cache_t clo_D1_cache = UNDEFINED_CACHE;
944static cache_t clo_L2_cache = UNDEFINED_CACHE;
945
njn7cf0bd32002-06-08 13:36:03 +0000946/* Checks cache config is ok; makes it so if not. */
sewardj07133bf2002-06-13 10:25:56 +0000947static
njna1d1a642004-11-26 18:36:02 +0000948void check_cache(cache_t* cache, Char *name)
njn7cf0bd32002-06-08 13:36:03 +0000949{
950 /* First check they're all powers of two */
sewardj07133bf2002-06-13 10:25:56 +0000951 if (-1 == VG_(log2)(cache->size)) {
njn7cf0bd32002-06-08 13:36:03 +0000952 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000953 "error: %s size of %dB not a power of two; aborting.",
954 name, cache->size);
955 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000956 }
957
sewardj07133bf2002-06-13 10:25:56 +0000958 if (-1 == VG_(log2)(cache->assoc)) {
njn7cf0bd32002-06-08 13:36:03 +0000959 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000960 "error: %s associativity of %d not a power of two; aborting.",
961 name, cache->assoc);
962 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000963 }
964
sewardj07133bf2002-06-13 10:25:56 +0000965 if (-1 == VG_(log2)(cache->line_size)) {
njn7cf0bd32002-06-08 13:36:03 +0000966 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000967 "error: %s line size of %dB not a power of two; aborting.",
968 name, cache->line_size);
969 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000970 }
971
njn6a3009b2005-03-20 00:20:06 +0000972 // Then check line size >= 16 -- any smaller and a single instruction could
973 // straddle three cache lines, which breaks a simulation assertion and is
974 // stupid anyway.
njn7cf0bd32002-06-08 13:36:03 +0000975 if (cache->line_size < MIN_LINE_SIZE) {
976 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000977 "error: %s line size of %dB too small; aborting.",
978 name, cache->line_size);
979 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000980 }
981
982 /* Then check cache size > line size (causes seg faults if not). */
983 if (cache->size <= cache->line_size) {
984 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000985 "error: %s cache size of %dB <= line size of %dB; aborting.",
986 name, cache->size, cache->line_size);
987 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000988 }
989
990 /* Then check assoc <= (size / line size) (seg faults otherwise). */
991 if (cache->assoc > (cache->size / cache->line_size)) {
992 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000993 "warning: %s associativity > (size / line size); aborting.", name);
994 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000995 }
996}
997
sewardj07133bf2002-06-13 10:25:56 +0000998static
nethercoteb35a8b92004-09-11 16:45:27 +0000999void configure_caches(cache_t* I1c, cache_t* D1c, cache_t* L2c)
njn7cf0bd32002-06-08 13:36:03 +00001000{
nethercote9313ac42004-07-06 21:54:20 +00001001#define DEFINED(L) (-1 != L.size || -1 != L.assoc || -1 != L.line_size)
1002
nethercoteb35a8b92004-09-11 16:45:27 +00001003 Int n_clos = 0;
nethercote9313ac42004-07-06 21:54:20 +00001004
nethercoteb35a8b92004-09-11 16:45:27 +00001005 // Count how many were defined on the command line.
1006 if (DEFINED(clo_I1_cache)) { n_clos++; }
1007 if (DEFINED(clo_D1_cache)) { n_clos++; }
1008 if (DEFINED(clo_L2_cache)) { n_clos++; }
njn7cf0bd32002-06-08 13:36:03 +00001009
njna1d1a642004-11-26 18:36:02 +00001010 // Set the cache config (using auto-detection, if supported by the
1011 // architecture)
njnaf839f52005-06-23 03:27:57 +00001012 VG_(configure_caches)( I1c, D1c, L2c, (3 == n_clos) );
sewardjb1a77a42002-07-13 13:31:20 +00001013
nethercote9313ac42004-07-06 21:54:20 +00001014 // Then replace with any defined on the command line.
nethercoteb35a8b92004-09-11 16:45:27 +00001015 if (DEFINED(clo_I1_cache)) { *I1c = clo_I1_cache; }
1016 if (DEFINED(clo_D1_cache)) { *D1c = clo_D1_cache; }
1017 if (DEFINED(clo_L2_cache)) { *L2c = clo_L2_cache; }
njn7cf0bd32002-06-08 13:36:03 +00001018
nethercote9313ac42004-07-06 21:54:20 +00001019 // Then check values and fix if not acceptable.
njna1d1a642004-11-26 18:36:02 +00001020 check_cache(I1c, "I1");
1021 check_cache(D1c, "D1");
1022 check_cache(L2c, "L2");
njn7cf0bd32002-06-08 13:36:03 +00001023
1024 if (VG_(clo_verbosity) > 1) {
1025 VG_(message)(Vg_UserMsg, "Cache configuration used:");
1026 VG_(message)(Vg_UserMsg, " I1: %dB, %d-way, %dB lines",
1027 I1c->size, I1c->assoc, I1c->line_size);
1028 VG_(message)(Vg_UserMsg, " D1: %dB, %d-way, %dB lines",
1029 D1c->size, D1c->assoc, D1c->line_size);
1030 VG_(message)(Vg_UserMsg, " L2: %dB, %d-way, %dB lines",
1031 L2c->size, L2c->assoc, L2c->line_size);
1032 }
nethercote9313ac42004-07-06 21:54:20 +00001033#undef CMD_LINE_DEFINED
njn7cf0bd32002-06-08 13:36:03 +00001034}
1035
njn4f9c9342002-04-29 16:03:24 +00001036/*------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +00001037/*--- cg_fini() and related function ---*/
njn4f9c9342002-04-29 16:03:24 +00001038/*------------------------------------------------------------*/
1039
nethercote9313ac42004-07-06 21:54:20 +00001040// Total reads/writes/misses. Calculated during CC traversal at the end.
1041// All auto-zeroed.
1042static CC Ir_total;
1043static CC Dr_total;
1044static CC Dw_total;
1045
1046static Char* cachegrind_out_file;
1047
nethercote9313ac42004-07-06 21:54:20 +00001048static void fprint_CC_table_and_calc_totals(void)
1049{
njnd3bef4f2005-10-15 17:46:18 +00001050 Int i, fd;
sewardj92645592005-07-23 09:18:34 +00001051 SysRes sres;
njnd3bef4f2005-10-15 17:46:18 +00001052 Char buf[512], *currFile = NULL, *currFn = NULL;
1053 LineCC* lineCC;
njn4f9c9342002-04-29 16:03:24 +00001054
njn25e49d8e72002-09-23 09:36:25 +00001055 VGP_PUSHCC(VgpCacheResults);
njn13f02932003-04-30 20:23:58 +00001056
sewardj92645592005-07-23 09:18:34 +00001057 sres = VG_(open)(cachegrind_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
1058 VKI_S_IRUSR|VKI_S_IWUSR);
1059 if (sres.isError) {
nethercote9313ac42004-07-06 21:54:20 +00001060 // If the file can't be opened for whatever reason (conflict
1061 // between multiple cachegrinded processes?), give up now.
njnee0e6a32005-04-24 00:21:01 +00001062 VG_(message)(Vg_UserMsg,
njn02bc4b82005-05-15 17:28:26 +00001063 "error: can't open cache simulation output file '%s'",
njnee0e6a32005-04-24 00:21:01 +00001064 cachegrind_out_file );
1065 VG_(message)(Vg_UserMsg,
1066 " ... so simulation results will be missing.");
sewardj0744b6c2002-12-11 00:45:42 +00001067 return;
sewardj92645592005-07-23 09:18:34 +00001068 } else {
1069 fd = sres.val;
sewardj0744b6c2002-12-11 00:45:42 +00001070 }
njn4f9c9342002-04-29 16:03:24 +00001071
nethercote9313ac42004-07-06 21:54:20 +00001072 // "desc:" lines (giving I1/D1/L2 cache configuration). The spaces after
1073 // the 2nd colon makes cg_annotate's output look nicer.
1074 VG_(sprintf)(buf, "desc: I1 cache: %s\n"
1075 "desc: D1 cache: %s\n"
1076 "desc: L2 cache: %s\n",
1077 I1.desc_line, D1.desc_line, L2.desc_line);
njn7cf0bd32002-06-08 13:36:03 +00001078 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njn4f9c9342002-04-29 16:03:24 +00001079
nethercote9313ac42004-07-06 21:54:20 +00001080 // "cmd:" line
njn4f9c9342002-04-29 16:03:24 +00001081 VG_(strcpy)(buf, "cmd:");
1082 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
sewardj45f4e7c2005-09-27 19:20:21 +00001083 if (VG_(args_the_exename)) {
1084 VG_(write)(fd, " ", 1);
1085 VG_(write)(fd, VG_(args_the_exename),
1086 VG_(strlen)( VG_(args_the_exename) ));
1087 }
1088 for (i = 0; i < VG_(args_for_client).used; i++) {
1089 if (VG_(args_for_client).strs[i]) {
1090 VG_(write)(fd, " ", 1);
1091 VG_(write)(fd, VG_(args_for_client).strs[i],
1092 VG_(strlen)(VG_(args_for_client).strs[i]));
1093 }
njn4f9c9342002-04-29 16:03:24 +00001094 }
nethercote9313ac42004-07-06 21:54:20 +00001095 // "events:" line
njn4f9c9342002-04-29 16:03:24 +00001096 VG_(sprintf)(buf, "\nevents: Ir I1mr I2mr Dr D1mr D2mr Dw D1mw D2mw\n");
1097 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1098
njnd3bef4f2005-10-15 17:46:18 +00001099 // Traverse every lineCC
1100 VG_(OSet_ResetIter)(CC_table);
1101 while ( (lineCC = VG_(OSet_Next)(CC_table)) ) {
1102 // If we've hit a new file, print a "fl=" line. Note that because
1103 // each string is stored exactly once in the string table, we can use
1104 // pointer comparison rather than strcmp() to test for equality, which
1105 // is good because most of the time the comparisons are equal and so
1106 // the whole strings would have to be traversed.
1107 if ( lineCC->loc.file != currFile ) {
1108 currFile = lineCC->loc.file;
1109 VG_(sprintf)(buf, "fl=%s\n", currFile);
njn4f9c9342002-04-29 16:03:24 +00001110 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njnd3bef4f2005-10-15 17:46:18 +00001111 distinct_files++;
njn4f9c9342002-04-29 16:03:24 +00001112 }
njnd3bef4f2005-10-15 17:46:18 +00001113 // If we've hit a new function, print a "fn=" line.
1114 if ( lineCC->loc.fn != currFn ) {
1115 currFn = lineCC->loc.fn;
1116 VG_(sprintf)(buf, "fn=%s\n", currFn);
1117 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1118 distinct_fns++;
1119 }
1120
1121 // Print the LineCC
1122 VG_(sprintf)(buf, "%u %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
1123 lineCC->loc.line,
1124 lineCC->Ir.a, lineCC->Ir.m1, lineCC->Ir.m2,
1125 lineCC->Dr.a, lineCC->Dr.m1, lineCC->Dr.m2,
1126 lineCC->Dw.a, lineCC->Dw.m1, lineCC->Dw.m2);
1127 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1128
1129 // Update summary stats
1130 Ir_total.a += lineCC->Ir.a;
1131 Ir_total.m1 += lineCC->Ir.m1;
1132 Ir_total.m2 += lineCC->Ir.m2;
1133 Dr_total.a += lineCC->Dr.a;
1134 Dr_total.m1 += lineCC->Dr.m1;
1135 Dr_total.m2 += lineCC->Dr.m2;
1136 Dw_total.a += lineCC->Dw.a;
1137 Dw_total.m1 += lineCC->Dw.m1;
1138 Dw_total.m2 += lineCC->Dw.m2;
1139
1140 distinct_lines++;
njn4f9c9342002-04-29 16:03:24 +00001141 }
1142
nethercote9313ac42004-07-06 21:54:20 +00001143 // Summary stats must come after rest of table, since we calculate them
1144 // during traversal. */
njn4f9c9342002-04-29 16:03:24 +00001145 VG_(sprintf)(buf, "summary: "
nethercote9313ac42004-07-06 21:54:20 +00001146 "%llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
njn4f9c9342002-04-29 16:03:24 +00001147 Ir_total.a, Ir_total.m1, Ir_total.m2,
1148 Dr_total.a, Dr_total.m1, Dr_total.m2,
1149 Dw_total.a, Dw_total.m1, Dw_total.m2);
1150 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1151 VG_(close)(fd);
1152}
1153
njn607adfc2003-09-30 14:15:44 +00001154static UInt ULong_width(ULong n)
njn4f9c9342002-04-29 16:03:24 +00001155{
njn607adfc2003-09-30 14:15:44 +00001156 UInt w = 0;
1157 while (n > 0) {
1158 n = n / 10;
1159 w++;
njn4f9c9342002-04-29 16:03:24 +00001160 }
njn607adfc2003-09-30 14:15:44 +00001161 return w + (w-1)/3; // add space for commas
njn4f9c9342002-04-29 16:03:24 +00001162}
1163
njn51d827b2005-05-09 01:02:08 +00001164static void cg_fini(Int exitcode)
njn4f9c9342002-04-29 16:03:24 +00001165{
njn0103de52005-10-10 16:49:01 +00001166 static Char buf1[128], buf2[128], buf3[128], fmt [128];
njn607adfc2003-09-30 14:15:44 +00001167
njn4f9c9342002-04-29 16:03:24 +00001168 CC D_total;
njn1d021fa2002-05-02 13:56:34 +00001169 ULong L2_total_m, L2_total_mr, L2_total_mw,
1170 L2_total, L2_total_r, L2_total_w;
njn4f9c9342002-04-29 16:03:24 +00001171 Int l1, l2, l3;
1172 Int p;
1173
nethercote9313ac42004-07-06 21:54:20 +00001174 fprint_CC_table_and_calc_totals();
njn4f9c9342002-04-29 16:03:24 +00001175
njn7cf0bd32002-06-08 13:36:03 +00001176 if (VG_(clo_verbosity) == 0)
1177 return;
1178
njn4f9c9342002-04-29 16:03:24 +00001179 /* I cache results. Use the I_refs value to determine the first column
1180 * width. */
njn607adfc2003-09-30 14:15:44 +00001181 l1 = ULong_width(Ir_total.a);
1182 l2 = ULong_width(Dr_total.a);
1183 l3 = ULong_width(Dw_total.a);
njn4f9c9342002-04-29 16:03:24 +00001184
njn607adfc2003-09-30 14:15:44 +00001185 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001186 VG_(sprintf)(fmt, "%%s %%,%dllu", l1);
njnd3bef4f2005-10-15 17:46:18 +00001187
njn607adfc2003-09-30 14:15:44 +00001188 VG_(message)(Vg_UserMsg, fmt, "I refs: ", Ir_total.a);
1189 VG_(message)(Vg_UserMsg, fmt, "I1 misses: ", Ir_total.m1);
1190 VG_(message)(Vg_UserMsg, fmt, "L2i misses: ", Ir_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001191
1192 p = 100;
1193
njn25e49d8e72002-09-23 09:36:25 +00001194 if (0 == Ir_total.a) Ir_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001195 VG_(percentify)(Ir_total.m1, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001196 VG_(message)(Vg_UserMsg, "I1 miss rate: %s", buf1);
njnd3bef4f2005-10-15 17:46:18 +00001197
njn856c54e2005-06-26 18:43:40 +00001198 VG_(percentify)(Ir_total.m2, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001199 VG_(message)(Vg_UserMsg, "L2i miss rate: %s", buf1);
1200 VG_(message)(Vg_UserMsg, "");
1201
1202 /* D cache results. Use the D_refs.rd and D_refs.wr values to determine the
1203 * width of columns 2 & 3. */
1204 D_total.a = Dr_total.a + Dw_total.a;
1205 D_total.m1 = Dr_total.m1 + Dw_total.m1;
1206 D_total.m2 = Dr_total.m2 + Dw_total.m2;
njnd3bef4f2005-10-15 17:46:18 +00001207
njn607adfc2003-09-30 14:15:44 +00001208 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001209 VG_(sprintf)(fmt, "%%s %%,%dllu (%%,%dllu rd + %%,%dllu wr)", l1, l2, l3);
njn4f9c9342002-04-29 16:03:24 +00001210
njn607adfc2003-09-30 14:15:44 +00001211 VG_(message)(Vg_UserMsg, fmt, "D refs: ",
1212 D_total.a, Dr_total.a, Dw_total.a);
1213 VG_(message)(Vg_UserMsg, fmt, "D1 misses: ",
1214 D_total.m1, Dr_total.m1, Dw_total.m1);
1215 VG_(message)(Vg_UserMsg, fmt, "L2d misses: ",
1216 D_total.m2, Dr_total.m2, Dw_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001217
1218 p = 10;
njnd3bef4f2005-10-15 17:46:18 +00001219
njn25e49d8e72002-09-23 09:36:25 +00001220 if (0 == D_total.a) D_total.a = 1;
1221 if (0 == Dr_total.a) Dr_total.a = 1;
1222 if (0 == Dw_total.a) Dw_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001223 VG_(percentify)( D_total.m1, D_total.a, 1, l1+1, buf1);
1224 VG_(percentify)(Dr_total.m1, Dr_total.a, 1, l2+1, buf2);
1225 VG_(percentify)(Dw_total.m1, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001226 VG_(message)(Vg_UserMsg, "D1 miss rate: %s (%s + %s )", buf1, buf2,buf3);
1227
njn856c54e2005-06-26 18:43:40 +00001228 VG_(percentify)( D_total.m2, D_total.a, 1, l1+1, buf1);
1229 VG_(percentify)(Dr_total.m2, Dr_total.a, 1, l2+1, buf2);
1230 VG_(percentify)(Dw_total.m2, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001231 VG_(message)(Vg_UserMsg, "L2d miss rate: %s (%s + %s )", buf1, buf2,buf3);
1232 VG_(message)(Vg_UserMsg, "");
1233
1234 /* L2 overall results */
njn1d021fa2002-05-02 13:56:34 +00001235
1236 L2_total = Dr_total.m1 + Dw_total.m1 + Ir_total.m1;
1237 L2_total_r = Dr_total.m1 + Ir_total.m1;
1238 L2_total_w = Dw_total.m1;
njn607adfc2003-09-30 14:15:44 +00001239 VG_(message)(Vg_UserMsg, fmt, "L2 refs: ",
1240 L2_total, L2_total_r, L2_total_w);
njn1d021fa2002-05-02 13:56:34 +00001241
njn4f9c9342002-04-29 16:03:24 +00001242 L2_total_m = Dr_total.m2 + Dw_total.m2 + Ir_total.m2;
1243 L2_total_mr = Dr_total.m2 + Ir_total.m2;
1244 L2_total_mw = Dw_total.m2;
njn607adfc2003-09-30 14:15:44 +00001245 VG_(message)(Vg_UserMsg, fmt, "L2 misses: ",
1246 L2_total_m, L2_total_mr, L2_total_mw);
njn4f9c9342002-04-29 16:03:24 +00001247
njn856c54e2005-06-26 18:43:40 +00001248 VG_(percentify)(L2_total_m, (Ir_total.a + D_total.a), 1, l1+1, buf1);
1249 VG_(percentify)(L2_total_mr, (Ir_total.a + Dr_total.a), 1, l2+1, buf2);
1250 VG_(percentify)(L2_total_mw, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001251 VG_(message)(Vg_UserMsg, "L2 miss rate: %s (%s + %s )", buf1, buf2,buf3);
njnd3bef4f2005-10-15 17:46:18 +00001252
njn4f9c9342002-04-29 16:03:24 +00001253
nethercote9313ac42004-07-06 21:54:20 +00001254 // Various stats
njn4f9c9342002-04-29 16:03:24 +00001255 if (VG_(clo_verbosity) > 1) {
njnd3bef4f2005-10-15 17:46:18 +00001256 Int debug_lookups = full_debugs + fn_debugs +
1257 file_line_debugs + no_debugs;
1258
njn4f9c9342002-04-29 16:03:24 +00001259 VG_(message)(Vg_DebugMsg, "");
njnd3bef4f2005-10-15 17:46:18 +00001260 VG_(message)(Vg_DebugMsg, "cachegrind: distinct files: %d", distinct_files);
1261 VG_(message)(Vg_DebugMsg, "cachegrind: distinct fns: %d", distinct_fns);
1262 VG_(message)(Vg_DebugMsg, "cachegrind: distinct lines: %d", distinct_lines);
1263 VG_(message)(Vg_DebugMsg, "cachegrind: distinct instrs:%d", distinct_instrs);
1264 VG_(message)(Vg_DebugMsg, "cachegrind: debug lookups : %d", debug_lookups);
1265 VG_(message)(Vg_DebugMsg, "cachegrind: with full info:%3d%% (%d)",
1266 full_debugs * 100 / debug_lookups, full_debugs);
1267 VG_(message)(Vg_DebugMsg, "cachegrind: with file/line info:%3d%% (%d)",
1268 file_line_debugs * 100 / debug_lookups, file_line_debugs);
1269 VG_(message)(Vg_DebugMsg, "cachegrind: with fn name info:%3d%% (%d)",
1270 fn_debugs * 100 / debug_lookups, fn_debugs);
1271 VG_(message)(Vg_DebugMsg, "cachegrind: with zero info:%3d%% (%d)",
1272 no_debugs * 100 / debug_lookups, no_debugs);
1273 VG_(message)(Vg_DebugMsg, "cachegrind: BBs Retranslated: %d",
1274 BB_retranslations);
1275 VG_(message)(Vg_DebugMsg, "cachegrind: string table size: %u",
1276 VG_(OSet_Size)(stringTable));
1277 VG_(message)(Vg_DebugMsg, "cachegrind: CC table size: %u",
1278 VG_(OSet_Size)(CC_table));
1279 VG_(message)(Vg_DebugMsg, "cachegrind: InstrInfo table size: %u",
1280 VG_(OSet_Size)(instrInfoTable));
njn4f9c9342002-04-29 16:03:24 +00001281 }
njn25e49d8e72002-09-23 09:36:25 +00001282 VGP_POPCC(VgpCacheResults);
njn4f9c9342002-04-29 16:03:24 +00001283}
1284
nethercote9313ac42004-07-06 21:54:20 +00001285/*--------------------------------------------------------------------*/
1286/*--- Discarding BB info ---*/
1287/*--------------------------------------------------------------------*/
sewardj18d75132002-05-16 11:06:21 +00001288
sewardja3a29a52005-10-12 16:16:03 +00001289// Called when a translation is removed from the translation cache for
1290// any reason at all: to free up space, because the guest code was
1291// unmapped or modified, or for any arbitrary reason.
sewardj5155dec2005-10-12 10:09:23 +00001292static void cg_discard_basic_block_info ( VexGuestExtents vge )
sewardj18d75132002-05-16 11:06:21 +00001293{
njnd3bef4f2005-10-15 17:46:18 +00001294 BB_info* bbInfo;
njn4294fd42002-06-05 14:41:10 +00001295
sewardj5155dec2005-10-12 10:09:23 +00001296 tl_assert(vge.n_used > 0);
1297
1298 if (DEBUG_CG)
1299 VG_(printf)( "discard_basic_block_info: %p, %llu\n",
1300 (void*)(Addr)vge.base[0], (ULong)vge.len[0]);
njn4294fd42002-06-05 14:41:10 +00001301
nethercote9313ac42004-07-06 21:54:20 +00001302 // Get BB info, remove from table, free BB info. Simple!
njnd3bef4f2005-10-15 17:46:18 +00001303 bbInfo = VG_(OSet_Remove)(instrInfoTable, &(vge.base[0]));
njn6a3009b2005-03-20 00:20:06 +00001304 tl_assert(NULL != bbInfo);
njnd3bef4f2005-10-15 17:46:18 +00001305 VG_(OSet_FreeNode)(instrInfoTable, bbInfo);
sewardj18d75132002-05-16 11:06:21 +00001306}
1307
1308/*--------------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001309/*--- Command line processing ---*/
1310/*--------------------------------------------------------------------*/
1311
njn0103de52005-10-10 16:49:01 +00001312static void parse_cache_opt ( cache_t* cache, Char* opt )
njn25e49d8e72002-09-23 09:36:25 +00001313{
njn0103de52005-10-10 16:49:01 +00001314 Int i = 0, i2, i3;
njn25e49d8e72002-09-23 09:36:25 +00001315
nethercote9313ac42004-07-06 21:54:20 +00001316 // Option argument looks like "65536,2,64".
1317 // Find commas, replace with NULs to make three independent
1318 // strings, then extract numbers, put NULs back. Yuck.
njn25e49d8e72002-09-23 09:36:25 +00001319 while (VG_(isdigit)(opt[i])) i++;
1320 if (',' == opt[i]) {
1321 opt[i++] = '\0';
1322 i2 = i;
1323 } else goto bad;
1324 while (VG_(isdigit)(opt[i])) i++;
1325 if (',' == opt[i]) {
1326 opt[i++] = '\0';
1327 i3 = i;
1328 } else goto bad;
1329 while (VG_(isdigit)(opt[i])) i++;
1330 if ('\0' != opt[i]) goto bad;
1331
nethercote9313ac42004-07-06 21:54:20 +00001332 cache->size = (Int)VG_(atoll)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001333 cache->assoc = (Int)VG_(atoll)(opt + i2);
1334 cache->line_size = (Int)VG_(atoll)(opt + i3);
1335
nethercote9313ac42004-07-06 21:54:20 +00001336 opt[i2-1] = ',';
1337 opt[i3-1] = ',';
njn25e49d8e72002-09-23 09:36:25 +00001338 return;
1339
1340 bad:
nethercote9313ac42004-07-06 21:54:20 +00001341 VG_(bad_option)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001342}
1343
njn51d827b2005-05-09 01:02:08 +00001344static Bool cg_process_cmd_line_option(Char* arg)
njn25e49d8e72002-09-23 09:36:25 +00001345{
nethercote9313ac42004-07-06 21:54:20 +00001346 // 5 is length of "--I1="
njn39c86652003-05-21 10:13:39 +00001347 if (VG_CLO_STREQN(5, arg, "--I1="))
nethercote9313ac42004-07-06 21:54:20 +00001348 parse_cache_opt(&clo_I1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001349 else if (VG_CLO_STREQN(5, arg, "--D1="))
nethercote9313ac42004-07-06 21:54:20 +00001350 parse_cache_opt(&clo_D1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001351 else if (VG_CLO_STREQN(5, arg, "--L2="))
nethercote9313ac42004-07-06 21:54:20 +00001352 parse_cache_opt(&clo_L2_cache, &arg[5]);
njn25e49d8e72002-09-23 09:36:25 +00001353 else
1354 return False;
1355
1356 return True;
1357}
1358
njn51d827b2005-05-09 01:02:08 +00001359static void cg_print_usage(void)
njn25e49d8e72002-09-23 09:36:25 +00001360{
njn3e884182003-04-15 13:03:23 +00001361 VG_(printf)(
njn25e49d8e72002-09-23 09:36:25 +00001362" --I1=<size>,<assoc>,<line_size> set I1 cache manually\n"
1363" --D1=<size>,<assoc>,<line_size> set D1 cache manually\n"
njn3e884182003-04-15 13:03:23 +00001364" --L2=<size>,<assoc>,<line_size> set L2 cache manually\n"
1365 );
1366}
1367
njn51d827b2005-05-09 01:02:08 +00001368static void cg_print_debug_usage(void)
njn3e884182003-04-15 13:03:23 +00001369{
1370 VG_(printf)(
1371" (none)\n"
1372 );
njn25e49d8e72002-09-23 09:36:25 +00001373}
1374
1375/*--------------------------------------------------------------------*/
1376/*--- Setup ---*/
1377/*--------------------------------------------------------------------*/
1378
njn51d827b2005-05-09 01:02:08 +00001379static void cg_post_clo_init(void)
njn25e49d8e72002-09-23 09:36:25 +00001380{
1381 cache_t I1c, D1c, L2c;
njn25e49d8e72002-09-23 09:36:25 +00001382
nethercoteb35a8b92004-09-11 16:45:27 +00001383 configure_caches(&I1c, &D1c, &L2c);
njn25e49d8e72002-09-23 09:36:25 +00001384
1385 cachesim_I1_initcache(I1c);
1386 cachesim_D1_initcache(D1c);
1387 cachesim_L2_initcache(L2c);
1388
njn31066fd2005-03-26 00:42:02 +00001389 VG_(register_profile_event)(VgpGetLineCC, "get-lineCC");
1390 VG_(register_profile_event)(VgpCacheSimulate, "cache-simulate");
1391 VG_(register_profile_event)(VgpCacheResults, "cache-results");
njn25e49d8e72002-09-23 09:36:25 +00001392}
1393
njn57ca7ab2005-06-21 23:44:58 +00001394static Char base_dir[VKI_PATH_MAX];
1395
njn51d827b2005-05-09 01:02:08 +00001396static void cg_pre_clo_init(void)
1397{
njn51d827b2005-05-09 01:02:08 +00001398 VG_(details_name) ("Cachegrind");
1399 VG_(details_version) (NULL);
1400 VG_(details_description) ("an I1/D1/L2 cache profiler");
1401 VG_(details_copyright_author)(
1402 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote et al.");
1403 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj5155dec2005-10-12 10:09:23 +00001404 VG_(details_avg_translation_sizeB) ( 245 );
njn51d827b2005-05-09 01:02:08 +00001405
1406 VG_(basic_tool_funcs) (cg_post_clo_init,
1407 cg_instrument,
1408 cg_fini);
1409
1410 VG_(needs_basic_block_discards)(cg_discard_basic_block_info);
1411 VG_(needs_command_line_options)(cg_process_cmd_line_option,
1412 cg_print_usage,
1413 cg_print_debug_usage);
1414
1415 /* Get working directory */
njn57ca7ab2005-06-21 23:44:58 +00001416 tl_assert( VG_(getcwd)(base_dir, VKI_PATH_MAX) );
njn51d827b2005-05-09 01:02:08 +00001417
1418 /* Block is big enough for dir name + cachegrind.out.<pid> */
1419 cachegrind_out_file = VG_(malloc)((VG_(strlen)(base_dir) + 32)*sizeof(Char));
1420 VG_(sprintf)(cachegrind_out_file, "%s/cachegrind.out.%d",
1421 base_dir, VG_(getpid)());
njn51d827b2005-05-09 01:02:08 +00001422
njnd3bef4f2005-10-15 17:46:18 +00001423 CC_table = VG_(OSet_Create)(offsetof(LineCC, loc),
1424 cmp_CodeLoc_LineCC,
1425 VG_(malloc), VG_(free));
1426 instrInfoTable = VG_(OSet_Create)(offsetof(BB_info, BB_addr),
1427 NULL,
1428 VG_(malloc), VG_(free));
1429 stringTable = VG_(OSet_Create)(/*keyOff*/0,
1430 stringCmp,
1431 VG_(malloc), VG_(free));
njn51d827b2005-05-09 01:02:08 +00001432}
1433
sewardj45f4e7c2005-09-27 19:20:21 +00001434VG_DETERMINE_INTERFACE_VERSION(cg_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00001435
njn25e49d8e72002-09-23 09:36:25 +00001436/*--------------------------------------------------------------------*/
njnf69f9452005-07-03 17:53:11 +00001437/*--- end ---*/
sewardj18d75132002-05-16 11:06:21 +00001438/*--------------------------------------------------------------------*/
njnd3bef4f2005-10-15 17:46:18 +00001439