blob: d0ef0a1effb1056df9c223a5b3c3b6dfe8f18faf [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
sewardj9ebd6e02007-01-08 06:01:59 +000011 Copyright (C) 2002-2007 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"
sewardj4cfea4f2006-10-14 19:26:10 +000033#include "pub_tool_vki.h"
njnea27e462005-05-31 02:38:09 +000034#include "pub_tool_debuginfo.h"
njn97405b22005-06-02 03:39:33 +000035#include "pub_tool_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000036#include "pub_tool_libcassert.h"
njneb8896b2005-06-04 20:03:55 +000037#include "pub_tool_libcfile.h"
njn36a20fa2005-06-03 03:08:39 +000038#include "pub_tool_libcprint.h"
njnf39e9a32005-06-12 02:43:17 +000039#include "pub_tool_libcproc.h"
njnf536bbb2005-06-13 04:21:38 +000040#include "pub_tool_machine.h"
njn717cde52005-05-10 02:47:21 +000041#include "pub_tool_mallocfree.h"
njn20242342005-05-16 23:31:24 +000042#include "pub_tool_options.h"
njnd3bef4f2005-10-15 17:46:18 +000043#include "pub_tool_oset.h"
njn43b9a8a2005-05-10 04:37:01 +000044#include "pub_tool_tooliface.h"
sewardj14c7cc52007-02-25 15:08:24 +000045#include "pub_tool_xarray.h"
sewardj45f4e7c2005-09-27 19:20:21 +000046#include "pub_tool_clientstate.h"
sewardj5bb86822005-12-23 12:47:42 +000047#include "pub_tool_machine.h" // VG_(fnptr_to_fnentry)
njn25e49d8e72002-09-23 09:36:25 +000048
nethercoteb35a8b92004-09-11 16:45:27 +000049#include "cg_arch.h"
nethercote27fc1da2004-01-04 16:56:57 +000050#include "cg_sim.c"
njn4f9c9342002-04-29 16:03:24 +000051
njn25e49d8e72002-09-23 09:36:25 +000052/*------------------------------------------------------------*/
53/*--- Constants ---*/
54/*------------------------------------------------------------*/
njn4f9c9342002-04-29 16:03:24 +000055
sewardj5155dec2005-10-12 10:09:23 +000056/* Set to 1 for very verbose debugging */
57#define DEBUG_CG 0
58
nethercote9313ac42004-07-06 21:54:20 +000059#define MIN_LINE_SIZE 16
njnd3bef4f2005-10-15 17:46:18 +000060#define FILE_LEN VKI_PATH_MAX
nethercote9313ac42004-07-06 21:54:20 +000061#define FN_LEN 256
njn7cf0bd32002-06-08 13:36:03 +000062
63/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +000064/*--- Types and Data Structures ---*/
njn4f9c9342002-04-29 16:03:24 +000065/*------------------------------------------------------------*/
66
67typedef struct _CC CC;
68struct _CC {
69 ULong a;
70 ULong m1;
71 ULong m2;
72};
73
nethercote9313ac42004-07-06 21:54:20 +000074//------------------------------------------------------------
75// Primary data structure #1: CC table
76// - Holds the per-source-line hit/miss stats, grouped by file/function/line.
njnd3bef4f2005-10-15 17:46:18 +000077// - an ordered set of CCs. CC indexing done by file/function/line (as
78// determined from the instrAddr).
nethercote9313ac42004-07-06 21:54:20 +000079// - Traversed for dumping stats at end in file/func/line hierarchy.
njn4f9c9342002-04-29 16:03:24 +000080
njnd3bef4f2005-10-15 17:46:18 +000081typedef struct {
82 Char* file;
83 Char* fn;
84 Int line;
85}
86CodeLoc;
njn4f9c9342002-04-29 16:03:24 +000087
njnd3bef4f2005-10-15 17:46:18 +000088typedef struct _LineCC LineCC;
89struct _LineCC {
90 CodeLoc loc;
91 CC Ir;
92 CC Dr;
93 CC Dw;
njn4f9c9342002-04-29 16:03:24 +000094};
95
njnd3bef4f2005-10-15 17:46:18 +000096// First compare file, then fn, then line.
njnafa12262005-12-24 03:10:56 +000097static Word cmp_CodeLoc_LineCC(void *vloc, void *vcc)
njnd3bef4f2005-10-15 17:46:18 +000098{
njnafa12262005-12-24 03:10:56 +000099 Word res;
njnd3bef4f2005-10-15 17:46:18 +0000100 CodeLoc* a = (CodeLoc*)vloc;
101 CodeLoc* b = &(((LineCC*)vcc)->loc);
njn4f9c9342002-04-29 16:03:24 +0000102
njnd3bef4f2005-10-15 17:46:18 +0000103 res = VG_(strcmp)(a->file, b->file);
104 if (0 != res)
105 return res;
njn4f9c9342002-04-29 16:03:24 +0000106
njnd3bef4f2005-10-15 17:46:18 +0000107 res = VG_(strcmp)(a->fn, b->fn);
108 if (0 != res)
109 return res;
110
111 return a->line - b->line;
112}
113
114static OSet* CC_table;
njn4f9c9342002-04-29 16:03:24 +0000115
nethercote9313ac42004-07-06 21:54:20 +0000116//------------------------------------------------------------
njnd3bef4f2005-10-15 17:46:18 +0000117// Primary data structure #2: InstrInfo table
nethercote9313ac42004-07-06 21:54:20 +0000118// - Holds the cached info about each instr that is used for simulation.
sewardj0b9d74a2006-12-24 02:24:11 +0000119// - table(SB_start_addr, list(InstrInfo))
120// - For each SB, each InstrInfo in the list holds info about the
njnd3bef4f2005-10-15 17:46:18 +0000121// instruction (instrLen, instrAddr, etc), plus a pointer to its line
nethercote9313ac42004-07-06 21:54:20 +0000122// CC. This node is what's passed to the simulation function.
sewardj0b9d74a2006-12-24 02:24:11 +0000123// - When SBs are discarded the relevant list(instr_details) is freed.
nethercote9313ac42004-07-06 21:54:20 +0000124
njnd3bef4f2005-10-15 17:46:18 +0000125typedef struct _InstrInfo InstrInfo;
126struct _InstrInfo {
nethercoteca1f2dc2004-07-21 08:49:02 +0000127 Addr instr_addr;
njn6a3009b2005-03-20 00:20:06 +0000128 UChar instr_len;
njnd3bef4f2005-10-15 17:46:18 +0000129 LineCC* parent; // parent line-CC
nethercote9313ac42004-07-06 21:54:20 +0000130};
131
sewardj0b9d74a2006-12-24 02:24:11 +0000132typedef struct _SB_info SB_info;
133struct _SB_info {
134 Addr SB_addr; // key; MUST BE FIRST
njnd3bef4f2005-10-15 17:46:18 +0000135 Int n_instrs;
136 InstrInfo instrs[0];
nethercote9313ac42004-07-06 21:54:20 +0000137};
138
njnd3bef4f2005-10-15 17:46:18 +0000139static OSet* instrInfoTable;
140
141//------------------------------------------------------------
142// Secondary data structure: string table
143// - holds strings, avoiding dups
144// - used for filenames and function names, each of which will be
145// pointed to by one or more CCs.
146// - it also allows equality checks just by pointer comparison, which
147// is good when printing the output file at the end.
148
149static OSet* stringTable;
nethercote9313ac42004-07-06 21:54:20 +0000150
151//------------------------------------------------------------
152// Stats
sewardj4f29ddf2002-05-03 22:29:04 +0000153static Int distinct_files = 0;
154static Int distinct_fns = 0;
nethercote9313ac42004-07-06 21:54:20 +0000155static Int distinct_lines = 0;
sewardj4f29ddf2002-05-03 22:29:04 +0000156static Int distinct_instrs = 0;
nethercote9313ac42004-07-06 21:54:20 +0000157
njnd3bef4f2005-10-15 17:46:18 +0000158static Int full_debugs = 0;
159static Int file_line_debugs = 0;
160static Int fn_debugs = 0;
161static Int no_debugs = 0;
njn4f9c9342002-04-29 16:03:24 +0000162
nethercote9313ac42004-07-06 21:54:20 +0000163/*------------------------------------------------------------*/
njnd3bef4f2005-10-15 17:46:18 +0000164/*--- String table operations ---*/
165/*------------------------------------------------------------*/
166
njnafa12262005-12-24 03:10:56 +0000167static Word stringCmp( void* key, void* elem )
njnd3bef4f2005-10-15 17:46:18 +0000168{
169 return VG_(strcmp)(*(Char**)key, *(Char**)elem);
170}
171
172// Get a permanent string; either pull it out of the string table if it's
173// been encountered before, or dup it and put it into the string table.
174static Char* get_perm_string(Char* s)
175{
176 Char** s_ptr = VG_(OSet_Lookup)(stringTable, &s);
177 if (s_ptr) {
178 return *s_ptr;
179 } else {
180 Char** s_node = VG_(OSet_AllocNode)(stringTable, sizeof(Char*));
181 *s_node = VG_(strdup)(s);
182 VG_(OSet_Insert)(stringTable, s_node);
183 return *s_node;
184 }
185}
186
187/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +0000188/*--- CC table operations ---*/
189/*------------------------------------------------------------*/
njn4294fd42002-06-05 14:41:10 +0000190
nethercote9313ac42004-07-06 21:54:20 +0000191static void get_debug_info(Addr instr_addr, Char file[FILE_LEN],
192 Char fn[FN_LEN], Int* line)
njn4f9c9342002-04-29 16:03:24 +0000193{
sewardj7cee6f92005-06-13 17:39:06 +0000194 Bool found_file_line = VG_(get_filename_linenum)(
195 instr_addr,
196 file, FILE_LEN,
197 NULL, 0, NULL,
198 line
199 );
nethercote9313ac42004-07-06 21:54:20 +0000200 Bool found_fn = VG_(get_fnname)(instr_addr, fn, FN_LEN);
njn4f9c9342002-04-29 16:03:24 +0000201
nethercote9313ac42004-07-06 21:54:20 +0000202 if (!found_file_line) {
203 VG_(strcpy)(file, "???");
204 *line = 0;
205 }
206 if (!found_fn) {
207 VG_(strcpy)(fn, "???");
208 }
209 if (found_file_line) {
njnd3bef4f2005-10-15 17:46:18 +0000210 if (found_fn) full_debugs++;
211 else file_line_debugs++;
nethercote9313ac42004-07-06 21:54:20 +0000212 } else {
njnd3bef4f2005-10-15 17:46:18 +0000213 if (found_fn) fn_debugs++;
214 else no_debugs++;
njn4f9c9342002-04-29 16:03:24 +0000215 }
216}
217
nethercote9313ac42004-07-06 21:54:20 +0000218// Do a three step traversal: by file, then fn, then line.
njnd3bef4f2005-10-15 17:46:18 +0000219// Returns a pointer to the line CC, creates a new one if necessary.
220static LineCC* get_lineCC(Addr origAddr)
nethercote9313ac42004-07-06 21:54:20 +0000221{
nethercote9313ac42004-07-06 21:54:20 +0000222 Char file[FILE_LEN], fn[FN_LEN];
223 Int line;
njnd3bef4f2005-10-15 17:46:18 +0000224 CodeLoc loc;
225 LineCC* lineCC;
nethercote9313ac42004-07-06 21:54:20 +0000226
njn6a3009b2005-03-20 00:20:06 +0000227 get_debug_info(origAddr, file, fn, &line);
nethercote9313ac42004-07-06 21:54:20 +0000228
njnd3bef4f2005-10-15 17:46:18 +0000229 loc.file = file;
230 loc.fn = fn;
231 loc.line = line;
njn4f9c9342002-04-29 16:03:24 +0000232
njnd3bef4f2005-10-15 17:46:18 +0000233 lineCC = VG_(OSet_Lookup)(CC_table, &loc);
234 if (!lineCC) {
235 // Allocate and zero a new node.
236 lineCC = VG_(OSet_AllocNode)(CC_table, sizeof(LineCC));
237 lineCC->loc.file = get_perm_string(loc.file);
238 lineCC->loc.fn = get_perm_string(loc.fn);
239 lineCC->loc.line = loc.line;
njn0a8db5c2007-04-02 03:11:41 +0000240 lineCC->Ir.a = 0;
241 lineCC->Ir.m1 = 0;
242 lineCC->Ir.m2 = 0;
243 lineCC->Dr.a = 0;
244 lineCC->Dr.m1 = 0;
245 lineCC->Dr.m2 = 0;
246 lineCC->Dw.a = 0;
247 lineCC->Dw.m1 = 0;
248 lineCC->Dw.m2 = 0;
njnd3bef4f2005-10-15 17:46:18 +0000249 VG_(OSet_Insert)(CC_table, lineCC);
njn4f9c9342002-04-29 16:03:24 +0000250 }
nethercote9313ac42004-07-06 21:54:20 +0000251
njnd3bef4f2005-10-15 17:46:18 +0000252 return lineCC;
njn4f9c9342002-04-29 16:03:24 +0000253}
254
255/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +0000256/*--- Cache simulation functions ---*/
njn4f9c9342002-04-29 16:03:24 +0000257/*------------------------------------------------------------*/
258
njnaf839f52005-06-23 03:27:57 +0000259static VG_REGPARM(1)
njnd3bef4f2005-10-15 17:46:18 +0000260void log_1I_0D_cache_access(InstrInfo* n)
njn25e49d8e72002-09-23 09:36:25 +0000261{
sewardj5155dec2005-10-12 10:09:23 +0000262 //VG_(printf)("1I_0D : CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n",
263 // n, n->instr_addr, n->instr_len);
njn6a3009b2005-03-20 00:20:06 +0000264 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000265 &n->parent->Ir.m1, &n->parent->Ir.m2);
266 n->parent->Ir.a++;
njn25e49d8e72002-09-23 09:36:25 +0000267}
268
njnaf839f52005-06-23 03:27:57 +0000269static VG_REGPARM(2)
njnd3bef4f2005-10-15 17:46:18 +0000270void log_2I_0D_cache_access(InstrInfo* n, InstrInfo* n2)
njn25e49d8e72002-09-23 09:36:25 +0000271{
sewardj5155dec2005-10-12 10:09:23 +0000272 //VG_(printf)("2I_0D : CC1addr=0x%010lx, i1addr=0x%010lx, i1size=%lu\n"
273 // " CC2addr=0x%010lx, i2addr=0x%010lx, i2size=%lu\n",
274 // n, n->instr_addr, n->instr_len,
275 // n2, n2->instr_addr, n2->instr_len);
sewardj5155dec2005-10-12 10:09:23 +0000276 cachesim_I1_doref(n->instr_addr, n->instr_len,
277 &n->parent->Ir.m1, &n->parent->Ir.m2);
278 n->parent->Ir.a++;
279 cachesim_I1_doref(n2->instr_addr, n2->instr_len,
280 &n2->parent->Ir.m1, &n2->parent->Ir.m2);
281 n2->parent->Ir.a++;
sewardj5155dec2005-10-12 10:09:23 +0000282}
283
284static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000285void log_3I_0D_cache_access(InstrInfo* n, InstrInfo* n2, InstrInfo* n3)
sewardj5155dec2005-10-12 10:09:23 +0000286{
287 //VG_(printf)("3I_0D : CC1addr=0x%010lx, i1addr=0x%010lx, i1size=%lu\n"
288 // " CC2addr=0x%010lx, i2addr=0x%010lx, i2size=%lu\n"
289 // " CC3addr=0x%010lx, i3addr=0x%010lx, i3size=%lu\n",
290 // n, n->instr_addr, n->instr_len,
291 // n2, n2->instr_addr, n2->instr_len,
292 // n3, n3->instr_addr, n3->instr_len);
sewardj5155dec2005-10-12 10:09:23 +0000293 cachesim_I1_doref(n->instr_addr, n->instr_len,
294 &n->parent->Ir.m1, &n->parent->Ir.m2);
295 n->parent->Ir.a++;
296 cachesim_I1_doref(n2->instr_addr, n2->instr_len,
297 &n2->parent->Ir.m1, &n2->parent->Ir.m2);
298 n2->parent->Ir.a++;
299 cachesim_I1_doref(n3->instr_addr, n3->instr_len,
300 &n3->parent->Ir.m1, &n3->parent->Ir.m2);
301 n3->parent->Ir.a++;
sewardj5155dec2005-10-12 10:09:23 +0000302}
303
304static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000305void log_1I_1Dr_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
sewardj5155dec2005-10-12 10:09:23 +0000306{
307 //VG_(printf)("1I_1Dr: CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n"
308 // " daddr=0x%010lx, dsize=%lu\n",
309 // n, n->instr_addr, n->instr_len, data_addr, data_size);
njn6a3009b2005-03-20 00:20:06 +0000310 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000311 &n->parent->Ir.m1, &n->parent->Ir.m2);
312 n->parent->Ir.a++;
njn25e49d8e72002-09-23 09:36:25 +0000313
sewardj5155dec2005-10-12 10:09:23 +0000314 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000315 &n->parent->Dr.m1, &n->parent->Dr.m2);
316 n->parent->Dr.a++;
njn25e49d8e72002-09-23 09:36:25 +0000317}
318
sewardj5155dec2005-10-12 10:09:23 +0000319static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000320void log_1I_1Dw_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
njn25e49d8e72002-09-23 09:36:25 +0000321{
sewardj5155dec2005-10-12 10:09:23 +0000322 //VG_(printf)("1I_1Dw: CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n"
323 // " daddr=0x%010lx, dsize=%lu\n",
324 // n, n->instr_addr, n->instr_len, data_addr, data_size);
njn6a3009b2005-03-20 00:20:06 +0000325 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000326 &n->parent->Ir.m1, &n->parent->Ir.m2);
327 n->parent->Ir.a++;
328
sewardj5155dec2005-10-12 10:09:23 +0000329 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000330 &n->parent->Dw.m1, &n->parent->Dw.m2);
331 n->parent->Dw.a++;
njn25e49d8e72002-09-23 09:36:25 +0000332}
333
njnaf839f52005-06-23 03:27:57 +0000334static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000335void log_0I_1Dr_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
njn25e49d8e72002-09-23 09:36:25 +0000336{
sewardj5155dec2005-10-12 10:09:23 +0000337 //VG_(printf)("0I_1Dr: CCaddr=0x%010lx, daddr=0x%010lx, dsize=%lu\n",
338 // n, data_addr, data_size);
sewardj5155dec2005-10-12 10:09:23 +0000339 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000340 &n->parent->Dr.m1, &n->parent->Dr.m2);
341 n->parent->Dr.a++;
sewardj5155dec2005-10-12 10:09:23 +0000342}
343
344static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000345void log_0I_1Dw_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
sewardj5155dec2005-10-12 10:09:23 +0000346{
347 //VG_(printf)("0I_1Dw: CCaddr=0x%010lx, daddr=0x%010lx, dsize=%lu\n",
348 // n, data_addr, data_size);
sewardj5155dec2005-10-12 10:09:23 +0000349 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000350 &n->parent->Dw.m1, &n->parent->Dw.m2);
351 n->parent->Dw.a++;
njn25e49d8e72002-09-23 09:36:25 +0000352}
353
nethercote9313ac42004-07-06 21:54:20 +0000354/*------------------------------------------------------------*/
sewardj5155dec2005-10-12 10:09:23 +0000355/*--- Instrumentation types and structures ---*/
356/*------------------------------------------------------------*/
357
358/* Maintain an ordered list of memory events which are outstanding, in
359 the sense that no IR has yet been generated to do the relevant
360 helper calls. The BB is scanned top to bottom and memory events
361 are added to the end of the list, merging with the most recent
362 notified event where possible (Dw immediately following Dr and
363 having the same size and EA can be merged).
364
365 This merging is done so that for architectures which have
366 load-op-store instructions (x86, amd64), the insn is treated as if
367 it makes just one memory reference (a modify), rather than two (a
368 read followed by a write at the same address).
369
370 At various points the list will need to be flushed, that is, IR
371 generated from it. That must happen before any possible exit from
372 the block (the end, or an IRStmt_Exit). Flushing also takes place
373 when there is no space to add a new event.
374
375 If we require the simulation statistics to be up to date with
376 respect to possible memory exceptions, then the list would have to
377 be flushed before each memory reference. That would however lose
378 performance by inhibiting event-merging during flushing.
379
380 Flushing the list consists of walking it start to end and emitting
381 instrumentation IR for each event, in the order in which they
382 appear. It may be possible to emit a single call for two adjacent
383 events in order to reduce the number of helper function calls made.
384 For example, it could well be profitable to handle two adjacent Ir
385 events with a single helper call. */
386
387typedef
388 IRExpr
389 IRAtom;
390
391typedef
sewardj20edebf2005-10-12 10:29:40 +0000392 enum { Event_Ir, Event_Dr, Event_Dw, Event_Dm }
sewardj5155dec2005-10-12 10:09:23 +0000393 EventKind;
394
395typedef
396 struct {
njnfd9f6222005-10-16 00:17:37 +0000397 EventKind ekind; // All
398 InstrInfo* inode; // All; inode for this event's instruction
399 Int datasize; // Dr/Dw/Dm only
400 IRAtom* dataEA; // Dr/Dw/Dm only; IR ATOM ONLY
sewardj5155dec2005-10-12 10:09:23 +0000401 }
402 Event;
403
404/* Up to this many unnotified events are allowed. Number is
405 arbitrary. Larger numbers allow more event merging to occur, but
406 potentially induce more spilling due to extending live ranges of
407 address temporaries. */
408#define N_EVENTS 16
409
410
411/* A struct which holds all the running state during instrumentation.
412 Mostly to avoid passing loads of parameters everywhere. */
413typedef
414 struct {
415 /* The current outstanding-memory-event list. */
416 Event events[N_EVENTS];
417 Int events_used;
418
njnd3bef4f2005-10-15 17:46:18 +0000419 /* The array of InstrInfo bins for the BB. */
sewardj0b9d74a2006-12-24 02:24:11 +0000420 SB_info* sbInfo;
sewardj5155dec2005-10-12 10:09:23 +0000421
njnd3bef4f2005-10-15 17:46:18 +0000422 /* Number InstrInfo bins 'used' so far. */
sewardj0b9d74a2006-12-24 02:24:11 +0000423 Int sbInfo_i;
sewardj5155dec2005-10-12 10:09:23 +0000424
sewardj0b9d74a2006-12-24 02:24:11 +0000425 /* The output SB being constructed. */
426 IRSB* sbOut;
sewardj5155dec2005-10-12 10:09:23 +0000427 }
428 CgState;
429
430
sewardj5155dec2005-10-12 10:09:23 +0000431/*------------------------------------------------------------*/
432/*--- Instrumentation main ---*/
nethercote9313ac42004-07-06 21:54:20 +0000433/*------------------------------------------------------------*/
434
sewardj4ba057c2005-10-18 12:04:18 +0000435// Note that origAddr is the real origAddr, not the address of the first
436// instruction in the block (they can be different due to redirection).
nethercote564b2b02004-08-07 15:54:53 +0000437static
sewardj0b9d74a2006-12-24 02:24:11 +0000438SB_info* get_SB_info(IRSB* sbIn, Addr origAddr)
nethercote9313ac42004-07-06 21:54:20 +0000439{
njn4bd67b52005-08-11 00:47:10 +0000440 Int i, n_instrs;
441 IRStmt* st;
sewardj0b9d74a2006-12-24 02:24:11 +0000442 SB_info* sbInfo;
njnd3bef4f2005-10-15 17:46:18 +0000443
sewardj0b9d74a2006-12-24 02:24:11 +0000444 // Count number of original instrs in SB
njn6a3009b2005-03-20 00:20:06 +0000445 n_instrs = 0;
sewardj0b9d74a2006-12-24 02:24:11 +0000446 for (i = 0; i < sbIn->stmts_used; i++) {
447 st = sbIn->stmts[i];
njn6a3009b2005-03-20 00:20:06 +0000448 if (Ist_IMark == st->tag) n_instrs++;
nethercote9313ac42004-07-06 21:54:20 +0000449 }
450
njnf7d26092005-10-12 16:45:17 +0000451 // Check that we don't have an entry for this BB in the instr-info table.
452 // If this assertion fails, there has been some screwup: some
453 // translations must have been discarded but Cachegrind hasn't discarded
454 // the corresponding entries in the instr-info table.
sewardj0b9d74a2006-12-24 02:24:11 +0000455 sbInfo = VG_(OSet_Lookup)(instrInfoTable, &origAddr);
456 tl_assert(NULL == sbInfo);
sewardja3a29a52005-10-12 16:16:03 +0000457
njnd3bef4f2005-10-15 17:46:18 +0000458 // BB never translated before (at this address, at least; could have
459 // been unloaded and then reloaded elsewhere in memory)
sewardj0b9d74a2006-12-24 02:24:11 +0000460 sbInfo = VG_(OSet_AllocNode)(instrInfoTable,
461 sizeof(SB_info) + n_instrs*sizeof(InstrInfo));
462 sbInfo->SB_addr = origAddr;
463 sbInfo->n_instrs = n_instrs;
464 VG_(OSet_Insert)( instrInfoTable, sbInfo );
sewardja3a29a52005-10-12 16:16:03 +0000465 distinct_instrs++;
466
sewardj0b9d74a2006-12-24 02:24:11 +0000467 return sbInfo;
nethercote9313ac42004-07-06 21:54:20 +0000468}
njn6a3009b2005-03-20 00:20:06 +0000469
nethercote9313ac42004-07-06 21:54:20 +0000470
sewardj5155dec2005-10-12 10:09:23 +0000471static void showEvent ( Event* ev )
nethercote9313ac42004-07-06 21:54:20 +0000472{
sewardj5155dec2005-10-12 10:09:23 +0000473 switch (ev->ekind) {
474 case Event_Ir:
njnfd9f6222005-10-16 00:17:37 +0000475 VG_(printf)("Ir %p\n", ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000476 break;
477 case Event_Dr:
njnfd9f6222005-10-16 00:17:37 +0000478 VG_(printf)("Dr %p %d EA=", ev->inode, ev->datasize);
sewardj5155dec2005-10-12 10:09:23 +0000479 ppIRExpr(ev->dataEA);
480 VG_(printf)("\n");
481 break;
482 case Event_Dw:
njnfd9f6222005-10-16 00:17:37 +0000483 VG_(printf)("Dw %p %d EA=", ev->inode, ev->datasize);
sewardj5155dec2005-10-12 10:09:23 +0000484 ppIRExpr(ev->dataEA);
485 VG_(printf)("\n");
486 break;
487 case Event_Dm:
njnfd9f6222005-10-16 00:17:37 +0000488 VG_(printf)("Dm %p %d EA=", ev->inode, ev->datasize);
sewardj5155dec2005-10-12 10:09:23 +0000489 ppIRExpr(ev->dataEA);
490 VG_(printf)("\n");
491 break;
492 default:
493 tl_assert(0);
494 break;
495 }
njn6a3009b2005-03-20 00:20:06 +0000496}
497
njnfd9f6222005-10-16 00:17:37 +0000498// Reserve and initialise an InstrInfo for the first mention of a new insn.
499static
500InstrInfo* setup_InstrInfo ( CgState* cgs, Addr instr_addr, UInt instr_len )
njn6a3009b2005-03-20 00:20:06 +0000501{
njnd3bef4f2005-10-15 17:46:18 +0000502 InstrInfo* i_node;
sewardj0b9d74a2006-12-24 02:24:11 +0000503 tl_assert(cgs->sbInfo_i >= 0);
504 tl_assert(cgs->sbInfo_i < cgs->sbInfo->n_instrs);
505 i_node = &cgs->sbInfo->instrs[ cgs->sbInfo_i ];
njnfd9f6222005-10-16 00:17:37 +0000506 i_node->instr_addr = instr_addr;
507 i_node->instr_len = instr_len;
508 i_node->parent = get_lineCC(instr_addr);
sewardj0b9d74a2006-12-24 02:24:11 +0000509 cgs->sbInfo_i++;
sewardj5155dec2005-10-12 10:09:23 +0000510 return i_node;
511}
sewardj17a56bf2005-03-21 01:35:02 +0000512
sewardj17a56bf2005-03-21 01:35:02 +0000513
sewardj5155dec2005-10-12 10:09:23 +0000514/* Generate code for all outstanding memory events, and mark the queue
515 empty. Code is generated into cgs->bbOut, and this activity
sewardj0b9d74a2006-12-24 02:24:11 +0000516 'consumes' slots in cgs->sbInfo. */
njn6a3009b2005-03-20 00:20:06 +0000517
sewardj5155dec2005-10-12 10:09:23 +0000518static void flushEvents ( CgState* cgs )
519{
njnd3bef4f2005-10-15 17:46:18 +0000520 Int i, regparms;
521 Char* helperName;
522 void* helperAddr;
523 IRExpr** argv;
524 IRExpr* i_node_expr;
njnd3bef4f2005-10-15 17:46:18 +0000525 IRDirty* di;
njnc285dca2005-10-15 22:07:28 +0000526 Event* ev;
527 Event* ev2;
528 Event* ev3;
njn6a3009b2005-03-20 00:20:06 +0000529
sewardj5155dec2005-10-12 10:09:23 +0000530 i = 0;
531 while (i < cgs->events_used) {
njn6a3009b2005-03-20 00:20:06 +0000532
sewardj5155dec2005-10-12 10:09:23 +0000533 helperName = NULL;
534 helperAddr = NULL;
535 argv = NULL;
536 regparms = 0;
537
538 /* generate IR to notify event i and possibly the ones
539 immediately following it. */
540 tl_assert(i >= 0 && i < cgs->events_used);
njnc285dca2005-10-15 22:07:28 +0000541
542 ev = &cgs->events[i];
543 ev2 = ( i < cgs->events_used-1 ? &cgs->events[i+1] : NULL );
544 ev3 = ( i < cgs->events_used-2 ? &cgs->events[i+2] : NULL );
545
sewardj5155dec2005-10-12 10:09:23 +0000546 if (DEBUG_CG) {
547 VG_(printf)(" flush ");
njnc285dca2005-10-15 22:07:28 +0000548 showEvent( ev );
njn4f9c9342002-04-29 16:03:24 +0000549 }
sewardj5155dec2005-10-12 10:09:23 +0000550
njnfd9f6222005-10-16 00:17:37 +0000551 i_node_expr = mkIRExpr_HWord( (HWord)ev->inode );
sewardj5155dec2005-10-12 10:09:23 +0000552
553 /* Decide on helper fn to call and args to pass it, and advance
554 i appropriately. */
njnc285dca2005-10-15 22:07:28 +0000555 switch (ev->ekind) {
sewardj5155dec2005-10-12 10:09:23 +0000556 case Event_Ir:
557 /* Merge with a following Dr/Dm if it is from this insn. */
njnc285dca2005-10-15 22:07:28 +0000558 if (ev2 && (ev2->ekind == Event_Dr || ev2->ekind == Event_Dm)) {
njnfd9f6222005-10-16 00:17:37 +0000559 tl_assert(ev2->inode == ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000560 helperName = "log_1I_1Dr_cache_access";
561 helperAddr = &log_1I_1Dr_cache_access;
562 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000563 ev2->dataEA,
njnfd9f6222005-10-16 00:17:37 +0000564 mkIRExpr_HWord( ev2->datasize ) );
sewardj5155dec2005-10-12 10:09:23 +0000565 regparms = 3;
566 i += 2;
567 }
568 /* Merge with a following Dw if it is from this insn. */
569 else
njnc285dca2005-10-15 22:07:28 +0000570 if (ev2 && ev2->ekind == Event_Dw) {
njnfd9f6222005-10-16 00:17:37 +0000571 tl_assert(ev2->inode == ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000572 helperName = "log_1I_1Dw_cache_access";
573 helperAddr = &log_1I_1Dw_cache_access;
574 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000575 ev2->dataEA,
njnfd9f6222005-10-16 00:17:37 +0000576 mkIRExpr_HWord( ev2->datasize ) );
sewardj5155dec2005-10-12 10:09:23 +0000577 regparms = 3;
578 i += 2;
579 }
580 /* Merge with two following Irs if possible. */
581 else
njnc285dca2005-10-15 22:07:28 +0000582 if (ev2 && ev3 && ev2->ekind == Event_Ir && ev3->ekind == Event_Ir)
583 {
sewardj5155dec2005-10-12 10:09:23 +0000584 helperName = "log_3I_0D_cache_access";
585 helperAddr = &log_3I_0D_cache_access;
njnfd9f6222005-10-16 00:17:37 +0000586 argv = mkIRExprVec_3( i_node_expr,
587 mkIRExpr_HWord( (HWord)ev2->inode ),
588 mkIRExpr_HWord( (HWord)ev3->inode ) );
sewardj5155dec2005-10-12 10:09:23 +0000589 regparms = 3;
590 i += 3;
591 }
592 /* Merge with a following Ir if possible. */
593 else
njnc285dca2005-10-15 22:07:28 +0000594 if (ev2 && ev2->ekind == Event_Ir) {
sewardj5155dec2005-10-12 10:09:23 +0000595 helperName = "log_2I_0D_cache_access";
596 helperAddr = &log_2I_0D_cache_access;
njnfd9f6222005-10-16 00:17:37 +0000597 argv = mkIRExprVec_2( i_node_expr,
598 mkIRExpr_HWord( (HWord)ev2->inode ) );
sewardj5155dec2005-10-12 10:09:23 +0000599 regparms = 2;
600 i += 2;
601 }
602 /* No merging possible; emit as-is. */
603 else {
njnc285dca2005-10-15 22:07:28 +0000604 // Assertion: this Event_Ir must be the last one in the
605 // events buffer, otherwise it would have been merged with a
606 // following event.
607 tl_assert(!ev2 && !ev3);
sewardj5155dec2005-10-12 10:09:23 +0000608 helperName = "log_1I_0D_cache_access";
609 helperAddr = &log_1I_0D_cache_access;
610 argv = mkIRExprVec_1( i_node_expr );
611 regparms = 1;
612 i++;
613 }
614 break;
615 case Event_Dr:
616 case Event_Dm:
617 helperName = "log_0I_1Dr_cache_access";
618 helperAddr = &log_0I_1Dr_cache_access;
619 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000620 ev->dataEA,
njnfd9f6222005-10-16 00:17:37 +0000621 mkIRExpr_HWord( ev->datasize ) );
sewardj5155dec2005-10-12 10:09:23 +0000622 regparms = 3;
623 i++;
624 break;
625 case Event_Dw:
626 helperName = "log_0I_1Dw_cache_access";
627 helperAddr = &log_0I_1Dw_cache_access;
628 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000629 ev->dataEA,
njnfd9f6222005-10-16 00:17:37 +0000630 mkIRExpr_HWord( ev->datasize ) );
sewardj5155dec2005-10-12 10:09:23 +0000631 regparms = 3;
632 i++;
633 break;
634 default:
635 tl_assert(0);
636 }
637
638 /* Add the helper. */
639 tl_assert(helperName);
640 tl_assert(helperAddr);
641 tl_assert(argv);
sewardj5bb86822005-12-23 12:47:42 +0000642 di = unsafeIRDirty_0_N( regparms,
643 helperName, VG_(fnptr_to_fnentry)( helperAddr ),
644 argv );
sewardj0b9d74a2006-12-24 02:24:11 +0000645 addStmtToIRSB( cgs->sbOut, IRStmt_Dirty(di) );
njn4f9c9342002-04-29 16:03:24 +0000646 }
647
sewardj5155dec2005-10-12 10:09:23 +0000648 cgs->events_used = 0;
njn4f9c9342002-04-29 16:03:24 +0000649}
njn14d01ce2004-11-26 11:30:14 +0000650
njnfd9f6222005-10-16 00:17:37 +0000651static void addEvent_Ir ( CgState* cgs, InstrInfo* inode )
sewardj5155dec2005-10-12 10:09:23 +0000652{
653 Event* evt;
sewardj5155dec2005-10-12 10:09:23 +0000654 if (cgs->events_used == N_EVENTS)
655 flushEvents(cgs);
656 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
657 evt = &cgs->events[cgs->events_used];
njnfd9f6222005-10-16 00:17:37 +0000658 evt->ekind = Event_Ir;
659 evt->inode = inode;
660 evt->datasize = 0;
661 evt->dataEA = NULL; /*paranoia*/
sewardj5155dec2005-10-12 10:09:23 +0000662 cgs->events_used++;
663}
664
njnfd9f6222005-10-16 00:17:37 +0000665static
666void addEvent_Dr ( CgState* cgs, InstrInfo* inode, Int datasize, IRAtom* ea )
sewardj5155dec2005-10-12 10:09:23 +0000667{
njnfd9f6222005-10-16 00:17:37 +0000668 Event* evt;
sewardj5155dec2005-10-12 10:09:23 +0000669 tl_assert(isIRAtom(ea));
njnfd9f6222005-10-16 00:17:37 +0000670 tl_assert(datasize >= 1 && datasize <= MIN_LINE_SIZE);
671 if (cgs->events_used == N_EVENTS)
672 flushEvents(cgs);
673 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
674 evt = &cgs->events[cgs->events_used];
675 evt->ekind = Event_Dr;
676 evt->inode = inode;
677 evt->datasize = datasize;
678 evt->dataEA = ea;
679 cgs->events_used++;
680}
sewardj5155dec2005-10-12 10:09:23 +0000681
njnfd9f6222005-10-16 00:17:37 +0000682static
683void addEvent_Dw ( CgState* cgs, InstrInfo* inode, Int datasize, IRAtom* ea )
684{
685 Event* lastEvt;
686 Event* evt;
687
688 tl_assert(isIRAtom(ea));
689 tl_assert(datasize >= 1 && datasize <= MIN_LINE_SIZE);
690
691 /* Is it possible to merge this write with the preceding read? */
692 lastEvt = &cgs->events[cgs->events_used-1];
sewardj5155dec2005-10-12 10:09:23 +0000693 if (cgs->events_used > 0
njnfd9f6222005-10-16 00:17:37 +0000694 && lastEvt->ekind == Event_Dr
695 && lastEvt->datasize == datasize
696 && lastEvt->inode == inode
697 && eqIRAtom(lastEvt->dataEA, ea))
698 {
699 lastEvt->ekind = Event_Dm;
sewardj5155dec2005-10-12 10:09:23 +0000700 return;
701 }
702
703 /* No. Add as normal. */
704 if (cgs->events_used == N_EVENTS)
705 flushEvents(cgs);
706 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
njnfd9f6222005-10-16 00:17:37 +0000707 evt = &cgs->events[cgs->events_used];
708 evt->ekind = Event_Dw;
709 evt->inode = inode;
710 evt->datasize = datasize;
711 evt->dataEA = ea;
sewardj5155dec2005-10-12 10:09:23 +0000712 cgs->events_used++;
713}
714
715////////////////////////////////////////////////////////////
716
717
sewardj4ba057c2005-10-18 12:04:18 +0000718static
sewardj0b9d74a2006-12-24 02:24:11 +0000719IRSB* cg_instrument ( VgCallbackClosure* closure,
720 IRSB* sbIn,
sewardj461df9c2006-01-17 02:06:39 +0000721 VexGuestLayout* layout,
722 VexGuestExtents* vge,
sewardj4ba057c2005-10-18 12:04:18 +0000723 IRType gWordTy, IRType hWordTy )
njn14d01ce2004-11-26 11:30:14 +0000724{
njnfd9f6222005-10-16 00:17:37 +0000725 Int i, isize;
sewardj5155dec2005-10-12 10:09:23 +0000726 IRStmt* st;
727 Addr64 cia; /* address of current insn */
728 CgState cgs;
sewardj0b9d74a2006-12-24 02:24:11 +0000729 IRTypeEnv* tyenv = sbIn->tyenv;
njnfd9f6222005-10-16 00:17:37 +0000730 InstrInfo* curr_inode = NULL;
sewardj5155dec2005-10-12 10:09:23 +0000731
sewardjd54babf2005-03-21 00:55:49 +0000732 if (gWordTy != hWordTy) {
733 /* We don't currently support this case. */
734 VG_(tool_panic)("host/guest word size mismatch");
735 }
736
sewardj0b9d74a2006-12-24 02:24:11 +0000737 // Set up new SB
738 cgs.sbOut = deepCopyIRSBExceptStmts(sbIn);
njn6a3009b2005-03-20 00:20:06 +0000739
sewardja9f538c2005-10-23 12:06:55 +0000740 // Copy verbatim any IR preamble preceding the first IMark
njn6a3009b2005-03-20 00:20:06 +0000741 i = 0;
sewardj0b9d74a2006-12-24 02:24:11 +0000742 while (i < sbIn->stmts_used && sbIn->stmts[i]->tag != Ist_IMark) {
743 addStmtToIRSB( cgs.sbOut, sbIn->stmts[i] );
sewardja9f538c2005-10-23 12:06:55 +0000744 i++;
745 }
746
747 // Get the first statement, and initial cia from it
sewardj0b9d74a2006-12-24 02:24:11 +0000748 tl_assert(sbIn->stmts_used > 0);
749 tl_assert(i < sbIn->stmts_used);
750 st = sbIn->stmts[i];
njn6a3009b2005-03-20 00:20:06 +0000751 tl_assert(Ist_IMark == st->tag);
sewardj5155dec2005-10-12 10:09:23 +0000752 cia = st->Ist.IMark.addr;
njn6a3009b2005-03-20 00:20:06 +0000753
sewardj5155dec2005-10-12 10:09:23 +0000754 // Set up running state and get block info
sewardj3a384b32006-01-22 01:12:51 +0000755 tl_assert(closure->readdr == vge->base[0]);
sewardj5155dec2005-10-12 10:09:23 +0000756 cgs.events_used = 0;
sewardj0b9d74a2006-12-24 02:24:11 +0000757 cgs.sbInfo = get_SB_info(sbIn, (Addr)closure->readdr);
758 cgs.sbInfo_i = 0;
njn6a3009b2005-03-20 00:20:06 +0000759
sewardj5155dec2005-10-12 10:09:23 +0000760 if (DEBUG_CG)
761 VG_(printf)("\n\n---------- cg_instrument ----------\n");
njn6a3009b2005-03-20 00:20:06 +0000762
njnfd9f6222005-10-16 00:17:37 +0000763 // Traverse the block, initialising inodes, adding events and flushing as
764 // necessary.
sewardj0b9d74a2006-12-24 02:24:11 +0000765 for (/*use current i*/; i < sbIn->stmts_used; i++) {
njn6a3009b2005-03-20 00:20:06 +0000766
sewardj0b9d74a2006-12-24 02:24:11 +0000767 st = sbIn->stmts[i];
sewardj5155dec2005-10-12 10:09:23 +0000768 tl_assert(isFlatIRStmt(st));
njnb3507ea2005-08-02 23:07:02 +0000769
sewardj5155dec2005-10-12 10:09:23 +0000770 switch (st->tag) {
771 case Ist_NoOp:
772 case Ist_AbiHint:
773 case Ist_Put:
774 case Ist_PutI:
775 case Ist_MFence:
776 break;
njn20677cc2005-08-12 23:47:51 +0000777
sewardj5155dec2005-10-12 10:09:23 +0000778 case Ist_IMark:
njnfd9f6222005-10-16 00:17:37 +0000779 cia = st->Ist.IMark.addr;
780 isize = st->Ist.IMark.len;
781
782 // If Vex fails to decode an instruction, the size will be zero.
783 // Pretend otherwise.
784 if (isize == 0) isize = VG_MIN_INSTR_SZB;
785
njna5ad9ba2005-11-10 15:20:37 +0000786 // Sanity-check size.
787 tl_assert( (VG_MIN_INSTR_SZB <= isize && isize <= VG_MAX_INSTR_SZB)
788 || VG_CLREQ_SZB == isize );
njnfd9f6222005-10-16 00:17:37 +0000789
790 // Get space for and init the inode, record it as the current one.
791 // Subsequent Dr/Dw/Dm events from the same instruction will
792 // also use it.
793 curr_inode = setup_InstrInfo(&cgs, cia, isize);
794
795 addEvent_Ir( &cgs, curr_inode );
sewardj5155dec2005-10-12 10:09:23 +0000796 break;
797
sewardj0b9d74a2006-12-24 02:24:11 +0000798 case Ist_WrTmp: {
799 IRExpr* data = st->Ist.WrTmp.data;
sewardj5155dec2005-10-12 10:09:23 +0000800 if (data->tag == Iex_Load) {
801 IRExpr* aexpr = data->Iex.Load.addr;
sewardj5155dec2005-10-12 10:09:23 +0000802 // Note also, endianness info is ignored. I guess
803 // that's not interesting.
njnfd9f6222005-10-16 00:17:37 +0000804 addEvent_Dr( &cgs, curr_inode, sizeofIRType(data->Iex.Load.ty),
805 aexpr );
sewardj5155dec2005-10-12 10:09:23 +0000806 }
807 break;
njnb3507ea2005-08-02 23:07:02 +0000808 }
809
sewardj5155dec2005-10-12 10:09:23 +0000810 case Ist_Store: {
811 IRExpr* data = st->Ist.Store.data;
812 IRExpr* aexpr = st->Ist.Store.addr;
njnfd9f6222005-10-16 00:17:37 +0000813 addEvent_Dw( &cgs, curr_inode,
814 sizeofIRType(typeOfIRExpr(tyenv, data)), aexpr );
sewardj5155dec2005-10-12 10:09:23 +0000815 break;
816 }
njnb3507ea2005-08-02 23:07:02 +0000817
sewardj5155dec2005-10-12 10:09:23 +0000818 case Ist_Dirty: {
819 Int dataSize;
820 IRDirty* d = st->Ist.Dirty.details;
821 if (d->mFx != Ifx_None) {
njnfd9f6222005-10-16 00:17:37 +0000822 /* This dirty helper accesses memory. Collect the details. */
sewardj5155dec2005-10-12 10:09:23 +0000823 tl_assert(d->mAddr != NULL);
824 tl_assert(d->mSize != 0);
825 dataSize = d->mSize;
826 // Large (eg. 28B, 108B, 512B on x86) data-sized
827 // instructions will be done inaccurately, but they're
828 // very rare and this avoids errors from hitting more
829 // than two cache lines in the simulation.
830 if (dataSize > MIN_LINE_SIZE)
831 dataSize = MIN_LINE_SIZE;
832 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
njnfd9f6222005-10-16 00:17:37 +0000833 addEvent_Dr( &cgs, curr_inode, dataSize, d->mAddr );
sewardj5155dec2005-10-12 10:09:23 +0000834 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
njnfd9f6222005-10-16 00:17:37 +0000835 addEvent_Dw( &cgs, curr_inode, dataSize, d->mAddr );
sewardj5155dec2005-10-12 10:09:23 +0000836 } else {
837 tl_assert(d->mAddr == NULL);
838 tl_assert(d->mSize == 0);
839 }
840 break;
841 }
njn6a3009b2005-03-20 00:20:06 +0000842
sewardj5155dec2005-10-12 10:09:23 +0000843 case Ist_Exit:
844 /* We may never reach the next statement, so need to flush
845 all outstanding transactions now. */
846 flushEvents( &cgs );
847 break;
848
849 default:
850 tl_assert(0);
851 break;
njnb3507ea2005-08-02 23:07:02 +0000852 }
njn6a3009b2005-03-20 00:20:06 +0000853
sewardj5155dec2005-10-12 10:09:23 +0000854 /* Copy the original statement */
sewardj0b9d74a2006-12-24 02:24:11 +0000855 addStmtToIRSB( cgs.sbOut, st );
njn6a3009b2005-03-20 00:20:06 +0000856
sewardj5155dec2005-10-12 10:09:23 +0000857 if (DEBUG_CG) {
858 ppIRStmt(st);
859 VG_(printf)("\n");
860 }
861 }
862
863 /* At the end of the bb. Flush outstandings. */
sewardj5155dec2005-10-12 10:09:23 +0000864 flushEvents( &cgs );
865
sewardj5155dec2005-10-12 10:09:23 +0000866 /* done. stay sane ... */
sewardj0b9d74a2006-12-24 02:24:11 +0000867 tl_assert(cgs.sbInfo_i == cgs.sbInfo->n_instrs);
sewardj5155dec2005-10-12 10:09:23 +0000868
869 if (DEBUG_CG) {
870 VG_(printf)( "goto {");
sewardj0b9d74a2006-12-24 02:24:11 +0000871 ppIRJumpKind(sbIn->jumpkind);
sewardj5155dec2005-10-12 10:09:23 +0000872 VG_(printf)( "} ");
sewardj0b9d74a2006-12-24 02:24:11 +0000873 ppIRExpr( sbIn->next );
sewardj5155dec2005-10-12 10:09:23 +0000874 VG_(printf)( "}\n");
875 }
876
sewardj0b9d74a2006-12-24 02:24:11 +0000877 return cgs.sbOut;
njn14d01ce2004-11-26 11:30:14 +0000878}
njn4f9c9342002-04-29 16:03:24 +0000879
880/*------------------------------------------------------------*/
nethercoteb35a8b92004-09-11 16:45:27 +0000881/*--- Cache configuration ---*/
njn4f9c9342002-04-29 16:03:24 +0000882/*------------------------------------------------------------*/
883
sewardjb5f6f512005-03-10 23:59:00 +0000884#define UNDEFINED_CACHE { -1, -1, -1 }
njn25e49d8e72002-09-23 09:36:25 +0000885
886static cache_t clo_I1_cache = UNDEFINED_CACHE;
887static cache_t clo_D1_cache = UNDEFINED_CACHE;
888static cache_t clo_L2_cache = UNDEFINED_CACHE;
889
njn7cf0bd32002-06-08 13:36:03 +0000890/* Checks cache config is ok; makes it so if not. */
sewardj07133bf2002-06-13 10:25:56 +0000891static
njna1d1a642004-11-26 18:36:02 +0000892void check_cache(cache_t* cache, Char *name)
njn7cf0bd32002-06-08 13:36:03 +0000893{
894 /* First check they're all powers of two */
sewardj07133bf2002-06-13 10:25:56 +0000895 if (-1 == VG_(log2)(cache->size)) {
njn7cf0bd32002-06-08 13:36:03 +0000896 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000897 "error: %s size of %dB not a power of two; aborting.",
898 name, cache->size);
899 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000900 }
901
sewardj07133bf2002-06-13 10:25:56 +0000902 if (-1 == VG_(log2)(cache->assoc)) {
njn7cf0bd32002-06-08 13:36:03 +0000903 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000904 "error: %s associativity of %d not a power of two; aborting.",
905 name, cache->assoc);
906 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000907 }
908
sewardj07133bf2002-06-13 10:25:56 +0000909 if (-1 == VG_(log2)(cache->line_size)) {
njn7cf0bd32002-06-08 13:36:03 +0000910 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000911 "error: %s line size of %dB not a power of two; aborting.",
912 name, cache->line_size);
913 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000914 }
915
njn6a3009b2005-03-20 00:20:06 +0000916 // Then check line size >= 16 -- any smaller and a single instruction could
917 // straddle three cache lines, which breaks a simulation assertion and is
918 // stupid anyway.
njn7cf0bd32002-06-08 13:36:03 +0000919 if (cache->line_size < MIN_LINE_SIZE) {
920 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000921 "error: %s line size of %dB too small; aborting.",
922 name, cache->line_size);
923 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000924 }
925
926 /* Then check cache size > line size (causes seg faults if not). */
927 if (cache->size <= cache->line_size) {
928 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000929 "error: %s cache size of %dB <= line size of %dB; aborting.",
930 name, cache->size, cache->line_size);
931 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000932 }
933
934 /* Then check assoc <= (size / line size) (seg faults otherwise). */
935 if (cache->assoc > (cache->size / cache->line_size)) {
936 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000937 "warning: %s associativity > (size / line size); aborting.", name);
938 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000939 }
940}
941
sewardj07133bf2002-06-13 10:25:56 +0000942static
nethercoteb35a8b92004-09-11 16:45:27 +0000943void configure_caches(cache_t* I1c, cache_t* D1c, cache_t* L2c)
njn7cf0bd32002-06-08 13:36:03 +0000944{
nethercote9313ac42004-07-06 21:54:20 +0000945#define DEFINED(L) (-1 != L.size || -1 != L.assoc || -1 != L.line_size)
946
nethercoteb35a8b92004-09-11 16:45:27 +0000947 Int n_clos = 0;
nethercote9313ac42004-07-06 21:54:20 +0000948
nethercoteb35a8b92004-09-11 16:45:27 +0000949 // Count how many were defined on the command line.
950 if (DEFINED(clo_I1_cache)) { n_clos++; }
951 if (DEFINED(clo_D1_cache)) { n_clos++; }
952 if (DEFINED(clo_L2_cache)) { n_clos++; }
njn7cf0bd32002-06-08 13:36:03 +0000953
njna1d1a642004-11-26 18:36:02 +0000954 // Set the cache config (using auto-detection, if supported by the
955 // architecture)
njnaf839f52005-06-23 03:27:57 +0000956 VG_(configure_caches)( I1c, D1c, L2c, (3 == n_clos) );
sewardjb1a77a42002-07-13 13:31:20 +0000957
nethercote9313ac42004-07-06 21:54:20 +0000958 // Then replace with any defined on the command line.
nethercoteb35a8b92004-09-11 16:45:27 +0000959 if (DEFINED(clo_I1_cache)) { *I1c = clo_I1_cache; }
960 if (DEFINED(clo_D1_cache)) { *D1c = clo_D1_cache; }
961 if (DEFINED(clo_L2_cache)) { *L2c = clo_L2_cache; }
njn7cf0bd32002-06-08 13:36:03 +0000962
nethercote9313ac42004-07-06 21:54:20 +0000963 // Then check values and fix if not acceptable.
njna1d1a642004-11-26 18:36:02 +0000964 check_cache(I1c, "I1");
965 check_cache(D1c, "D1");
966 check_cache(L2c, "L2");
njn7cf0bd32002-06-08 13:36:03 +0000967
968 if (VG_(clo_verbosity) > 1) {
969 VG_(message)(Vg_UserMsg, "Cache configuration used:");
970 VG_(message)(Vg_UserMsg, " I1: %dB, %d-way, %dB lines",
971 I1c->size, I1c->assoc, I1c->line_size);
972 VG_(message)(Vg_UserMsg, " D1: %dB, %d-way, %dB lines",
973 D1c->size, D1c->assoc, D1c->line_size);
974 VG_(message)(Vg_UserMsg, " L2: %dB, %d-way, %dB lines",
975 L2c->size, L2c->assoc, L2c->line_size);
976 }
nethercote9313ac42004-07-06 21:54:20 +0000977#undef CMD_LINE_DEFINED
njn7cf0bd32002-06-08 13:36:03 +0000978}
979
njn4f9c9342002-04-29 16:03:24 +0000980/*------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +0000981/*--- cg_fini() and related function ---*/
njn4f9c9342002-04-29 16:03:24 +0000982/*------------------------------------------------------------*/
983
nethercote9313ac42004-07-06 21:54:20 +0000984// Total reads/writes/misses. Calculated during CC traversal at the end.
985// All auto-zeroed.
986static CC Ir_total;
987static CC Dr_total;
988static CC Dw_total;
989
sewardje1216cb2007-02-07 19:55:30 +0000990// The output file base name specified by the user using the
991// --cachegrind-out-file switch. This is combined with the
992// process ID and optional user-supplied qualifier (from
993// --log-file-qualifier) to produce the name stored in
994// cachegrind_out_file.
995static Char* cachegrind_out_file_basename = "cachegrind.out";
996
997// The final, completed name for the output file.
998static Char* cachegrind_out_file = NULL;
999
nethercote9313ac42004-07-06 21:54:20 +00001000
nethercote9313ac42004-07-06 21:54:20 +00001001static void fprint_CC_table_and_calc_totals(void)
1002{
njnd3bef4f2005-10-15 17:46:18 +00001003 Int i, fd;
sewardj92645592005-07-23 09:18:34 +00001004 SysRes sres;
njnd3bef4f2005-10-15 17:46:18 +00001005 Char buf[512], *currFile = NULL, *currFn = NULL;
1006 LineCC* lineCC;
njn4f9c9342002-04-29 16:03:24 +00001007
sewardj92645592005-07-23 09:18:34 +00001008 sres = VG_(open)(cachegrind_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
1009 VKI_S_IRUSR|VKI_S_IWUSR);
1010 if (sres.isError) {
nethercote9313ac42004-07-06 21:54:20 +00001011 // If the file can't be opened for whatever reason (conflict
1012 // between multiple cachegrinded processes?), give up now.
njnee0e6a32005-04-24 00:21:01 +00001013 VG_(message)(Vg_UserMsg,
njn02bc4b82005-05-15 17:28:26 +00001014 "error: can't open cache simulation output file '%s'",
njnee0e6a32005-04-24 00:21:01 +00001015 cachegrind_out_file );
1016 VG_(message)(Vg_UserMsg,
1017 " ... so simulation results will be missing.");
sewardj0744b6c2002-12-11 00:45:42 +00001018 return;
sewardj92645592005-07-23 09:18:34 +00001019 } else {
sewardje8089302006-10-17 02:15:17 +00001020 fd = sres.res;
sewardj0744b6c2002-12-11 00:45:42 +00001021 }
njn4f9c9342002-04-29 16:03:24 +00001022
nethercote9313ac42004-07-06 21:54:20 +00001023 // "desc:" lines (giving I1/D1/L2 cache configuration). The spaces after
1024 // the 2nd colon makes cg_annotate's output look nicer.
1025 VG_(sprintf)(buf, "desc: I1 cache: %s\n"
1026 "desc: D1 cache: %s\n"
1027 "desc: L2 cache: %s\n",
1028 I1.desc_line, D1.desc_line, L2.desc_line);
njn7cf0bd32002-06-08 13:36:03 +00001029 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njn4f9c9342002-04-29 16:03:24 +00001030
nethercote9313ac42004-07-06 21:54:20 +00001031 // "cmd:" line
njn4f9c9342002-04-29 16:03:24 +00001032 VG_(strcpy)(buf, "cmd:");
1033 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
sewardj45f4e7c2005-09-27 19:20:21 +00001034 if (VG_(args_the_exename)) {
1035 VG_(write)(fd, " ", 1);
1036 VG_(write)(fd, VG_(args_the_exename),
1037 VG_(strlen)( VG_(args_the_exename) ));
1038 }
sewardj14c7cc52007-02-25 15:08:24 +00001039 for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
1040 HChar* arg = * (HChar**) VG_(indexXA)( VG_(args_for_client), i );
1041 if (arg) {
sewardj45f4e7c2005-09-27 19:20:21 +00001042 VG_(write)(fd, " ", 1);
sewardj14c7cc52007-02-25 15:08:24 +00001043 VG_(write)(fd, arg, VG_(strlen)( arg ));
sewardj45f4e7c2005-09-27 19:20:21 +00001044 }
njn4f9c9342002-04-29 16:03:24 +00001045 }
nethercote9313ac42004-07-06 21:54:20 +00001046 // "events:" line
njn4f9c9342002-04-29 16:03:24 +00001047 VG_(sprintf)(buf, "\nevents: Ir I1mr I2mr Dr D1mr D2mr Dw D1mw D2mw\n");
1048 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1049
njnd3bef4f2005-10-15 17:46:18 +00001050 // Traverse every lineCC
1051 VG_(OSet_ResetIter)(CC_table);
1052 while ( (lineCC = VG_(OSet_Next)(CC_table)) ) {
njn4311fe62005-12-08 23:18:50 +00001053 Bool just_hit_a_new_file = False;
njnd3bef4f2005-10-15 17:46:18 +00001054 // 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
njn4311fe62005-12-08 23:18:50 +00001058 // the whole strings would have to be checked.
njnd3bef4f2005-10-15 17:46:18 +00001059 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++;
njn4311fe62005-12-08 23:18:50 +00001064 just_hit_a_new_file = True;
njn4f9c9342002-04-29 16:03:24 +00001065 }
njn4311fe62005-12-08 23:18:50 +00001066 // If we've hit a new function, print a "fn=" line. We know to do
1067 // this when the function name changes, and also every time we hit a
1068 // new file (in which case the new function name might be the same as
1069 // in the old file, hence the just_hit_a_new_file test).
1070 if ( just_hit_a_new_file || lineCC->loc.fn != currFn ) {
njnd3bef4f2005-10-15 17:46:18 +00001071 currFn = lineCC->loc.fn;
1072 VG_(sprintf)(buf, "fn=%s\n", currFn);
1073 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1074 distinct_fns++;
njn4311fe62005-12-08 23:18:50 +00001075 just_hit_a_new_file = False;
njnd3bef4f2005-10-15 17:46:18 +00001076 }
1077
1078 // Print the LineCC
1079 VG_(sprintf)(buf, "%u %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
1080 lineCC->loc.line,
1081 lineCC->Ir.a, lineCC->Ir.m1, lineCC->Ir.m2,
1082 lineCC->Dr.a, lineCC->Dr.m1, lineCC->Dr.m2,
1083 lineCC->Dw.a, lineCC->Dw.m1, lineCC->Dw.m2);
1084 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1085
1086 // Update summary stats
1087 Ir_total.a += lineCC->Ir.a;
1088 Ir_total.m1 += lineCC->Ir.m1;
1089 Ir_total.m2 += lineCC->Ir.m2;
1090 Dr_total.a += lineCC->Dr.a;
1091 Dr_total.m1 += lineCC->Dr.m1;
1092 Dr_total.m2 += lineCC->Dr.m2;
1093 Dw_total.a += lineCC->Dw.a;
1094 Dw_total.m1 += lineCC->Dw.m1;
1095 Dw_total.m2 += lineCC->Dw.m2;
1096
1097 distinct_lines++;
njn4f9c9342002-04-29 16:03:24 +00001098 }
1099
nethercote9313ac42004-07-06 21:54:20 +00001100 // Summary stats must come after rest of table, since we calculate them
1101 // during traversal. */
njn4f9c9342002-04-29 16:03:24 +00001102 VG_(sprintf)(buf, "summary: "
nethercote9313ac42004-07-06 21:54:20 +00001103 "%llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
njn4f9c9342002-04-29 16:03:24 +00001104 Ir_total.a, Ir_total.m1, Ir_total.m2,
1105 Dr_total.a, Dr_total.m1, Dr_total.m2,
1106 Dw_total.a, Dw_total.m1, Dw_total.m2);
1107 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1108 VG_(close)(fd);
1109}
1110
njn607adfc2003-09-30 14:15:44 +00001111static UInt ULong_width(ULong n)
njn4f9c9342002-04-29 16:03:24 +00001112{
njn607adfc2003-09-30 14:15:44 +00001113 UInt w = 0;
1114 while (n > 0) {
1115 n = n / 10;
1116 w++;
njn4f9c9342002-04-29 16:03:24 +00001117 }
sewardj46c59b12005-11-01 02:20:19 +00001118 if (w == 0) w = 1;
njn607adfc2003-09-30 14:15:44 +00001119 return w + (w-1)/3; // add space for commas
njn4f9c9342002-04-29 16:03:24 +00001120}
1121
njn51d827b2005-05-09 01:02:08 +00001122static void cg_fini(Int exitcode)
njn4f9c9342002-04-29 16:03:24 +00001123{
njn1baf7db2006-04-18 22:34:48 +00001124 static Char buf1[128], buf2[128], buf3[128], buf4[123], fmt[128];
njn607adfc2003-09-30 14:15:44 +00001125
njn4f9c9342002-04-29 16:03:24 +00001126 CC D_total;
njn1d021fa2002-05-02 13:56:34 +00001127 ULong L2_total_m, L2_total_mr, L2_total_mw,
1128 L2_total, L2_total_r, L2_total_w;
njn4f9c9342002-04-29 16:03:24 +00001129 Int l1, l2, l3;
1130 Int p;
1131
nethercote9313ac42004-07-06 21:54:20 +00001132 fprint_CC_table_and_calc_totals();
njn4f9c9342002-04-29 16:03:24 +00001133
njn7cf0bd32002-06-08 13:36:03 +00001134 if (VG_(clo_verbosity) == 0)
1135 return;
1136
njn4f9c9342002-04-29 16:03:24 +00001137 /* I cache results. Use the I_refs value to determine the first column
1138 * width. */
njn607adfc2003-09-30 14:15:44 +00001139 l1 = ULong_width(Ir_total.a);
1140 l2 = ULong_width(Dr_total.a);
1141 l3 = ULong_width(Dw_total.a);
njn4f9c9342002-04-29 16:03:24 +00001142
njn607adfc2003-09-30 14:15:44 +00001143 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001144 VG_(sprintf)(fmt, "%%s %%,%dllu", l1);
njnd3bef4f2005-10-15 17:46:18 +00001145
njn607adfc2003-09-30 14:15:44 +00001146 VG_(message)(Vg_UserMsg, fmt, "I refs: ", Ir_total.a);
1147 VG_(message)(Vg_UserMsg, fmt, "I1 misses: ", Ir_total.m1);
1148 VG_(message)(Vg_UserMsg, fmt, "L2i misses: ", Ir_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001149
1150 p = 100;
1151
njn25e49d8e72002-09-23 09:36:25 +00001152 if (0 == Ir_total.a) Ir_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001153 VG_(percentify)(Ir_total.m1, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001154 VG_(message)(Vg_UserMsg, "I1 miss rate: %s", buf1);
njnd3bef4f2005-10-15 17:46:18 +00001155
njn856c54e2005-06-26 18:43:40 +00001156 VG_(percentify)(Ir_total.m2, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001157 VG_(message)(Vg_UserMsg, "L2i miss rate: %s", buf1);
1158 VG_(message)(Vg_UserMsg, "");
1159
1160 /* D cache results. Use the D_refs.rd and D_refs.wr values to determine the
1161 * width of columns 2 & 3. */
1162 D_total.a = Dr_total.a + Dw_total.a;
1163 D_total.m1 = Dr_total.m1 + Dw_total.m1;
1164 D_total.m2 = Dr_total.m2 + Dw_total.m2;
njnd3bef4f2005-10-15 17:46:18 +00001165
njn607adfc2003-09-30 14:15:44 +00001166 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001167 VG_(sprintf)(fmt, "%%s %%,%dllu (%%,%dllu rd + %%,%dllu wr)", l1, l2, l3);
njn4f9c9342002-04-29 16:03:24 +00001168
njn607adfc2003-09-30 14:15:44 +00001169 VG_(message)(Vg_UserMsg, fmt, "D refs: ",
1170 D_total.a, Dr_total.a, Dw_total.a);
1171 VG_(message)(Vg_UserMsg, fmt, "D1 misses: ",
1172 D_total.m1, Dr_total.m1, Dw_total.m1);
1173 VG_(message)(Vg_UserMsg, fmt, "L2d misses: ",
1174 D_total.m2, Dr_total.m2, Dw_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001175
1176 p = 10;
njnd3bef4f2005-10-15 17:46:18 +00001177
njn25e49d8e72002-09-23 09:36:25 +00001178 if (0 == D_total.a) D_total.a = 1;
1179 if (0 == Dr_total.a) Dr_total.a = 1;
1180 if (0 == Dw_total.a) Dw_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001181 VG_(percentify)( D_total.m1, D_total.a, 1, l1+1, buf1);
1182 VG_(percentify)(Dr_total.m1, Dr_total.a, 1, l2+1, buf2);
1183 VG_(percentify)(Dw_total.m1, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001184 VG_(message)(Vg_UserMsg, "D1 miss rate: %s (%s + %s )", buf1, buf2,buf3);
1185
njn856c54e2005-06-26 18:43:40 +00001186 VG_(percentify)( D_total.m2, D_total.a, 1, l1+1, buf1);
1187 VG_(percentify)(Dr_total.m2, Dr_total.a, 1, l2+1, buf2);
1188 VG_(percentify)(Dw_total.m2, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001189 VG_(message)(Vg_UserMsg, "L2d miss rate: %s (%s + %s )", buf1, buf2,buf3);
1190 VG_(message)(Vg_UserMsg, "");
1191
1192 /* L2 overall results */
njn1d021fa2002-05-02 13:56:34 +00001193
1194 L2_total = Dr_total.m1 + Dw_total.m1 + Ir_total.m1;
1195 L2_total_r = Dr_total.m1 + Ir_total.m1;
1196 L2_total_w = Dw_total.m1;
njn607adfc2003-09-30 14:15:44 +00001197 VG_(message)(Vg_UserMsg, fmt, "L2 refs: ",
1198 L2_total, L2_total_r, L2_total_w);
njn1d021fa2002-05-02 13:56:34 +00001199
njn4f9c9342002-04-29 16:03:24 +00001200 L2_total_m = Dr_total.m2 + Dw_total.m2 + Ir_total.m2;
1201 L2_total_mr = Dr_total.m2 + Ir_total.m2;
1202 L2_total_mw = Dw_total.m2;
njn607adfc2003-09-30 14:15:44 +00001203 VG_(message)(Vg_UserMsg, fmt, "L2 misses: ",
1204 L2_total_m, L2_total_mr, L2_total_mw);
njn4f9c9342002-04-29 16:03:24 +00001205
njn856c54e2005-06-26 18:43:40 +00001206 VG_(percentify)(L2_total_m, (Ir_total.a + D_total.a), 1, l1+1, buf1);
1207 VG_(percentify)(L2_total_mr, (Ir_total.a + Dr_total.a), 1, l2+1, buf2);
1208 VG_(percentify)(L2_total_mw, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001209 VG_(message)(Vg_UserMsg, "L2 miss rate: %s (%s + %s )", buf1, buf2,buf3);
njnd3bef4f2005-10-15 17:46:18 +00001210
njn4f9c9342002-04-29 16:03:24 +00001211
nethercote9313ac42004-07-06 21:54:20 +00001212 // Various stats
njn4f9c9342002-04-29 16:03:24 +00001213 if (VG_(clo_verbosity) > 1) {
njn1baf7db2006-04-18 22:34:48 +00001214 Int debug_lookups = full_debugs + fn_debugs +
1215 file_line_debugs + no_debugs;
njnd3bef4f2005-10-15 17:46:18 +00001216
njn1baf7db2006-04-18 22:34:48 +00001217 VG_(message)(Vg_DebugMsg, "");
1218 VG_(message)(Vg_DebugMsg, "cachegrind: distinct files: %d", distinct_files);
1219 VG_(message)(Vg_DebugMsg, "cachegrind: distinct fns: %d", distinct_fns);
1220 VG_(message)(Vg_DebugMsg, "cachegrind: distinct lines: %d", distinct_lines);
1221 VG_(message)(Vg_DebugMsg, "cachegrind: distinct instrs:%d", distinct_instrs);
1222 VG_(message)(Vg_DebugMsg, "cachegrind: debug lookups : %d", debug_lookups);
1223
1224 VG_(percentify)(full_debugs, debug_lookups, 1, 6, buf1);
1225 VG_(percentify)(file_line_debugs, debug_lookups, 1, 6, buf2);
1226 VG_(percentify)(fn_debugs, debug_lookups, 1, 6, buf3);
1227 VG_(percentify)(no_debugs, debug_lookups, 1, 6, buf4);
1228 VG_(message)(Vg_DebugMsg, "cachegrind: with full info:%s (%d)",
1229 buf1, full_debugs);
1230 VG_(message)(Vg_DebugMsg, "cachegrind: with file/line info:%s (%d)",
1231 buf2, file_line_debugs);
1232 VG_(message)(Vg_DebugMsg, "cachegrind: with fn name info:%s (%d)",
1233 buf3, fn_debugs);
1234 VG_(message)(Vg_DebugMsg, "cachegrind: with zero info:%s (%d)",
1235 buf4, no_debugs);
1236
1237 VG_(message)(Vg_DebugMsg, "cachegrind: string table size: %u",
1238 VG_(OSet_Size)(stringTable));
1239 VG_(message)(Vg_DebugMsg, "cachegrind: CC table size: %u",
1240 VG_(OSet_Size)(CC_table));
1241 VG_(message)(Vg_DebugMsg, "cachegrind: InstrInfo table size: %u",
1242 VG_(OSet_Size)(instrInfoTable));
njn4f9c9342002-04-29 16:03:24 +00001243 }
njn4f9c9342002-04-29 16:03:24 +00001244}
1245
nethercote9313ac42004-07-06 21:54:20 +00001246/*--------------------------------------------------------------------*/
1247/*--- Discarding BB info ---*/
1248/*--------------------------------------------------------------------*/
sewardj18d75132002-05-16 11:06:21 +00001249
sewardja3a29a52005-10-12 16:16:03 +00001250// Called when a translation is removed from the translation cache for
1251// any reason at all: to free up space, because the guest code was
1252// unmapped or modified, or for any arbitrary reason.
sewardj4ba057c2005-10-18 12:04:18 +00001253static
sewardj0b9d74a2006-12-24 02:24:11 +00001254void cg_discard_superblock_info ( Addr64 orig_addr64, VexGuestExtents vge )
sewardj18d75132002-05-16 11:06:21 +00001255{
sewardj0b9d74a2006-12-24 02:24:11 +00001256 SB_info* sbInfo;
sewardj3a384b32006-01-22 01:12:51 +00001257 Addr orig_addr = (Addr)vge.base[0];
njn4294fd42002-06-05 14:41:10 +00001258
sewardj5155dec2005-10-12 10:09:23 +00001259 tl_assert(vge.n_used > 0);
1260
1261 if (DEBUG_CG)
sewardj4ba057c2005-10-18 12:04:18 +00001262 VG_(printf)( "discard_basic_block_info: %p, %p, %llu\n",
1263 (void*)(Addr)orig_addr,
sewardj5155dec2005-10-12 10:09:23 +00001264 (void*)(Addr)vge.base[0], (ULong)vge.len[0]);
njn4294fd42002-06-05 14:41:10 +00001265
sewardj4ba057c2005-10-18 12:04:18 +00001266 // Get BB info, remove from table, free BB info. Simple! Note that we
1267 // use orig_addr, not the first instruction address in vge.
sewardj0b9d74a2006-12-24 02:24:11 +00001268 sbInfo = VG_(OSet_Remove)(instrInfoTable, &orig_addr);
1269 tl_assert(NULL != sbInfo);
1270 VG_(OSet_FreeNode)(instrInfoTable, sbInfo);
sewardj18d75132002-05-16 11:06:21 +00001271}
1272
1273/*--------------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001274/*--- Command line processing ---*/
1275/*--------------------------------------------------------------------*/
1276
njn0103de52005-10-10 16:49:01 +00001277static void parse_cache_opt ( cache_t* cache, Char* opt )
njn25e49d8e72002-09-23 09:36:25 +00001278{
njn0103de52005-10-10 16:49:01 +00001279 Int i = 0, i2, i3;
njn25e49d8e72002-09-23 09:36:25 +00001280
nethercote9313ac42004-07-06 21:54:20 +00001281 // Option argument looks like "65536,2,64".
1282 // Find commas, replace with NULs to make three independent
1283 // strings, then extract numbers, put NULs back. Yuck.
njn25e49d8e72002-09-23 09:36:25 +00001284 while (VG_(isdigit)(opt[i])) i++;
1285 if (',' == opt[i]) {
1286 opt[i++] = '\0';
1287 i2 = i;
1288 } else goto bad;
1289 while (VG_(isdigit)(opt[i])) i++;
1290 if (',' == opt[i]) {
1291 opt[i++] = '\0';
1292 i3 = i;
1293 } else goto bad;
1294 while (VG_(isdigit)(opt[i])) i++;
1295 if ('\0' != opt[i]) goto bad;
1296
nethercote9313ac42004-07-06 21:54:20 +00001297 cache->size = (Int)VG_(atoll)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001298 cache->assoc = (Int)VG_(atoll)(opt + i2);
1299 cache->line_size = (Int)VG_(atoll)(opt + i3);
1300
nethercote9313ac42004-07-06 21:54:20 +00001301 opt[i2-1] = ',';
1302 opt[i3-1] = ',';
njn25e49d8e72002-09-23 09:36:25 +00001303 return;
1304
1305 bad:
sewardj6893d652006-10-15 01:25:13 +00001306 VG_(err_bad_option)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001307}
1308
njn51d827b2005-05-09 01:02:08 +00001309static Bool cg_process_cmd_line_option(Char* arg)
njn25e49d8e72002-09-23 09:36:25 +00001310{
nethercote9313ac42004-07-06 21:54:20 +00001311 // 5 is length of "--I1="
njn39c86652003-05-21 10:13:39 +00001312 if (VG_CLO_STREQN(5, arg, "--I1="))
nethercote9313ac42004-07-06 21:54:20 +00001313 parse_cache_opt(&clo_I1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001314 else if (VG_CLO_STREQN(5, arg, "--D1="))
nethercote9313ac42004-07-06 21:54:20 +00001315 parse_cache_opt(&clo_D1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001316 else if (VG_CLO_STREQN(5, arg, "--L2="))
nethercote9313ac42004-07-06 21:54:20 +00001317 parse_cache_opt(&clo_L2_cache, &arg[5]);
sewardje1216cb2007-02-07 19:55:30 +00001318 else if (VG_CLO_STREQN(22, arg, "--cachegrind-out-file=")) {
1319 cachegrind_out_file_basename = &arg[22];
1320 }
njn25e49d8e72002-09-23 09:36:25 +00001321 else
1322 return False;
1323
1324 return True;
1325}
1326
njn51d827b2005-05-09 01:02:08 +00001327static void cg_print_usage(void)
njn25e49d8e72002-09-23 09:36:25 +00001328{
njn3e884182003-04-15 13:03:23 +00001329 VG_(printf)(
njn25e49d8e72002-09-23 09:36:25 +00001330" --I1=<size>,<assoc>,<line_size> set I1 cache manually\n"
1331" --D1=<size>,<assoc>,<line_size> set D1 cache manually\n"
njn3e884182003-04-15 13:03:23 +00001332" --L2=<size>,<assoc>,<line_size> set L2 cache manually\n"
sewardje1216cb2007-02-07 19:55:30 +00001333" --cachegrind-out-file=<file> write profile data to <file>.<pid>\n"
1334" [cachegrind.out.<pid>]\n"
njn3e884182003-04-15 13:03:23 +00001335 );
1336}
1337
njn51d827b2005-05-09 01:02:08 +00001338static void cg_print_debug_usage(void)
njn3e884182003-04-15 13:03:23 +00001339{
1340 VG_(printf)(
1341" (none)\n"
1342 );
njn25e49d8e72002-09-23 09:36:25 +00001343}
1344
1345/*--------------------------------------------------------------------*/
1346/*--- Setup ---*/
1347/*--------------------------------------------------------------------*/
1348
njn57ca7ab2005-06-21 23:44:58 +00001349static Char base_dir[VKI_PATH_MAX];
1350
sewardje1216cb2007-02-07 19:55:30 +00001351static void cg_post_clo_init(void); /* just below */
1352
njn51d827b2005-05-09 01:02:08 +00001353static void cg_pre_clo_init(void)
1354{
njn51d827b2005-05-09 01:02:08 +00001355 VG_(details_name) ("Cachegrind");
1356 VG_(details_version) (NULL);
1357 VG_(details_description) ("an I1/D1/L2 cache profiler");
1358 VG_(details_copyright_author)(
sewardj9ebd6e02007-01-08 06:01:59 +00001359 "Copyright (C) 2002-2007, and GNU GPL'd, by Nicholas Nethercote et al.");
njn51d827b2005-05-09 01:02:08 +00001360 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardje8089302006-10-17 02:15:17 +00001361 VG_(details_avg_translation_sizeB) ( 500 );
njn51d827b2005-05-09 01:02:08 +00001362
1363 VG_(basic_tool_funcs) (cg_post_clo_init,
1364 cg_instrument,
1365 cg_fini);
1366
sewardj0b9d74a2006-12-24 02:24:11 +00001367 VG_(needs_superblock_discards)(cg_discard_superblock_info);
njn51d827b2005-05-09 01:02:08 +00001368 VG_(needs_command_line_options)(cg_process_cmd_line_option,
1369 cg_print_usage,
1370 cg_print_debug_usage);
sewardje1216cb2007-02-07 19:55:30 +00001371}
1372
1373static void cg_post_clo_init(void)
1374{
1375 HChar* qual = NULL;
1376 cache_t I1c, D1c, L2c;
1377 Int filename_szB;
njn51d827b2005-05-09 01:02:08 +00001378
1379 /* Get working directory */
njn57ca7ab2005-06-21 23:44:58 +00001380 tl_assert( VG_(getcwd)(base_dir, VKI_PATH_MAX) );
njn51d827b2005-05-09 01:02:08 +00001381
sewardje1216cb2007-02-07 19:55:30 +00001382 /* Do we have a --log-file-qualifier= to consider? */
1383 if (VG_(clo_log_file_qualifier)) {
1384 qual = VG_(getenv)(VG_(clo_log_file_qualifier));
1385 }
1386
1387 /* Block is big enough for
1388 dir name ++ cachegrind_out_file_basename
1389 ++ ".<pid>"
1390 ++ the log file qualifier, if in use */
1391 filename_szB
1392 = VG_(strlen)(base_dir)
1393 + 1 /* "/" */
1394 + VG_(strlen)(cachegrind_out_file_basename)
1395 + 11 /* "." <pid>, assuming sizeof(pid) <= 4 */
1396 + (qual ? (10 + VG_(strlen)(qual)) : 0)
1397 + 1; /* to guarantee checkable zero at the end */
1398
1399 tl_assert(filename_szB > 0);
1400 cachegrind_out_file
1401 = VG_(calloc)( sizeof(Char), filename_szB );
1402
1403 if (qual) {
1404 VG_(sprintf)(cachegrind_out_file, "%s/%s.%d.lfq.%s",
1405 base_dir, cachegrind_out_file_basename,
1406 VG_(getpid)(), qual);
1407 } else {
1408 VG_(sprintf)(cachegrind_out_file, "%s/%s.%d",
1409 base_dir, cachegrind_out_file_basename,
1410 VG_(getpid)());
1411 }
1412
1413 tl_assert( cachegrind_out_file[filename_szB-1] == 0 );
njn51d827b2005-05-09 01:02:08 +00001414
njnd3bef4f2005-10-15 17:46:18 +00001415 CC_table = VG_(OSet_Create)(offsetof(LineCC, loc),
1416 cmp_CodeLoc_LineCC,
1417 VG_(malloc), VG_(free));
sewardj4ba057c2005-10-18 12:04:18 +00001418 instrInfoTable = VG_(OSet_Create)(/*keyOff*/0,
njnd3bef4f2005-10-15 17:46:18 +00001419 NULL,
1420 VG_(malloc), VG_(free));
1421 stringTable = VG_(OSet_Create)(/*keyOff*/0,
1422 stringCmp,
1423 VG_(malloc), VG_(free));
sewardje1216cb2007-02-07 19:55:30 +00001424
1425 configure_caches(&I1c, &D1c, &L2c);
1426
1427 cachesim_I1_initcache(I1c);
1428 cachesim_D1_initcache(D1c);
1429 cachesim_L2_initcache(L2c);
njn51d827b2005-05-09 01:02:08 +00001430}
1431
sewardj45f4e7c2005-09-27 19:20:21 +00001432VG_DETERMINE_INTERFACE_VERSION(cg_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00001433
njn25e49d8e72002-09-23 09:36:25 +00001434/*--------------------------------------------------------------------*/
njnf69f9452005-07-03 17:53:11 +00001435/*--- end ---*/
sewardj18d75132002-05-16 11:06:21 +00001436/*--------------------------------------------------------------------*/
njnd3bef4f2005-10-15 17:46:18 +00001437