blob: d750953b8daaaa314eae88b73d4a13ff77c18cf7 [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 {
njnfd9f6222005-10-16 00:17:37 +0000417 EventKind ekind; // All
418 InstrInfo* inode; // All; inode for this event's instruction
419 Int datasize; // Dr/Dw/Dm only
420 IRAtom* dataEA; // Dr/Dw/Dm only; IR ATOM ONLY
sewardj5155dec2005-10-12 10:09:23 +0000421 }
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
sewardj5155dec2005-10-12 10:09:23 +0000489static void showEvent ( Event* ev )
nethercote9313ac42004-07-06 21:54:20 +0000490{
sewardj5155dec2005-10-12 10:09:23 +0000491 switch (ev->ekind) {
492 case Event_Ir:
njnfd9f6222005-10-16 00:17:37 +0000493 VG_(printf)("Ir %p\n", ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000494 break;
495 case Event_Dr:
njnfd9f6222005-10-16 00:17:37 +0000496 VG_(printf)("Dr %p %d EA=", ev->inode, ev->datasize);
sewardj5155dec2005-10-12 10:09:23 +0000497 ppIRExpr(ev->dataEA);
498 VG_(printf)("\n");
499 break;
500 case Event_Dw:
njnfd9f6222005-10-16 00:17:37 +0000501 VG_(printf)("Dw %p %d EA=", ev->inode, ev->datasize);
sewardj5155dec2005-10-12 10:09:23 +0000502 ppIRExpr(ev->dataEA);
503 VG_(printf)("\n");
504 break;
505 case Event_Dm:
njnfd9f6222005-10-16 00:17:37 +0000506 VG_(printf)("Dm %p %d EA=", ev->inode, ev->datasize);
sewardj5155dec2005-10-12 10:09:23 +0000507 ppIRExpr(ev->dataEA);
508 VG_(printf)("\n");
509 break;
510 default:
511 tl_assert(0);
512 break;
513 }
njn6a3009b2005-03-20 00:20:06 +0000514}
515
njnfd9f6222005-10-16 00:17:37 +0000516// Reserve and initialise an InstrInfo for the first mention of a new insn.
517static
518InstrInfo* setup_InstrInfo ( CgState* cgs, Addr instr_addr, UInt instr_len )
njn6a3009b2005-03-20 00:20:06 +0000519{
njnd3bef4f2005-10-15 17:46:18 +0000520 InstrInfo* i_node;
sewardj5155dec2005-10-12 10:09:23 +0000521 tl_assert(cgs->bbInfo_i >= 0);
522 tl_assert(cgs->bbInfo_i < cgs->bbInfo->n_instrs);
523 i_node = &cgs->bbInfo->instrs[ cgs->bbInfo_i ];
njnfd9f6222005-10-16 00:17:37 +0000524 i_node->instr_addr = instr_addr;
525 i_node->instr_len = instr_len;
526 i_node->parent = get_lineCC(instr_addr);
sewardj5155dec2005-10-12 10:09:23 +0000527 cgs->bbInfo_i++;
528 return i_node;
529}
sewardj17a56bf2005-03-21 01:35:02 +0000530
sewardj17a56bf2005-03-21 01:35:02 +0000531
sewardj5155dec2005-10-12 10:09:23 +0000532/* Generate code for all outstanding memory events, and mark the queue
533 empty. Code is generated into cgs->bbOut, and this activity
534 'consumes' slots in cgs->bbInfo. */
njn6a3009b2005-03-20 00:20:06 +0000535
sewardj5155dec2005-10-12 10:09:23 +0000536static void flushEvents ( CgState* cgs )
537{
njnd3bef4f2005-10-15 17:46:18 +0000538 Int i, regparms;
539 Char* helperName;
540 void* helperAddr;
541 IRExpr** argv;
542 IRExpr* i_node_expr;
njnd3bef4f2005-10-15 17:46:18 +0000543 IRDirty* di;
njnc285dca2005-10-15 22:07:28 +0000544 Event* ev;
545 Event* ev2;
546 Event* ev3;
njn6a3009b2005-03-20 00:20:06 +0000547
sewardj5155dec2005-10-12 10:09:23 +0000548 i = 0;
549 while (i < cgs->events_used) {
njn6a3009b2005-03-20 00:20:06 +0000550
sewardj5155dec2005-10-12 10:09:23 +0000551 helperName = NULL;
552 helperAddr = NULL;
553 argv = NULL;
554 regparms = 0;
555
556 /* generate IR to notify event i and possibly the ones
557 immediately following it. */
558 tl_assert(i >= 0 && i < cgs->events_used);
njnc285dca2005-10-15 22:07:28 +0000559
560 ev = &cgs->events[i];
561 ev2 = ( i < cgs->events_used-1 ? &cgs->events[i+1] : NULL );
562 ev3 = ( i < cgs->events_used-2 ? &cgs->events[i+2] : NULL );
563
sewardj5155dec2005-10-12 10:09:23 +0000564 if (DEBUG_CG) {
565 VG_(printf)(" flush ");
njnc285dca2005-10-15 22:07:28 +0000566 showEvent( ev );
njn4f9c9342002-04-29 16:03:24 +0000567 }
sewardj5155dec2005-10-12 10:09:23 +0000568
njnfd9f6222005-10-16 00:17:37 +0000569 i_node_expr = mkIRExpr_HWord( (HWord)ev->inode );
sewardj5155dec2005-10-12 10:09:23 +0000570
571 /* Decide on helper fn to call and args to pass it, and advance
572 i appropriately. */
njnc285dca2005-10-15 22:07:28 +0000573 switch (ev->ekind) {
sewardj5155dec2005-10-12 10:09:23 +0000574 case Event_Ir:
575 /* Merge with a following Dr/Dm if it is from this insn. */
njnc285dca2005-10-15 22:07:28 +0000576 if (ev2 && (ev2->ekind == Event_Dr || ev2->ekind == Event_Dm)) {
njnfd9f6222005-10-16 00:17:37 +0000577 tl_assert(ev2->inode == ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000578 helperName = "log_1I_1Dr_cache_access";
579 helperAddr = &log_1I_1Dr_cache_access;
580 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000581 ev2->dataEA,
njnfd9f6222005-10-16 00:17:37 +0000582 mkIRExpr_HWord( ev2->datasize ) );
sewardj5155dec2005-10-12 10:09:23 +0000583 regparms = 3;
584 i += 2;
585 }
586 /* Merge with a following Dw if it is from this insn. */
587 else
njnc285dca2005-10-15 22:07:28 +0000588 if (ev2 && ev2->ekind == Event_Dw) {
njnfd9f6222005-10-16 00:17:37 +0000589 tl_assert(ev2->inode == ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000590 helperName = "log_1I_1Dw_cache_access";
591 helperAddr = &log_1I_1Dw_cache_access;
592 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000593 ev2->dataEA,
njnfd9f6222005-10-16 00:17:37 +0000594 mkIRExpr_HWord( ev2->datasize ) );
sewardj5155dec2005-10-12 10:09:23 +0000595 regparms = 3;
596 i += 2;
597 }
598 /* Merge with two following Irs if possible. */
599 else
njnc285dca2005-10-15 22:07:28 +0000600 if (ev2 && ev3 && ev2->ekind == Event_Ir && ev3->ekind == Event_Ir)
601 {
sewardj5155dec2005-10-12 10:09:23 +0000602 helperName = "log_3I_0D_cache_access";
603 helperAddr = &log_3I_0D_cache_access;
njnfd9f6222005-10-16 00:17:37 +0000604 argv = mkIRExprVec_3( i_node_expr,
605 mkIRExpr_HWord( (HWord)ev2->inode ),
606 mkIRExpr_HWord( (HWord)ev3->inode ) );
sewardj5155dec2005-10-12 10:09:23 +0000607 regparms = 3;
608 i += 3;
609 }
610 /* Merge with a following Ir if possible. */
611 else
njnc285dca2005-10-15 22:07:28 +0000612 if (ev2 && ev2->ekind == Event_Ir) {
sewardj5155dec2005-10-12 10:09:23 +0000613 helperName = "log_2I_0D_cache_access";
614 helperAddr = &log_2I_0D_cache_access;
njnfd9f6222005-10-16 00:17:37 +0000615 argv = mkIRExprVec_2( i_node_expr,
616 mkIRExpr_HWord( (HWord)ev2->inode ) );
sewardj5155dec2005-10-12 10:09:23 +0000617 regparms = 2;
618 i += 2;
619 }
620 /* No merging possible; emit as-is. */
621 else {
njnc285dca2005-10-15 22:07:28 +0000622 // Assertion: this Event_Ir must be the last one in the
623 // events buffer, otherwise it would have been merged with a
624 // following event.
625 tl_assert(!ev2 && !ev3);
sewardj5155dec2005-10-12 10:09:23 +0000626 helperName = "log_1I_0D_cache_access";
627 helperAddr = &log_1I_0D_cache_access;
628 argv = mkIRExprVec_1( i_node_expr );
629 regparms = 1;
630 i++;
631 }
632 break;
633 case Event_Dr:
634 case Event_Dm:
635 helperName = "log_0I_1Dr_cache_access";
636 helperAddr = &log_0I_1Dr_cache_access;
637 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000638 ev->dataEA,
njnfd9f6222005-10-16 00:17:37 +0000639 mkIRExpr_HWord( ev->datasize ) );
sewardj5155dec2005-10-12 10:09:23 +0000640 regparms = 3;
641 i++;
642 break;
643 case Event_Dw:
644 helperName = "log_0I_1Dw_cache_access";
645 helperAddr = &log_0I_1Dw_cache_access;
646 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000647 ev->dataEA,
njnfd9f6222005-10-16 00:17:37 +0000648 mkIRExpr_HWord( ev->datasize ) );
sewardj5155dec2005-10-12 10:09:23 +0000649 regparms = 3;
650 i++;
651 break;
652 default:
653 tl_assert(0);
654 }
655
656 /* Add the helper. */
657 tl_assert(helperName);
658 tl_assert(helperAddr);
659 tl_assert(argv);
660 di = unsafeIRDirty_0_N( regparms, helperName, helperAddr, argv);
661 addStmtToIRBB( cgs->bbOut, IRStmt_Dirty(di) );
njn4f9c9342002-04-29 16:03:24 +0000662 }
663
sewardj5155dec2005-10-12 10:09:23 +0000664 cgs->events_used = 0;
njn4f9c9342002-04-29 16:03:24 +0000665}
njn14d01ce2004-11-26 11:30:14 +0000666
njnfd9f6222005-10-16 00:17:37 +0000667static void addEvent_Ir ( CgState* cgs, InstrInfo* inode )
sewardj5155dec2005-10-12 10:09:23 +0000668{
669 Event* evt;
sewardj5155dec2005-10-12 10:09:23 +0000670 if (cgs->events_used == N_EVENTS)
671 flushEvents(cgs);
672 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
673 evt = &cgs->events[cgs->events_used];
njnfd9f6222005-10-16 00:17:37 +0000674 evt->ekind = Event_Ir;
675 evt->inode = inode;
676 evt->datasize = 0;
677 evt->dataEA = NULL; /*paranoia*/
sewardj5155dec2005-10-12 10:09:23 +0000678 cgs->events_used++;
679}
680
njnfd9f6222005-10-16 00:17:37 +0000681static
682void addEvent_Dr ( CgState* cgs, InstrInfo* inode, Int datasize, IRAtom* ea )
sewardj5155dec2005-10-12 10:09:23 +0000683{
njnfd9f6222005-10-16 00:17:37 +0000684 Event* evt;
sewardj5155dec2005-10-12 10:09:23 +0000685 tl_assert(isIRAtom(ea));
njnfd9f6222005-10-16 00:17:37 +0000686 tl_assert(datasize >= 1 && datasize <= MIN_LINE_SIZE);
687 if (cgs->events_used == N_EVENTS)
688 flushEvents(cgs);
689 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
690 evt = &cgs->events[cgs->events_used];
691 evt->ekind = Event_Dr;
692 evt->inode = inode;
693 evt->datasize = datasize;
694 evt->dataEA = ea;
695 cgs->events_used++;
696}
sewardj5155dec2005-10-12 10:09:23 +0000697
njnfd9f6222005-10-16 00:17:37 +0000698static
699void addEvent_Dw ( CgState* cgs, InstrInfo* inode, Int datasize, IRAtom* ea )
700{
701 Event* lastEvt;
702 Event* evt;
703
704 tl_assert(isIRAtom(ea));
705 tl_assert(datasize >= 1 && datasize <= MIN_LINE_SIZE);
706
707 /* Is it possible to merge this write with the preceding read? */
708 lastEvt = &cgs->events[cgs->events_used-1];
sewardj5155dec2005-10-12 10:09:23 +0000709 if (cgs->events_used > 0
njnfd9f6222005-10-16 00:17:37 +0000710 && lastEvt->ekind == Event_Dr
711 && lastEvt->datasize == datasize
712 && lastEvt->inode == inode
713 && eqIRAtom(lastEvt->dataEA, ea))
714 {
715 lastEvt->ekind = Event_Dm;
sewardj5155dec2005-10-12 10:09:23 +0000716 return;
717 }
718
719 /* No. Add as normal. */
720 if (cgs->events_used == N_EVENTS)
721 flushEvents(cgs);
722 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
njnfd9f6222005-10-16 00:17:37 +0000723 evt = &cgs->events[cgs->events_used];
724 evt->ekind = Event_Dw;
725 evt->inode = inode;
726 evt->datasize = datasize;
727 evt->dataEA = ea;
sewardj5155dec2005-10-12 10:09:23 +0000728 cgs->events_used++;
729}
730
731////////////////////////////////////////////////////////////
732
733
njn51d827b2005-05-09 01:02:08 +0000734static IRBB* cg_instrument ( IRBB* bbIn, VexGuestLayout* layout,
735 IRType gWordTy, IRType hWordTy )
njn14d01ce2004-11-26 11:30:14 +0000736{
njnfd9f6222005-10-16 00:17:37 +0000737 Int i, isize;
sewardj5155dec2005-10-12 10:09:23 +0000738 IRStmt* st;
739 Addr64 cia; /* address of current insn */
740 CgState cgs;
741 IRTypeEnv* tyenv = bbIn->tyenv;
njnfd9f6222005-10-16 00:17:37 +0000742 InstrInfo* curr_inode = NULL;
sewardj5155dec2005-10-12 10:09:23 +0000743
njn6a3009b2005-03-20 00:20:06 +0000744
sewardjd54babf2005-03-21 00:55:49 +0000745 if (gWordTy != hWordTy) {
746 /* We don't currently support this case. */
747 VG_(tool_panic)("host/guest word size mismatch");
748 }
749
njnfd9f6222005-10-16 00:17:37 +0000750 /* Set up BB, including copying of the where-next stuff. */
751 cgs.bbOut = emptyIRBB();
752 cgs.bbOut->tyenv = dopyIRTypeEnv(tyenv);
753 tl_assert( isIRAtom(bbIn->next) );
754 cgs.bbOut->next = dopyIRExpr(bbIn->next);
755 cgs.bbOut->jumpkind = bbIn->jumpkind;
njn6a3009b2005-03-20 00:20:06 +0000756
sewardj5155dec2005-10-12 10:09:23 +0000757 // Get the first statement, and initial cia from it
njn6a3009b2005-03-20 00:20:06 +0000758 i = 0;
759 tl_assert(bbIn->stmts_used > 0);
760 st = bbIn->stmts[0];
761 tl_assert(Ist_IMark == st->tag);
sewardj5155dec2005-10-12 10:09:23 +0000762 cia = st->Ist.IMark.addr;
njn6a3009b2005-03-20 00:20:06 +0000763
sewardj5155dec2005-10-12 10:09:23 +0000764 // Set up running state and get block info
765 cgs.events_used = 0;
sewardja3a29a52005-10-12 16:16:03 +0000766 cgs.bbInfo = get_BB_info(bbIn, (Addr)cia);
sewardj5155dec2005-10-12 10:09:23 +0000767 cgs.bbInfo_i = 0;
njn6a3009b2005-03-20 00:20:06 +0000768
sewardj5155dec2005-10-12 10:09:23 +0000769 if (DEBUG_CG)
770 VG_(printf)("\n\n---------- cg_instrument ----------\n");
njn6a3009b2005-03-20 00:20:06 +0000771
njnfd9f6222005-10-16 00:17:37 +0000772 // Traverse the block, initialising inodes, adding events and flushing as
773 // necessary.
sewardj5155dec2005-10-12 10:09:23 +0000774 for (i = 0; i < bbIn->stmts_used; i++) {
njn6a3009b2005-03-20 00:20:06 +0000775
sewardj5155dec2005-10-12 10:09:23 +0000776 st = bbIn->stmts[i];
777 tl_assert(isFlatIRStmt(st));
njnb3507ea2005-08-02 23:07:02 +0000778
sewardj5155dec2005-10-12 10:09:23 +0000779 switch (st->tag) {
780 case Ist_NoOp:
781 case Ist_AbiHint:
782 case Ist_Put:
783 case Ist_PutI:
784 case Ist_MFence:
785 break;
njn20677cc2005-08-12 23:47:51 +0000786
sewardj5155dec2005-10-12 10:09:23 +0000787 case Ist_IMark:
njnfd9f6222005-10-16 00:17:37 +0000788 cia = st->Ist.IMark.addr;
789 isize = st->Ist.IMark.len;
790
791 // If Vex fails to decode an instruction, the size will be zero.
792 // Pretend otherwise.
793 if (isize == 0) isize = VG_MIN_INSTR_SZB;
794
795 // Check size. XXX: broken for client requests!
796 tl_assert(VG_MIN_INSTR_SZB <= isize && isize <= VG_MAX_INSTR_SZB);
797
798 // Get space for and init the inode, record it as the current one.
799 // Subsequent Dr/Dw/Dm events from the same instruction will
800 // also use it.
801 curr_inode = setup_InstrInfo(&cgs, cia, isize);
802
803 addEvent_Ir( &cgs, curr_inode );
sewardj5155dec2005-10-12 10:09:23 +0000804 break;
805
806 case Ist_Tmp: {
807 IRExpr* data = st->Ist.Tmp.data;
808 if (data->tag == Iex_Load) {
809 IRExpr* aexpr = data->Iex.Load.addr;
sewardj5155dec2005-10-12 10:09:23 +0000810 // Note also, endianness info is ignored. I guess
811 // that's not interesting.
njnfd9f6222005-10-16 00:17:37 +0000812 addEvent_Dr( &cgs, curr_inode, sizeofIRType(data->Iex.Load.ty),
813 aexpr );
sewardj5155dec2005-10-12 10:09:23 +0000814 }
815 break;
njnb3507ea2005-08-02 23:07:02 +0000816 }
817
sewardj5155dec2005-10-12 10:09:23 +0000818 case Ist_Store: {
819 IRExpr* data = st->Ist.Store.data;
820 IRExpr* aexpr = st->Ist.Store.addr;
njnfd9f6222005-10-16 00:17:37 +0000821 addEvent_Dw( &cgs, curr_inode,
822 sizeofIRType(typeOfIRExpr(tyenv, data)), aexpr );
sewardj5155dec2005-10-12 10:09:23 +0000823 break;
824 }
njnb3507ea2005-08-02 23:07:02 +0000825
sewardj5155dec2005-10-12 10:09:23 +0000826 case Ist_Dirty: {
827 Int dataSize;
828 IRDirty* d = st->Ist.Dirty.details;
829 if (d->mFx != Ifx_None) {
njnfd9f6222005-10-16 00:17:37 +0000830 /* This dirty helper accesses memory. Collect the details. */
sewardj5155dec2005-10-12 10:09:23 +0000831 tl_assert(d->mAddr != NULL);
832 tl_assert(d->mSize != 0);
833 dataSize = d->mSize;
834 // Large (eg. 28B, 108B, 512B on x86) data-sized
835 // instructions will be done inaccurately, but they're
836 // very rare and this avoids errors from hitting more
837 // than two cache lines in the simulation.
838 if (dataSize > MIN_LINE_SIZE)
839 dataSize = MIN_LINE_SIZE;
840 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
njnfd9f6222005-10-16 00:17:37 +0000841 addEvent_Dr( &cgs, curr_inode, dataSize, d->mAddr );
sewardj5155dec2005-10-12 10:09:23 +0000842 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
njnfd9f6222005-10-16 00:17:37 +0000843 addEvent_Dw( &cgs, curr_inode, dataSize, d->mAddr );
sewardj5155dec2005-10-12 10:09:23 +0000844 } else {
845 tl_assert(d->mAddr == NULL);
846 tl_assert(d->mSize == 0);
847 }
848 break;
849 }
njn6a3009b2005-03-20 00:20:06 +0000850
sewardj5155dec2005-10-12 10:09:23 +0000851 case Ist_Exit:
852 /* We may never reach the next statement, so need to flush
853 all outstanding transactions now. */
854 flushEvents( &cgs );
855 break;
856
857 default:
858 tl_assert(0);
859 break;
njnb3507ea2005-08-02 23:07:02 +0000860 }
njn6a3009b2005-03-20 00:20:06 +0000861
sewardj5155dec2005-10-12 10:09:23 +0000862 /* Copy the original statement */
863 addStmtToIRBB( cgs.bbOut, st );
njn6a3009b2005-03-20 00:20:06 +0000864
sewardj5155dec2005-10-12 10:09:23 +0000865 if (DEBUG_CG) {
866 ppIRStmt(st);
867 VG_(printf)("\n");
868 }
869 }
870
871 /* At the end of the bb. Flush outstandings. */
sewardj5155dec2005-10-12 10:09:23 +0000872 flushEvents( &cgs );
873
sewardj5155dec2005-10-12 10:09:23 +0000874 /* done. stay sane ... */
875 tl_assert(cgs.bbInfo_i == cgs.bbInfo->n_instrs);
876
877 if (DEBUG_CG) {
878 VG_(printf)( "goto {");
879 ppIRJumpKind(bbIn->jumpkind);
880 VG_(printf)( "} ");
881 ppIRExpr( bbIn->next );
882 VG_(printf)( "}\n");
883 }
884
885 return cgs.bbOut;
njn14d01ce2004-11-26 11:30:14 +0000886}
njn4f9c9342002-04-29 16:03:24 +0000887
888/*------------------------------------------------------------*/
nethercoteb35a8b92004-09-11 16:45:27 +0000889/*--- Cache configuration ---*/
njn4f9c9342002-04-29 16:03:24 +0000890/*------------------------------------------------------------*/
891
sewardjb5f6f512005-03-10 23:59:00 +0000892#define UNDEFINED_CACHE { -1, -1, -1 }
njn25e49d8e72002-09-23 09:36:25 +0000893
894static cache_t clo_I1_cache = UNDEFINED_CACHE;
895static cache_t clo_D1_cache = UNDEFINED_CACHE;
896static cache_t clo_L2_cache = UNDEFINED_CACHE;
897
njn7cf0bd32002-06-08 13:36:03 +0000898/* Checks cache config is ok; makes it so if not. */
sewardj07133bf2002-06-13 10:25:56 +0000899static
njna1d1a642004-11-26 18:36:02 +0000900void check_cache(cache_t* cache, Char *name)
njn7cf0bd32002-06-08 13:36:03 +0000901{
902 /* First check they're all powers of two */
sewardj07133bf2002-06-13 10:25:56 +0000903 if (-1 == VG_(log2)(cache->size)) {
njn7cf0bd32002-06-08 13:36:03 +0000904 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000905 "error: %s size of %dB not a power of two; aborting.",
906 name, cache->size);
907 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000908 }
909
sewardj07133bf2002-06-13 10:25:56 +0000910 if (-1 == VG_(log2)(cache->assoc)) {
njn7cf0bd32002-06-08 13:36:03 +0000911 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000912 "error: %s associativity of %d not a power of two; aborting.",
913 name, cache->assoc);
914 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000915 }
916
sewardj07133bf2002-06-13 10:25:56 +0000917 if (-1 == VG_(log2)(cache->line_size)) {
njn7cf0bd32002-06-08 13:36:03 +0000918 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000919 "error: %s line size of %dB not a power of two; aborting.",
920 name, cache->line_size);
921 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000922 }
923
njn6a3009b2005-03-20 00:20:06 +0000924 // Then check line size >= 16 -- any smaller and a single instruction could
925 // straddle three cache lines, which breaks a simulation assertion and is
926 // stupid anyway.
njn7cf0bd32002-06-08 13:36:03 +0000927 if (cache->line_size < MIN_LINE_SIZE) {
928 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000929 "error: %s line size of %dB too small; aborting.",
930 name, cache->line_size);
931 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000932 }
933
934 /* Then check cache size > line size (causes seg faults if not). */
935 if (cache->size <= cache->line_size) {
936 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000937 "error: %s cache size of %dB <= line size of %dB; aborting.",
938 name, cache->size, cache->line_size);
939 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000940 }
941
942 /* Then check assoc <= (size / line size) (seg faults otherwise). */
943 if (cache->assoc > (cache->size / cache->line_size)) {
944 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000945 "warning: %s associativity > (size / line size); aborting.", name);
946 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000947 }
948}
949
sewardj07133bf2002-06-13 10:25:56 +0000950static
nethercoteb35a8b92004-09-11 16:45:27 +0000951void configure_caches(cache_t* I1c, cache_t* D1c, cache_t* L2c)
njn7cf0bd32002-06-08 13:36:03 +0000952{
nethercote9313ac42004-07-06 21:54:20 +0000953#define DEFINED(L) (-1 != L.size || -1 != L.assoc || -1 != L.line_size)
954
nethercoteb35a8b92004-09-11 16:45:27 +0000955 Int n_clos = 0;
nethercote9313ac42004-07-06 21:54:20 +0000956
nethercoteb35a8b92004-09-11 16:45:27 +0000957 // Count how many were defined on the command line.
958 if (DEFINED(clo_I1_cache)) { n_clos++; }
959 if (DEFINED(clo_D1_cache)) { n_clos++; }
960 if (DEFINED(clo_L2_cache)) { n_clos++; }
njn7cf0bd32002-06-08 13:36:03 +0000961
njna1d1a642004-11-26 18:36:02 +0000962 // Set the cache config (using auto-detection, if supported by the
963 // architecture)
njnaf839f52005-06-23 03:27:57 +0000964 VG_(configure_caches)( I1c, D1c, L2c, (3 == n_clos) );
sewardjb1a77a42002-07-13 13:31:20 +0000965
nethercote9313ac42004-07-06 21:54:20 +0000966 // Then replace with any defined on the command line.
nethercoteb35a8b92004-09-11 16:45:27 +0000967 if (DEFINED(clo_I1_cache)) { *I1c = clo_I1_cache; }
968 if (DEFINED(clo_D1_cache)) { *D1c = clo_D1_cache; }
969 if (DEFINED(clo_L2_cache)) { *L2c = clo_L2_cache; }
njn7cf0bd32002-06-08 13:36:03 +0000970
nethercote9313ac42004-07-06 21:54:20 +0000971 // Then check values and fix if not acceptable.
njna1d1a642004-11-26 18:36:02 +0000972 check_cache(I1c, "I1");
973 check_cache(D1c, "D1");
974 check_cache(L2c, "L2");
njn7cf0bd32002-06-08 13:36:03 +0000975
976 if (VG_(clo_verbosity) > 1) {
977 VG_(message)(Vg_UserMsg, "Cache configuration used:");
978 VG_(message)(Vg_UserMsg, " I1: %dB, %d-way, %dB lines",
979 I1c->size, I1c->assoc, I1c->line_size);
980 VG_(message)(Vg_UserMsg, " D1: %dB, %d-way, %dB lines",
981 D1c->size, D1c->assoc, D1c->line_size);
982 VG_(message)(Vg_UserMsg, " L2: %dB, %d-way, %dB lines",
983 L2c->size, L2c->assoc, L2c->line_size);
984 }
nethercote9313ac42004-07-06 21:54:20 +0000985#undef CMD_LINE_DEFINED
njn7cf0bd32002-06-08 13:36:03 +0000986}
987
njn4f9c9342002-04-29 16:03:24 +0000988/*------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +0000989/*--- cg_fini() and related function ---*/
njn4f9c9342002-04-29 16:03:24 +0000990/*------------------------------------------------------------*/
991
nethercote9313ac42004-07-06 21:54:20 +0000992// Total reads/writes/misses. Calculated during CC traversal at the end.
993// All auto-zeroed.
994static CC Ir_total;
995static CC Dr_total;
996static CC Dw_total;
997
998static Char* cachegrind_out_file;
999
nethercote9313ac42004-07-06 21:54:20 +00001000static void fprint_CC_table_and_calc_totals(void)
1001{
njnd3bef4f2005-10-15 17:46:18 +00001002 Int i, fd;
sewardj92645592005-07-23 09:18:34 +00001003 SysRes sres;
njnd3bef4f2005-10-15 17:46:18 +00001004 Char buf[512], *currFile = NULL, *currFn = NULL;
1005 LineCC* lineCC;
njn4f9c9342002-04-29 16:03:24 +00001006
njn25e49d8e72002-09-23 09:36:25 +00001007 VGP_PUSHCC(VgpCacheResults);
njn13f02932003-04-30 20:23:58 +00001008
sewardj92645592005-07-23 09:18:34 +00001009 sres = VG_(open)(cachegrind_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
1010 VKI_S_IRUSR|VKI_S_IWUSR);
1011 if (sres.isError) {
nethercote9313ac42004-07-06 21:54:20 +00001012 // If the file can't be opened for whatever reason (conflict
1013 // between multiple cachegrinded processes?), give up now.
njnee0e6a32005-04-24 00:21:01 +00001014 VG_(message)(Vg_UserMsg,
njn02bc4b82005-05-15 17:28:26 +00001015 "error: can't open cache simulation output file '%s'",
njnee0e6a32005-04-24 00:21:01 +00001016 cachegrind_out_file );
1017 VG_(message)(Vg_UserMsg,
1018 " ... so simulation results will be missing.");
sewardj0744b6c2002-12-11 00:45:42 +00001019 return;
sewardj92645592005-07-23 09:18:34 +00001020 } else {
1021 fd = sres.val;
sewardj0744b6c2002-12-11 00:45:42 +00001022 }
njn4f9c9342002-04-29 16:03:24 +00001023
nethercote9313ac42004-07-06 21:54:20 +00001024 // "desc:" lines (giving I1/D1/L2 cache configuration). The spaces after
1025 // the 2nd colon makes cg_annotate's output look nicer.
1026 VG_(sprintf)(buf, "desc: I1 cache: %s\n"
1027 "desc: D1 cache: %s\n"
1028 "desc: L2 cache: %s\n",
1029 I1.desc_line, D1.desc_line, L2.desc_line);
njn7cf0bd32002-06-08 13:36:03 +00001030 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njn4f9c9342002-04-29 16:03:24 +00001031
nethercote9313ac42004-07-06 21:54:20 +00001032 // "cmd:" line
njn4f9c9342002-04-29 16:03:24 +00001033 VG_(strcpy)(buf, "cmd:");
1034 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
sewardj45f4e7c2005-09-27 19:20:21 +00001035 if (VG_(args_the_exename)) {
1036 VG_(write)(fd, " ", 1);
1037 VG_(write)(fd, VG_(args_the_exename),
1038 VG_(strlen)( VG_(args_the_exename) ));
1039 }
1040 for (i = 0; i < VG_(args_for_client).used; i++) {
1041 if (VG_(args_for_client).strs[i]) {
1042 VG_(write)(fd, " ", 1);
1043 VG_(write)(fd, VG_(args_for_client).strs[i],
1044 VG_(strlen)(VG_(args_for_client).strs[i]));
1045 }
njn4f9c9342002-04-29 16:03:24 +00001046 }
nethercote9313ac42004-07-06 21:54:20 +00001047 // "events:" line
njn4f9c9342002-04-29 16:03:24 +00001048 VG_(sprintf)(buf, "\nevents: Ir I1mr I2mr Dr D1mr D2mr Dw D1mw D2mw\n");
1049 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1050
njnd3bef4f2005-10-15 17:46:18 +00001051 // Traverse every lineCC
1052 VG_(OSet_ResetIter)(CC_table);
1053 while ( (lineCC = VG_(OSet_Next)(CC_table)) ) {
1054 // If we've hit a new file, print a "fl=" line. Note that because
1055 // each string is stored exactly once in the string table, we can use
1056 // pointer comparison rather than strcmp() to test for equality, which
1057 // is good because most of the time the comparisons are equal and so
1058 // the whole strings would have to be traversed.
1059 if ( lineCC->loc.file != currFile ) {
1060 currFile = lineCC->loc.file;
1061 VG_(sprintf)(buf, "fl=%s\n", currFile);
njn4f9c9342002-04-29 16:03:24 +00001062 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njnd3bef4f2005-10-15 17:46:18 +00001063 distinct_files++;
njn4f9c9342002-04-29 16:03:24 +00001064 }
njnd3bef4f2005-10-15 17:46:18 +00001065 // If we've hit a new function, print a "fn=" line.
1066 if ( lineCC->loc.fn != currFn ) {
1067 currFn = lineCC->loc.fn;
1068 VG_(sprintf)(buf, "fn=%s\n", currFn);
1069 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1070 distinct_fns++;
1071 }
1072
1073 // Print the LineCC
1074 VG_(sprintf)(buf, "%u %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
1075 lineCC->loc.line,
1076 lineCC->Ir.a, lineCC->Ir.m1, lineCC->Ir.m2,
1077 lineCC->Dr.a, lineCC->Dr.m1, lineCC->Dr.m2,
1078 lineCC->Dw.a, lineCC->Dw.m1, lineCC->Dw.m2);
1079 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1080
1081 // Update summary stats
1082 Ir_total.a += lineCC->Ir.a;
1083 Ir_total.m1 += lineCC->Ir.m1;
1084 Ir_total.m2 += lineCC->Ir.m2;
1085 Dr_total.a += lineCC->Dr.a;
1086 Dr_total.m1 += lineCC->Dr.m1;
1087 Dr_total.m2 += lineCC->Dr.m2;
1088 Dw_total.a += lineCC->Dw.a;
1089 Dw_total.m1 += lineCC->Dw.m1;
1090 Dw_total.m2 += lineCC->Dw.m2;
1091
1092 distinct_lines++;
njn4f9c9342002-04-29 16:03:24 +00001093 }
1094
nethercote9313ac42004-07-06 21:54:20 +00001095 // Summary stats must come after rest of table, since we calculate them
1096 // during traversal. */
njn4f9c9342002-04-29 16:03:24 +00001097 VG_(sprintf)(buf, "summary: "
nethercote9313ac42004-07-06 21:54:20 +00001098 "%llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
njn4f9c9342002-04-29 16:03:24 +00001099 Ir_total.a, Ir_total.m1, Ir_total.m2,
1100 Dr_total.a, Dr_total.m1, Dr_total.m2,
1101 Dw_total.a, Dw_total.m1, Dw_total.m2);
1102 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1103 VG_(close)(fd);
1104}
1105
njn607adfc2003-09-30 14:15:44 +00001106static UInt ULong_width(ULong n)
njn4f9c9342002-04-29 16:03:24 +00001107{
njn607adfc2003-09-30 14:15:44 +00001108 UInt w = 0;
1109 while (n > 0) {
1110 n = n / 10;
1111 w++;
njn4f9c9342002-04-29 16:03:24 +00001112 }
njn607adfc2003-09-30 14:15:44 +00001113 return w + (w-1)/3; // add space for commas
njn4f9c9342002-04-29 16:03:24 +00001114}
1115
njn51d827b2005-05-09 01:02:08 +00001116static void cg_fini(Int exitcode)
njn4f9c9342002-04-29 16:03:24 +00001117{
njn0103de52005-10-10 16:49:01 +00001118 static Char buf1[128], buf2[128], buf3[128], fmt [128];
njn607adfc2003-09-30 14:15:44 +00001119
njn4f9c9342002-04-29 16:03:24 +00001120 CC D_total;
njn1d021fa2002-05-02 13:56:34 +00001121 ULong L2_total_m, L2_total_mr, L2_total_mw,
1122 L2_total, L2_total_r, L2_total_w;
njn4f9c9342002-04-29 16:03:24 +00001123 Int l1, l2, l3;
1124 Int p;
1125
nethercote9313ac42004-07-06 21:54:20 +00001126 fprint_CC_table_and_calc_totals();
njn4f9c9342002-04-29 16:03:24 +00001127
njn7cf0bd32002-06-08 13:36:03 +00001128 if (VG_(clo_verbosity) == 0)
1129 return;
1130
njn4f9c9342002-04-29 16:03:24 +00001131 /* I cache results. Use the I_refs value to determine the first column
1132 * width. */
njn607adfc2003-09-30 14:15:44 +00001133 l1 = ULong_width(Ir_total.a);
1134 l2 = ULong_width(Dr_total.a);
1135 l3 = ULong_width(Dw_total.a);
njn4f9c9342002-04-29 16:03:24 +00001136
njn607adfc2003-09-30 14:15:44 +00001137 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001138 VG_(sprintf)(fmt, "%%s %%,%dllu", l1);
njnd3bef4f2005-10-15 17:46:18 +00001139
njn607adfc2003-09-30 14:15:44 +00001140 VG_(message)(Vg_UserMsg, fmt, "I refs: ", Ir_total.a);
1141 VG_(message)(Vg_UserMsg, fmt, "I1 misses: ", Ir_total.m1);
1142 VG_(message)(Vg_UserMsg, fmt, "L2i misses: ", Ir_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001143
1144 p = 100;
1145
njn25e49d8e72002-09-23 09:36:25 +00001146 if (0 == Ir_total.a) Ir_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001147 VG_(percentify)(Ir_total.m1, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001148 VG_(message)(Vg_UserMsg, "I1 miss rate: %s", buf1);
njnd3bef4f2005-10-15 17:46:18 +00001149
njn856c54e2005-06-26 18:43:40 +00001150 VG_(percentify)(Ir_total.m2, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001151 VG_(message)(Vg_UserMsg, "L2i miss rate: %s", buf1);
1152 VG_(message)(Vg_UserMsg, "");
1153
1154 /* D cache results. Use the D_refs.rd and D_refs.wr values to determine the
1155 * width of columns 2 & 3. */
1156 D_total.a = Dr_total.a + Dw_total.a;
1157 D_total.m1 = Dr_total.m1 + Dw_total.m1;
1158 D_total.m2 = Dr_total.m2 + Dw_total.m2;
njnd3bef4f2005-10-15 17:46:18 +00001159
njn607adfc2003-09-30 14:15:44 +00001160 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001161 VG_(sprintf)(fmt, "%%s %%,%dllu (%%,%dllu rd + %%,%dllu wr)", l1, l2, l3);
njn4f9c9342002-04-29 16:03:24 +00001162
njn607adfc2003-09-30 14:15:44 +00001163 VG_(message)(Vg_UserMsg, fmt, "D refs: ",
1164 D_total.a, Dr_total.a, Dw_total.a);
1165 VG_(message)(Vg_UserMsg, fmt, "D1 misses: ",
1166 D_total.m1, Dr_total.m1, Dw_total.m1);
1167 VG_(message)(Vg_UserMsg, fmt, "L2d misses: ",
1168 D_total.m2, Dr_total.m2, Dw_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001169
1170 p = 10;
njnd3bef4f2005-10-15 17:46:18 +00001171
njn25e49d8e72002-09-23 09:36:25 +00001172 if (0 == D_total.a) D_total.a = 1;
1173 if (0 == Dr_total.a) Dr_total.a = 1;
1174 if (0 == Dw_total.a) Dw_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001175 VG_(percentify)( D_total.m1, D_total.a, 1, l1+1, buf1);
1176 VG_(percentify)(Dr_total.m1, Dr_total.a, 1, l2+1, buf2);
1177 VG_(percentify)(Dw_total.m1, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001178 VG_(message)(Vg_UserMsg, "D1 miss rate: %s (%s + %s )", buf1, buf2,buf3);
1179
njn856c54e2005-06-26 18:43:40 +00001180 VG_(percentify)( D_total.m2, D_total.a, 1, l1+1, buf1);
1181 VG_(percentify)(Dr_total.m2, Dr_total.a, 1, l2+1, buf2);
1182 VG_(percentify)(Dw_total.m2, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001183 VG_(message)(Vg_UserMsg, "L2d miss rate: %s (%s + %s )", buf1, buf2,buf3);
1184 VG_(message)(Vg_UserMsg, "");
1185
1186 /* L2 overall results */
njn1d021fa2002-05-02 13:56:34 +00001187
1188 L2_total = Dr_total.m1 + Dw_total.m1 + Ir_total.m1;
1189 L2_total_r = Dr_total.m1 + Ir_total.m1;
1190 L2_total_w = Dw_total.m1;
njn607adfc2003-09-30 14:15:44 +00001191 VG_(message)(Vg_UserMsg, fmt, "L2 refs: ",
1192 L2_total, L2_total_r, L2_total_w);
njn1d021fa2002-05-02 13:56:34 +00001193
njn4f9c9342002-04-29 16:03:24 +00001194 L2_total_m = Dr_total.m2 + Dw_total.m2 + Ir_total.m2;
1195 L2_total_mr = Dr_total.m2 + Ir_total.m2;
1196 L2_total_mw = Dw_total.m2;
njn607adfc2003-09-30 14:15:44 +00001197 VG_(message)(Vg_UserMsg, fmt, "L2 misses: ",
1198 L2_total_m, L2_total_mr, L2_total_mw);
njn4f9c9342002-04-29 16:03:24 +00001199
njn856c54e2005-06-26 18:43:40 +00001200 VG_(percentify)(L2_total_m, (Ir_total.a + D_total.a), 1, l1+1, buf1);
1201 VG_(percentify)(L2_total_mr, (Ir_total.a + Dr_total.a), 1, l2+1, buf2);
1202 VG_(percentify)(L2_total_mw, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001203 VG_(message)(Vg_UserMsg, "L2 miss rate: %s (%s + %s )", buf1, buf2,buf3);
njnd3bef4f2005-10-15 17:46:18 +00001204
njn4f9c9342002-04-29 16:03:24 +00001205
nethercote9313ac42004-07-06 21:54:20 +00001206 // Various stats
njn4f9c9342002-04-29 16:03:24 +00001207 if (VG_(clo_verbosity) > 1) {
njnd3bef4f2005-10-15 17:46:18 +00001208 Int debug_lookups = full_debugs + fn_debugs +
1209 file_line_debugs + no_debugs;
1210
njn4f9c9342002-04-29 16:03:24 +00001211 VG_(message)(Vg_DebugMsg, "");
njnd3bef4f2005-10-15 17:46:18 +00001212 VG_(message)(Vg_DebugMsg, "cachegrind: distinct files: %d", distinct_files);
1213 VG_(message)(Vg_DebugMsg, "cachegrind: distinct fns: %d", distinct_fns);
1214 VG_(message)(Vg_DebugMsg, "cachegrind: distinct lines: %d", distinct_lines);
1215 VG_(message)(Vg_DebugMsg, "cachegrind: distinct instrs:%d", distinct_instrs);
1216 VG_(message)(Vg_DebugMsg, "cachegrind: debug lookups : %d", debug_lookups);
1217 VG_(message)(Vg_DebugMsg, "cachegrind: with full info:%3d%% (%d)",
1218 full_debugs * 100 / debug_lookups, full_debugs);
1219 VG_(message)(Vg_DebugMsg, "cachegrind: with file/line info:%3d%% (%d)",
1220 file_line_debugs * 100 / debug_lookups, file_line_debugs);
1221 VG_(message)(Vg_DebugMsg, "cachegrind: with fn name info:%3d%% (%d)",
1222 fn_debugs * 100 / debug_lookups, fn_debugs);
1223 VG_(message)(Vg_DebugMsg, "cachegrind: with zero info:%3d%% (%d)",
1224 no_debugs * 100 / debug_lookups, no_debugs);
1225 VG_(message)(Vg_DebugMsg, "cachegrind: BBs Retranslated: %d",
1226 BB_retranslations);
1227 VG_(message)(Vg_DebugMsg, "cachegrind: string table size: %u",
1228 VG_(OSet_Size)(stringTable));
1229 VG_(message)(Vg_DebugMsg, "cachegrind: CC table size: %u",
1230 VG_(OSet_Size)(CC_table));
1231 VG_(message)(Vg_DebugMsg, "cachegrind: InstrInfo table size: %u",
1232 VG_(OSet_Size)(instrInfoTable));
njn4f9c9342002-04-29 16:03:24 +00001233 }
njn25e49d8e72002-09-23 09:36:25 +00001234 VGP_POPCC(VgpCacheResults);
njn4f9c9342002-04-29 16:03:24 +00001235}
1236
nethercote9313ac42004-07-06 21:54:20 +00001237/*--------------------------------------------------------------------*/
1238/*--- Discarding BB info ---*/
1239/*--------------------------------------------------------------------*/
sewardj18d75132002-05-16 11:06:21 +00001240
sewardja3a29a52005-10-12 16:16:03 +00001241// Called when a translation is removed from the translation cache for
1242// any reason at all: to free up space, because the guest code was
1243// unmapped or modified, or for any arbitrary reason.
sewardj5155dec2005-10-12 10:09:23 +00001244static void cg_discard_basic_block_info ( VexGuestExtents vge )
sewardj18d75132002-05-16 11:06:21 +00001245{
njnd3bef4f2005-10-15 17:46:18 +00001246 BB_info* bbInfo;
njn4294fd42002-06-05 14:41:10 +00001247
sewardj5155dec2005-10-12 10:09:23 +00001248 tl_assert(vge.n_used > 0);
1249
1250 if (DEBUG_CG)
1251 VG_(printf)( "discard_basic_block_info: %p, %llu\n",
1252 (void*)(Addr)vge.base[0], (ULong)vge.len[0]);
njn4294fd42002-06-05 14:41:10 +00001253
nethercote9313ac42004-07-06 21:54:20 +00001254 // Get BB info, remove from table, free BB info. Simple!
njnd3bef4f2005-10-15 17:46:18 +00001255 bbInfo = VG_(OSet_Remove)(instrInfoTable, &(vge.base[0]));
njn6a3009b2005-03-20 00:20:06 +00001256 tl_assert(NULL != bbInfo);
njnd3bef4f2005-10-15 17:46:18 +00001257 VG_(OSet_FreeNode)(instrInfoTable, bbInfo);
sewardj18d75132002-05-16 11:06:21 +00001258}
1259
1260/*--------------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001261/*--- Command line processing ---*/
1262/*--------------------------------------------------------------------*/
1263
njn0103de52005-10-10 16:49:01 +00001264static void parse_cache_opt ( cache_t* cache, Char* opt )
njn25e49d8e72002-09-23 09:36:25 +00001265{
njn0103de52005-10-10 16:49:01 +00001266 Int i = 0, i2, i3;
njn25e49d8e72002-09-23 09:36:25 +00001267
nethercote9313ac42004-07-06 21:54:20 +00001268 // Option argument looks like "65536,2,64".
1269 // Find commas, replace with NULs to make three independent
1270 // strings, then extract numbers, put NULs back. Yuck.
njn25e49d8e72002-09-23 09:36:25 +00001271 while (VG_(isdigit)(opt[i])) i++;
1272 if (',' == opt[i]) {
1273 opt[i++] = '\0';
1274 i2 = i;
1275 } else goto bad;
1276 while (VG_(isdigit)(opt[i])) i++;
1277 if (',' == opt[i]) {
1278 opt[i++] = '\0';
1279 i3 = i;
1280 } else goto bad;
1281 while (VG_(isdigit)(opt[i])) i++;
1282 if ('\0' != opt[i]) goto bad;
1283
nethercote9313ac42004-07-06 21:54:20 +00001284 cache->size = (Int)VG_(atoll)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001285 cache->assoc = (Int)VG_(atoll)(opt + i2);
1286 cache->line_size = (Int)VG_(atoll)(opt + i3);
1287
nethercote9313ac42004-07-06 21:54:20 +00001288 opt[i2-1] = ',';
1289 opt[i3-1] = ',';
njn25e49d8e72002-09-23 09:36:25 +00001290 return;
1291
1292 bad:
nethercote9313ac42004-07-06 21:54:20 +00001293 VG_(bad_option)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001294}
1295
njn51d827b2005-05-09 01:02:08 +00001296static Bool cg_process_cmd_line_option(Char* arg)
njn25e49d8e72002-09-23 09:36:25 +00001297{
nethercote9313ac42004-07-06 21:54:20 +00001298 // 5 is length of "--I1="
njn39c86652003-05-21 10:13:39 +00001299 if (VG_CLO_STREQN(5, arg, "--I1="))
nethercote9313ac42004-07-06 21:54:20 +00001300 parse_cache_opt(&clo_I1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001301 else if (VG_CLO_STREQN(5, arg, "--D1="))
nethercote9313ac42004-07-06 21:54:20 +00001302 parse_cache_opt(&clo_D1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001303 else if (VG_CLO_STREQN(5, arg, "--L2="))
nethercote9313ac42004-07-06 21:54:20 +00001304 parse_cache_opt(&clo_L2_cache, &arg[5]);
njn25e49d8e72002-09-23 09:36:25 +00001305 else
1306 return False;
1307
1308 return True;
1309}
1310
njn51d827b2005-05-09 01:02:08 +00001311static void cg_print_usage(void)
njn25e49d8e72002-09-23 09:36:25 +00001312{
njn3e884182003-04-15 13:03:23 +00001313 VG_(printf)(
njn25e49d8e72002-09-23 09:36:25 +00001314" --I1=<size>,<assoc>,<line_size> set I1 cache manually\n"
1315" --D1=<size>,<assoc>,<line_size> set D1 cache manually\n"
njn3e884182003-04-15 13:03:23 +00001316" --L2=<size>,<assoc>,<line_size> set L2 cache manually\n"
1317 );
1318}
1319
njn51d827b2005-05-09 01:02:08 +00001320static void cg_print_debug_usage(void)
njn3e884182003-04-15 13:03:23 +00001321{
1322 VG_(printf)(
1323" (none)\n"
1324 );
njn25e49d8e72002-09-23 09:36:25 +00001325}
1326
1327/*--------------------------------------------------------------------*/
1328/*--- Setup ---*/
1329/*--------------------------------------------------------------------*/
1330
njn51d827b2005-05-09 01:02:08 +00001331static void cg_post_clo_init(void)
njn25e49d8e72002-09-23 09:36:25 +00001332{
1333 cache_t I1c, D1c, L2c;
njn25e49d8e72002-09-23 09:36:25 +00001334
nethercoteb35a8b92004-09-11 16:45:27 +00001335 configure_caches(&I1c, &D1c, &L2c);
njn25e49d8e72002-09-23 09:36:25 +00001336
1337 cachesim_I1_initcache(I1c);
1338 cachesim_D1_initcache(D1c);
1339 cachesim_L2_initcache(L2c);
1340
njn31066fd2005-03-26 00:42:02 +00001341 VG_(register_profile_event)(VgpGetLineCC, "get-lineCC");
1342 VG_(register_profile_event)(VgpCacheSimulate, "cache-simulate");
1343 VG_(register_profile_event)(VgpCacheResults, "cache-results");
njn25e49d8e72002-09-23 09:36:25 +00001344}
1345
njn57ca7ab2005-06-21 23:44:58 +00001346static Char base_dir[VKI_PATH_MAX];
1347
njn51d827b2005-05-09 01:02:08 +00001348static void cg_pre_clo_init(void)
1349{
njn51d827b2005-05-09 01:02:08 +00001350 VG_(details_name) ("Cachegrind");
1351 VG_(details_version) (NULL);
1352 VG_(details_description) ("an I1/D1/L2 cache profiler");
1353 VG_(details_copyright_author)(
1354 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote et al.");
1355 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj5155dec2005-10-12 10:09:23 +00001356 VG_(details_avg_translation_sizeB) ( 245 );
njn51d827b2005-05-09 01:02:08 +00001357
1358 VG_(basic_tool_funcs) (cg_post_clo_init,
1359 cg_instrument,
1360 cg_fini);
1361
1362 VG_(needs_basic_block_discards)(cg_discard_basic_block_info);
1363 VG_(needs_command_line_options)(cg_process_cmd_line_option,
1364 cg_print_usage,
1365 cg_print_debug_usage);
1366
1367 /* Get working directory */
njn57ca7ab2005-06-21 23:44:58 +00001368 tl_assert( VG_(getcwd)(base_dir, VKI_PATH_MAX) );
njn51d827b2005-05-09 01:02:08 +00001369
1370 /* Block is big enough for dir name + cachegrind.out.<pid> */
1371 cachegrind_out_file = VG_(malloc)((VG_(strlen)(base_dir) + 32)*sizeof(Char));
1372 VG_(sprintf)(cachegrind_out_file, "%s/cachegrind.out.%d",
1373 base_dir, VG_(getpid)());
njn51d827b2005-05-09 01:02:08 +00001374
njnd3bef4f2005-10-15 17:46:18 +00001375 CC_table = VG_(OSet_Create)(offsetof(LineCC, loc),
1376 cmp_CodeLoc_LineCC,
1377 VG_(malloc), VG_(free));
1378 instrInfoTable = VG_(OSet_Create)(offsetof(BB_info, BB_addr),
1379 NULL,
1380 VG_(malloc), VG_(free));
1381 stringTable = VG_(OSet_Create)(/*keyOff*/0,
1382 stringCmp,
1383 VG_(malloc), VG_(free));
njn51d827b2005-05-09 01:02:08 +00001384}
1385
sewardj45f4e7c2005-09-27 19:20:21 +00001386VG_DETERMINE_INTERFACE_VERSION(cg_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00001387
njn25e49d8e72002-09-23 09:36:25 +00001388/*--------------------------------------------------------------------*/
njnf69f9452005-07-03 17:53:11 +00001389/*--- end ---*/
sewardj18d75132002-05-16 11:06:21 +00001390/*--------------------------------------------------------------------*/
njnd3bef4f2005-10-15 17:46:18 +00001391