blob: b0768f77309ec43cd50f9b5737b2816f47a90c5e [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;
240 VG_(OSet_Insert)(CC_table, lineCC);
njn4f9c9342002-04-29 16:03:24 +0000241 }
nethercote9313ac42004-07-06 21:54:20 +0000242
njnd3bef4f2005-10-15 17:46:18 +0000243 return lineCC;
njn4f9c9342002-04-29 16:03:24 +0000244}
245
246/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +0000247/*--- Cache simulation functions ---*/
njn4f9c9342002-04-29 16:03:24 +0000248/*------------------------------------------------------------*/
249
njnaf839f52005-06-23 03:27:57 +0000250static VG_REGPARM(1)
njnd3bef4f2005-10-15 17:46:18 +0000251void log_1I_0D_cache_access(InstrInfo* n)
njn25e49d8e72002-09-23 09:36:25 +0000252{
sewardj5155dec2005-10-12 10:09:23 +0000253 //VG_(printf)("1I_0D : CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n",
254 // n, n->instr_addr, n->instr_len);
njn6a3009b2005-03-20 00:20:06 +0000255 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000256 &n->parent->Ir.m1, &n->parent->Ir.m2);
257 n->parent->Ir.a++;
njn25e49d8e72002-09-23 09:36:25 +0000258}
259
njnaf839f52005-06-23 03:27:57 +0000260static VG_REGPARM(2)
njnd3bef4f2005-10-15 17:46:18 +0000261void log_2I_0D_cache_access(InstrInfo* n, InstrInfo* n2)
njn25e49d8e72002-09-23 09:36:25 +0000262{
sewardj5155dec2005-10-12 10:09:23 +0000263 //VG_(printf)("2I_0D : CC1addr=0x%010lx, i1addr=0x%010lx, i1size=%lu\n"
264 // " CC2addr=0x%010lx, i2addr=0x%010lx, i2size=%lu\n",
265 // n, n->instr_addr, n->instr_len,
266 // n2, n2->instr_addr, n2->instr_len);
sewardj5155dec2005-10-12 10:09:23 +0000267 cachesim_I1_doref(n->instr_addr, n->instr_len,
268 &n->parent->Ir.m1, &n->parent->Ir.m2);
269 n->parent->Ir.a++;
270 cachesim_I1_doref(n2->instr_addr, n2->instr_len,
271 &n2->parent->Ir.m1, &n2->parent->Ir.m2);
272 n2->parent->Ir.a++;
sewardj5155dec2005-10-12 10:09:23 +0000273}
274
275static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000276void log_3I_0D_cache_access(InstrInfo* n, InstrInfo* n2, InstrInfo* n3)
sewardj5155dec2005-10-12 10:09:23 +0000277{
278 //VG_(printf)("3I_0D : CC1addr=0x%010lx, i1addr=0x%010lx, i1size=%lu\n"
279 // " CC2addr=0x%010lx, i2addr=0x%010lx, i2size=%lu\n"
280 // " CC3addr=0x%010lx, i3addr=0x%010lx, i3size=%lu\n",
281 // n, n->instr_addr, n->instr_len,
282 // n2, n2->instr_addr, n2->instr_len,
283 // n3, n3->instr_addr, n3->instr_len);
sewardj5155dec2005-10-12 10:09:23 +0000284 cachesim_I1_doref(n->instr_addr, n->instr_len,
285 &n->parent->Ir.m1, &n->parent->Ir.m2);
286 n->parent->Ir.a++;
287 cachesim_I1_doref(n2->instr_addr, n2->instr_len,
288 &n2->parent->Ir.m1, &n2->parent->Ir.m2);
289 n2->parent->Ir.a++;
290 cachesim_I1_doref(n3->instr_addr, n3->instr_len,
291 &n3->parent->Ir.m1, &n3->parent->Ir.m2);
292 n3->parent->Ir.a++;
sewardj5155dec2005-10-12 10:09:23 +0000293}
294
295static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000296void log_1I_1Dr_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
sewardj5155dec2005-10-12 10:09:23 +0000297{
298 //VG_(printf)("1I_1Dr: CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n"
299 // " daddr=0x%010lx, dsize=%lu\n",
300 // n, n->instr_addr, n->instr_len, data_addr, data_size);
njn6a3009b2005-03-20 00:20:06 +0000301 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000302 &n->parent->Ir.m1, &n->parent->Ir.m2);
303 n->parent->Ir.a++;
njn25e49d8e72002-09-23 09:36:25 +0000304
sewardj5155dec2005-10-12 10:09:23 +0000305 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000306 &n->parent->Dr.m1, &n->parent->Dr.m2);
307 n->parent->Dr.a++;
njn25e49d8e72002-09-23 09:36:25 +0000308}
309
sewardj5155dec2005-10-12 10:09:23 +0000310static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000311void log_1I_1Dw_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
njn25e49d8e72002-09-23 09:36:25 +0000312{
sewardj5155dec2005-10-12 10:09:23 +0000313 //VG_(printf)("1I_1Dw: CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n"
314 // " daddr=0x%010lx, dsize=%lu\n",
315 // n, n->instr_addr, n->instr_len, data_addr, data_size);
njn6a3009b2005-03-20 00:20:06 +0000316 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000317 &n->parent->Ir.m1, &n->parent->Ir.m2);
318 n->parent->Ir.a++;
319
sewardj5155dec2005-10-12 10:09:23 +0000320 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000321 &n->parent->Dw.m1, &n->parent->Dw.m2);
322 n->parent->Dw.a++;
njn25e49d8e72002-09-23 09:36:25 +0000323}
324
njnaf839f52005-06-23 03:27:57 +0000325static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000326void log_0I_1Dr_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
njn25e49d8e72002-09-23 09:36:25 +0000327{
sewardj5155dec2005-10-12 10:09:23 +0000328 //VG_(printf)("0I_1Dr: CCaddr=0x%010lx, daddr=0x%010lx, dsize=%lu\n",
329 // n, data_addr, data_size);
sewardj5155dec2005-10-12 10:09:23 +0000330 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000331 &n->parent->Dr.m1, &n->parent->Dr.m2);
332 n->parent->Dr.a++;
sewardj5155dec2005-10-12 10:09:23 +0000333}
334
335static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000336void log_0I_1Dw_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
sewardj5155dec2005-10-12 10:09:23 +0000337{
338 //VG_(printf)("0I_1Dw: CCaddr=0x%010lx, daddr=0x%010lx, dsize=%lu\n",
339 // n, data_addr, data_size);
sewardj5155dec2005-10-12 10:09:23 +0000340 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000341 &n->parent->Dw.m1, &n->parent->Dw.m2);
342 n->parent->Dw.a++;
njn25e49d8e72002-09-23 09:36:25 +0000343}
344
nethercote9313ac42004-07-06 21:54:20 +0000345/*------------------------------------------------------------*/
sewardj5155dec2005-10-12 10:09:23 +0000346/*--- Instrumentation types and structures ---*/
347/*------------------------------------------------------------*/
348
349/* Maintain an ordered list of memory events which are outstanding, in
350 the sense that no IR has yet been generated to do the relevant
351 helper calls. The BB is scanned top to bottom and memory events
352 are added to the end of the list, merging with the most recent
353 notified event where possible (Dw immediately following Dr and
354 having the same size and EA can be merged).
355
356 This merging is done so that for architectures which have
357 load-op-store instructions (x86, amd64), the insn is treated as if
358 it makes just one memory reference (a modify), rather than two (a
359 read followed by a write at the same address).
360
361 At various points the list will need to be flushed, that is, IR
362 generated from it. That must happen before any possible exit from
363 the block (the end, or an IRStmt_Exit). Flushing also takes place
364 when there is no space to add a new event.
365
366 If we require the simulation statistics to be up to date with
367 respect to possible memory exceptions, then the list would have to
368 be flushed before each memory reference. That would however lose
369 performance by inhibiting event-merging during flushing.
370
371 Flushing the list consists of walking it start to end and emitting
372 instrumentation IR for each event, in the order in which they
373 appear. It may be possible to emit a single call for two adjacent
374 events in order to reduce the number of helper function calls made.
375 For example, it could well be profitable to handle two adjacent Ir
376 events with a single helper call. */
377
378typedef
379 IRExpr
380 IRAtom;
381
382typedef
sewardj20edebf2005-10-12 10:29:40 +0000383 enum { Event_Ir, Event_Dr, Event_Dw, Event_Dm }
sewardj5155dec2005-10-12 10:09:23 +0000384 EventKind;
385
386typedef
387 struct {
njnfd9f6222005-10-16 00:17:37 +0000388 EventKind ekind; // All
389 InstrInfo* inode; // All; inode for this event's instruction
390 Int datasize; // Dr/Dw/Dm only
391 IRAtom* dataEA; // Dr/Dw/Dm only; IR ATOM ONLY
sewardj5155dec2005-10-12 10:09:23 +0000392 }
393 Event;
394
395/* Up to this many unnotified events are allowed. Number is
396 arbitrary. Larger numbers allow more event merging to occur, but
397 potentially induce more spilling due to extending live ranges of
398 address temporaries. */
399#define N_EVENTS 16
400
401
402/* A struct which holds all the running state during instrumentation.
403 Mostly to avoid passing loads of parameters everywhere. */
404typedef
405 struct {
406 /* The current outstanding-memory-event list. */
407 Event events[N_EVENTS];
408 Int events_used;
409
njnd3bef4f2005-10-15 17:46:18 +0000410 /* The array of InstrInfo bins for the BB. */
sewardj0b9d74a2006-12-24 02:24:11 +0000411 SB_info* sbInfo;
sewardj5155dec2005-10-12 10:09:23 +0000412
njnd3bef4f2005-10-15 17:46:18 +0000413 /* Number InstrInfo bins 'used' so far. */
sewardj0b9d74a2006-12-24 02:24:11 +0000414 Int sbInfo_i;
sewardj5155dec2005-10-12 10:09:23 +0000415
sewardj0b9d74a2006-12-24 02:24:11 +0000416 /* The output SB being constructed. */
417 IRSB* sbOut;
sewardj5155dec2005-10-12 10:09:23 +0000418 }
419 CgState;
420
421
sewardj5155dec2005-10-12 10:09:23 +0000422/*------------------------------------------------------------*/
423/*--- Instrumentation main ---*/
nethercote9313ac42004-07-06 21:54:20 +0000424/*------------------------------------------------------------*/
425
sewardj4ba057c2005-10-18 12:04:18 +0000426// Note that origAddr is the real origAddr, not the address of the first
427// instruction in the block (they can be different due to redirection).
nethercote564b2b02004-08-07 15:54:53 +0000428static
sewardj0b9d74a2006-12-24 02:24:11 +0000429SB_info* get_SB_info(IRSB* sbIn, Addr origAddr)
nethercote9313ac42004-07-06 21:54:20 +0000430{
njn4bd67b52005-08-11 00:47:10 +0000431 Int i, n_instrs;
432 IRStmt* st;
sewardj0b9d74a2006-12-24 02:24:11 +0000433 SB_info* sbInfo;
njnd3bef4f2005-10-15 17:46:18 +0000434
sewardj0b9d74a2006-12-24 02:24:11 +0000435 // Count number of original instrs in SB
njn6a3009b2005-03-20 00:20:06 +0000436 n_instrs = 0;
sewardj0b9d74a2006-12-24 02:24:11 +0000437 for (i = 0; i < sbIn->stmts_used; i++) {
438 st = sbIn->stmts[i];
njn6a3009b2005-03-20 00:20:06 +0000439 if (Ist_IMark == st->tag) n_instrs++;
nethercote9313ac42004-07-06 21:54:20 +0000440 }
441
njnf7d26092005-10-12 16:45:17 +0000442 // Check that we don't have an entry for this BB in the instr-info table.
443 // If this assertion fails, there has been some screwup: some
444 // translations must have been discarded but Cachegrind hasn't discarded
445 // the corresponding entries in the instr-info table.
sewardj0b9d74a2006-12-24 02:24:11 +0000446 sbInfo = VG_(OSet_Lookup)(instrInfoTable, &origAddr);
447 tl_assert(NULL == sbInfo);
sewardja3a29a52005-10-12 16:16:03 +0000448
njnd3bef4f2005-10-15 17:46:18 +0000449 // BB never translated before (at this address, at least; could have
450 // been unloaded and then reloaded elsewhere in memory)
sewardj0b9d74a2006-12-24 02:24:11 +0000451 sbInfo = VG_(OSet_AllocNode)(instrInfoTable,
452 sizeof(SB_info) + n_instrs*sizeof(InstrInfo));
453 sbInfo->SB_addr = origAddr;
454 sbInfo->n_instrs = n_instrs;
455 VG_(OSet_Insert)( instrInfoTable, sbInfo );
sewardja3a29a52005-10-12 16:16:03 +0000456 distinct_instrs++;
457
sewardj0b9d74a2006-12-24 02:24:11 +0000458 return sbInfo;
nethercote9313ac42004-07-06 21:54:20 +0000459}
njn6a3009b2005-03-20 00:20:06 +0000460
nethercote9313ac42004-07-06 21:54:20 +0000461
sewardj5155dec2005-10-12 10:09:23 +0000462static void showEvent ( Event* ev )
nethercote9313ac42004-07-06 21:54:20 +0000463{
sewardj5155dec2005-10-12 10:09:23 +0000464 switch (ev->ekind) {
465 case Event_Ir:
njnfd9f6222005-10-16 00:17:37 +0000466 VG_(printf)("Ir %p\n", ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000467 break;
468 case Event_Dr:
njnfd9f6222005-10-16 00:17:37 +0000469 VG_(printf)("Dr %p %d EA=", ev->inode, ev->datasize);
sewardj5155dec2005-10-12 10:09:23 +0000470 ppIRExpr(ev->dataEA);
471 VG_(printf)("\n");
472 break;
473 case Event_Dw:
njnfd9f6222005-10-16 00:17:37 +0000474 VG_(printf)("Dw %p %d EA=", ev->inode, ev->datasize);
sewardj5155dec2005-10-12 10:09:23 +0000475 ppIRExpr(ev->dataEA);
476 VG_(printf)("\n");
477 break;
478 case Event_Dm:
njnfd9f6222005-10-16 00:17:37 +0000479 VG_(printf)("Dm %p %d EA=", ev->inode, ev->datasize);
sewardj5155dec2005-10-12 10:09:23 +0000480 ppIRExpr(ev->dataEA);
481 VG_(printf)("\n");
482 break;
483 default:
484 tl_assert(0);
485 break;
486 }
njn6a3009b2005-03-20 00:20:06 +0000487}
488
njnfd9f6222005-10-16 00:17:37 +0000489// Reserve and initialise an InstrInfo for the first mention of a new insn.
490static
491InstrInfo* setup_InstrInfo ( CgState* cgs, Addr instr_addr, UInt instr_len )
njn6a3009b2005-03-20 00:20:06 +0000492{
njnd3bef4f2005-10-15 17:46:18 +0000493 InstrInfo* i_node;
sewardj0b9d74a2006-12-24 02:24:11 +0000494 tl_assert(cgs->sbInfo_i >= 0);
495 tl_assert(cgs->sbInfo_i < cgs->sbInfo->n_instrs);
496 i_node = &cgs->sbInfo->instrs[ cgs->sbInfo_i ];
njnfd9f6222005-10-16 00:17:37 +0000497 i_node->instr_addr = instr_addr;
498 i_node->instr_len = instr_len;
499 i_node->parent = get_lineCC(instr_addr);
sewardj0b9d74a2006-12-24 02:24:11 +0000500 cgs->sbInfo_i++;
sewardj5155dec2005-10-12 10:09:23 +0000501 return i_node;
502}
sewardj17a56bf2005-03-21 01:35:02 +0000503
sewardj17a56bf2005-03-21 01:35:02 +0000504
sewardj5155dec2005-10-12 10:09:23 +0000505/* Generate code for all outstanding memory events, and mark the queue
506 empty. Code is generated into cgs->bbOut, and this activity
sewardj0b9d74a2006-12-24 02:24:11 +0000507 'consumes' slots in cgs->sbInfo. */
njn6a3009b2005-03-20 00:20:06 +0000508
sewardj5155dec2005-10-12 10:09:23 +0000509static void flushEvents ( CgState* cgs )
510{
njnd3bef4f2005-10-15 17:46:18 +0000511 Int i, regparms;
512 Char* helperName;
513 void* helperAddr;
514 IRExpr** argv;
515 IRExpr* i_node_expr;
njnd3bef4f2005-10-15 17:46:18 +0000516 IRDirty* di;
njnc285dca2005-10-15 22:07:28 +0000517 Event* ev;
518 Event* ev2;
519 Event* ev3;
njn6a3009b2005-03-20 00:20:06 +0000520
sewardj5155dec2005-10-12 10:09:23 +0000521 i = 0;
522 while (i < cgs->events_used) {
njn6a3009b2005-03-20 00:20:06 +0000523
sewardj5155dec2005-10-12 10:09:23 +0000524 helperName = NULL;
525 helperAddr = NULL;
526 argv = NULL;
527 regparms = 0;
528
529 /* generate IR to notify event i and possibly the ones
530 immediately following it. */
531 tl_assert(i >= 0 && i < cgs->events_used);
njnc285dca2005-10-15 22:07:28 +0000532
533 ev = &cgs->events[i];
534 ev2 = ( i < cgs->events_used-1 ? &cgs->events[i+1] : NULL );
535 ev3 = ( i < cgs->events_used-2 ? &cgs->events[i+2] : NULL );
536
sewardj5155dec2005-10-12 10:09:23 +0000537 if (DEBUG_CG) {
538 VG_(printf)(" flush ");
njnc285dca2005-10-15 22:07:28 +0000539 showEvent( ev );
njn4f9c9342002-04-29 16:03:24 +0000540 }
sewardj5155dec2005-10-12 10:09:23 +0000541
njnfd9f6222005-10-16 00:17:37 +0000542 i_node_expr = mkIRExpr_HWord( (HWord)ev->inode );
sewardj5155dec2005-10-12 10:09:23 +0000543
544 /* Decide on helper fn to call and args to pass it, and advance
545 i appropriately. */
njnc285dca2005-10-15 22:07:28 +0000546 switch (ev->ekind) {
sewardj5155dec2005-10-12 10:09:23 +0000547 case Event_Ir:
548 /* Merge with a following Dr/Dm if it is from this insn. */
njnc285dca2005-10-15 22:07:28 +0000549 if (ev2 && (ev2->ekind == Event_Dr || ev2->ekind == Event_Dm)) {
njnfd9f6222005-10-16 00:17:37 +0000550 tl_assert(ev2->inode == ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000551 helperName = "log_1I_1Dr_cache_access";
552 helperAddr = &log_1I_1Dr_cache_access;
553 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000554 ev2->dataEA,
njnfd9f6222005-10-16 00:17:37 +0000555 mkIRExpr_HWord( ev2->datasize ) );
sewardj5155dec2005-10-12 10:09:23 +0000556 regparms = 3;
557 i += 2;
558 }
559 /* Merge with a following Dw if it is from this insn. */
560 else
njnc285dca2005-10-15 22:07:28 +0000561 if (ev2 && ev2->ekind == Event_Dw) {
njnfd9f6222005-10-16 00:17:37 +0000562 tl_assert(ev2->inode == ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000563 helperName = "log_1I_1Dw_cache_access";
564 helperAddr = &log_1I_1Dw_cache_access;
565 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000566 ev2->dataEA,
njnfd9f6222005-10-16 00:17:37 +0000567 mkIRExpr_HWord( ev2->datasize ) );
sewardj5155dec2005-10-12 10:09:23 +0000568 regparms = 3;
569 i += 2;
570 }
571 /* Merge with two following Irs if possible. */
572 else
njnc285dca2005-10-15 22:07:28 +0000573 if (ev2 && ev3 && ev2->ekind == Event_Ir && ev3->ekind == Event_Ir)
574 {
sewardj5155dec2005-10-12 10:09:23 +0000575 helperName = "log_3I_0D_cache_access";
576 helperAddr = &log_3I_0D_cache_access;
njnfd9f6222005-10-16 00:17:37 +0000577 argv = mkIRExprVec_3( i_node_expr,
578 mkIRExpr_HWord( (HWord)ev2->inode ),
579 mkIRExpr_HWord( (HWord)ev3->inode ) );
sewardj5155dec2005-10-12 10:09:23 +0000580 regparms = 3;
581 i += 3;
582 }
583 /* Merge with a following Ir if possible. */
584 else
njnc285dca2005-10-15 22:07:28 +0000585 if (ev2 && ev2->ekind == Event_Ir) {
sewardj5155dec2005-10-12 10:09:23 +0000586 helperName = "log_2I_0D_cache_access";
587 helperAddr = &log_2I_0D_cache_access;
njnfd9f6222005-10-16 00:17:37 +0000588 argv = mkIRExprVec_2( i_node_expr,
589 mkIRExpr_HWord( (HWord)ev2->inode ) );
sewardj5155dec2005-10-12 10:09:23 +0000590 regparms = 2;
591 i += 2;
592 }
593 /* No merging possible; emit as-is. */
594 else {
njnc285dca2005-10-15 22:07:28 +0000595 // Assertion: this Event_Ir must be the last one in the
596 // events buffer, otherwise it would have been merged with a
597 // following event.
598 tl_assert(!ev2 && !ev3);
sewardj5155dec2005-10-12 10:09:23 +0000599 helperName = "log_1I_0D_cache_access";
600 helperAddr = &log_1I_0D_cache_access;
601 argv = mkIRExprVec_1( i_node_expr );
602 regparms = 1;
603 i++;
604 }
605 break;
606 case Event_Dr:
607 case Event_Dm:
608 helperName = "log_0I_1Dr_cache_access";
609 helperAddr = &log_0I_1Dr_cache_access;
610 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000611 ev->dataEA,
njnfd9f6222005-10-16 00:17:37 +0000612 mkIRExpr_HWord( ev->datasize ) );
sewardj5155dec2005-10-12 10:09:23 +0000613 regparms = 3;
614 i++;
615 break;
616 case Event_Dw:
617 helperName = "log_0I_1Dw_cache_access";
618 helperAddr = &log_0I_1Dw_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 default:
626 tl_assert(0);
627 }
628
629 /* Add the helper. */
630 tl_assert(helperName);
631 tl_assert(helperAddr);
632 tl_assert(argv);
sewardj5bb86822005-12-23 12:47:42 +0000633 di = unsafeIRDirty_0_N( regparms,
634 helperName, VG_(fnptr_to_fnentry)( helperAddr ),
635 argv );
sewardj0b9d74a2006-12-24 02:24:11 +0000636 addStmtToIRSB( cgs->sbOut, IRStmt_Dirty(di) );
njn4f9c9342002-04-29 16:03:24 +0000637 }
638
sewardj5155dec2005-10-12 10:09:23 +0000639 cgs->events_used = 0;
njn4f9c9342002-04-29 16:03:24 +0000640}
njn14d01ce2004-11-26 11:30:14 +0000641
njnfd9f6222005-10-16 00:17:37 +0000642static void addEvent_Ir ( CgState* cgs, InstrInfo* inode )
sewardj5155dec2005-10-12 10:09:23 +0000643{
644 Event* evt;
sewardj5155dec2005-10-12 10:09:23 +0000645 if (cgs->events_used == N_EVENTS)
646 flushEvents(cgs);
647 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
648 evt = &cgs->events[cgs->events_used];
njnfd9f6222005-10-16 00:17:37 +0000649 evt->ekind = Event_Ir;
650 evt->inode = inode;
651 evt->datasize = 0;
652 evt->dataEA = NULL; /*paranoia*/
sewardj5155dec2005-10-12 10:09:23 +0000653 cgs->events_used++;
654}
655
njnfd9f6222005-10-16 00:17:37 +0000656static
657void addEvent_Dr ( CgState* cgs, InstrInfo* inode, Int datasize, IRAtom* ea )
sewardj5155dec2005-10-12 10:09:23 +0000658{
njnfd9f6222005-10-16 00:17:37 +0000659 Event* evt;
sewardj5155dec2005-10-12 10:09:23 +0000660 tl_assert(isIRAtom(ea));
njnfd9f6222005-10-16 00:17:37 +0000661 tl_assert(datasize >= 1 && datasize <= MIN_LINE_SIZE);
662 if (cgs->events_used == N_EVENTS)
663 flushEvents(cgs);
664 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
665 evt = &cgs->events[cgs->events_used];
666 evt->ekind = Event_Dr;
667 evt->inode = inode;
668 evt->datasize = datasize;
669 evt->dataEA = ea;
670 cgs->events_used++;
671}
sewardj5155dec2005-10-12 10:09:23 +0000672
njnfd9f6222005-10-16 00:17:37 +0000673static
674void addEvent_Dw ( CgState* cgs, InstrInfo* inode, Int datasize, IRAtom* ea )
675{
676 Event* lastEvt;
677 Event* evt;
678
679 tl_assert(isIRAtom(ea));
680 tl_assert(datasize >= 1 && datasize <= MIN_LINE_SIZE);
681
682 /* Is it possible to merge this write with the preceding read? */
683 lastEvt = &cgs->events[cgs->events_used-1];
sewardj5155dec2005-10-12 10:09:23 +0000684 if (cgs->events_used > 0
njnfd9f6222005-10-16 00:17:37 +0000685 && lastEvt->ekind == Event_Dr
686 && lastEvt->datasize == datasize
687 && lastEvt->inode == inode
688 && eqIRAtom(lastEvt->dataEA, ea))
689 {
690 lastEvt->ekind = Event_Dm;
sewardj5155dec2005-10-12 10:09:23 +0000691 return;
692 }
693
694 /* No. Add as normal. */
695 if (cgs->events_used == N_EVENTS)
696 flushEvents(cgs);
697 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
njnfd9f6222005-10-16 00:17:37 +0000698 evt = &cgs->events[cgs->events_used];
699 evt->ekind = Event_Dw;
700 evt->inode = inode;
701 evt->datasize = datasize;
702 evt->dataEA = ea;
sewardj5155dec2005-10-12 10:09:23 +0000703 cgs->events_used++;
704}
705
706////////////////////////////////////////////////////////////
707
708
sewardj4ba057c2005-10-18 12:04:18 +0000709static
sewardj0b9d74a2006-12-24 02:24:11 +0000710IRSB* cg_instrument ( VgCallbackClosure* closure,
711 IRSB* sbIn,
sewardj461df9c2006-01-17 02:06:39 +0000712 VexGuestLayout* layout,
713 VexGuestExtents* vge,
sewardj4ba057c2005-10-18 12:04:18 +0000714 IRType gWordTy, IRType hWordTy )
njn14d01ce2004-11-26 11:30:14 +0000715{
njnfd9f6222005-10-16 00:17:37 +0000716 Int i, isize;
sewardj5155dec2005-10-12 10:09:23 +0000717 IRStmt* st;
718 Addr64 cia; /* address of current insn */
719 CgState cgs;
sewardj0b9d74a2006-12-24 02:24:11 +0000720 IRTypeEnv* tyenv = sbIn->tyenv;
njnfd9f6222005-10-16 00:17:37 +0000721 InstrInfo* curr_inode = NULL;
sewardj5155dec2005-10-12 10:09:23 +0000722
sewardjd54babf2005-03-21 00:55:49 +0000723 if (gWordTy != hWordTy) {
724 /* We don't currently support this case. */
725 VG_(tool_panic)("host/guest word size mismatch");
726 }
727
sewardj0b9d74a2006-12-24 02:24:11 +0000728 // Set up new SB
729 cgs.sbOut = deepCopyIRSBExceptStmts(sbIn);
njn6a3009b2005-03-20 00:20:06 +0000730
sewardja9f538c2005-10-23 12:06:55 +0000731 // Copy verbatim any IR preamble preceding the first IMark
njn6a3009b2005-03-20 00:20:06 +0000732 i = 0;
sewardj0b9d74a2006-12-24 02:24:11 +0000733 while (i < sbIn->stmts_used && sbIn->stmts[i]->tag != Ist_IMark) {
734 addStmtToIRSB( cgs.sbOut, sbIn->stmts[i] );
sewardja9f538c2005-10-23 12:06:55 +0000735 i++;
736 }
737
738 // Get the first statement, and initial cia from it
sewardj0b9d74a2006-12-24 02:24:11 +0000739 tl_assert(sbIn->stmts_used > 0);
740 tl_assert(i < sbIn->stmts_used);
741 st = sbIn->stmts[i];
njn6a3009b2005-03-20 00:20:06 +0000742 tl_assert(Ist_IMark == st->tag);
sewardj5155dec2005-10-12 10:09:23 +0000743 cia = st->Ist.IMark.addr;
njn6a3009b2005-03-20 00:20:06 +0000744
sewardj5155dec2005-10-12 10:09:23 +0000745 // Set up running state and get block info
sewardj3a384b32006-01-22 01:12:51 +0000746 tl_assert(closure->readdr == vge->base[0]);
sewardj5155dec2005-10-12 10:09:23 +0000747 cgs.events_used = 0;
sewardj0b9d74a2006-12-24 02:24:11 +0000748 cgs.sbInfo = get_SB_info(sbIn, (Addr)closure->readdr);
749 cgs.sbInfo_i = 0;
njn6a3009b2005-03-20 00:20:06 +0000750
sewardj5155dec2005-10-12 10:09:23 +0000751 if (DEBUG_CG)
752 VG_(printf)("\n\n---------- cg_instrument ----------\n");
njn6a3009b2005-03-20 00:20:06 +0000753
njnfd9f6222005-10-16 00:17:37 +0000754 // Traverse the block, initialising inodes, adding events and flushing as
755 // necessary.
sewardj0b9d74a2006-12-24 02:24:11 +0000756 for (/*use current i*/; i < sbIn->stmts_used; i++) {
njn6a3009b2005-03-20 00:20:06 +0000757
sewardj0b9d74a2006-12-24 02:24:11 +0000758 st = sbIn->stmts[i];
sewardj5155dec2005-10-12 10:09:23 +0000759 tl_assert(isFlatIRStmt(st));
njnb3507ea2005-08-02 23:07:02 +0000760
sewardj5155dec2005-10-12 10:09:23 +0000761 switch (st->tag) {
762 case Ist_NoOp:
763 case Ist_AbiHint:
764 case Ist_Put:
765 case Ist_PutI:
766 case Ist_MFence:
767 break;
njn20677cc2005-08-12 23:47:51 +0000768
sewardj5155dec2005-10-12 10:09:23 +0000769 case Ist_IMark:
njnfd9f6222005-10-16 00:17:37 +0000770 cia = st->Ist.IMark.addr;
771 isize = st->Ist.IMark.len;
772
773 // If Vex fails to decode an instruction, the size will be zero.
774 // Pretend otherwise.
775 if (isize == 0) isize = VG_MIN_INSTR_SZB;
776
njna5ad9ba2005-11-10 15:20:37 +0000777 // Sanity-check size.
778 tl_assert( (VG_MIN_INSTR_SZB <= isize && isize <= VG_MAX_INSTR_SZB)
779 || VG_CLREQ_SZB == isize );
njnfd9f6222005-10-16 00:17:37 +0000780
781 // Get space for and init the inode, record it as the current one.
782 // Subsequent Dr/Dw/Dm events from the same instruction will
783 // also use it.
784 curr_inode = setup_InstrInfo(&cgs, cia, isize);
785
786 addEvent_Ir( &cgs, curr_inode );
sewardj5155dec2005-10-12 10:09:23 +0000787 break;
788
sewardj0b9d74a2006-12-24 02:24:11 +0000789 case Ist_WrTmp: {
790 IRExpr* data = st->Ist.WrTmp.data;
sewardj5155dec2005-10-12 10:09:23 +0000791 if (data->tag == Iex_Load) {
792 IRExpr* aexpr = data->Iex.Load.addr;
sewardj5155dec2005-10-12 10:09:23 +0000793 // Note also, endianness info is ignored. I guess
794 // that's not interesting.
njnfd9f6222005-10-16 00:17:37 +0000795 addEvent_Dr( &cgs, curr_inode, sizeofIRType(data->Iex.Load.ty),
796 aexpr );
sewardj5155dec2005-10-12 10:09:23 +0000797 }
798 break;
njnb3507ea2005-08-02 23:07:02 +0000799 }
800
sewardj5155dec2005-10-12 10:09:23 +0000801 case Ist_Store: {
802 IRExpr* data = st->Ist.Store.data;
803 IRExpr* aexpr = st->Ist.Store.addr;
njnfd9f6222005-10-16 00:17:37 +0000804 addEvent_Dw( &cgs, curr_inode,
805 sizeofIRType(typeOfIRExpr(tyenv, data)), aexpr );
sewardj5155dec2005-10-12 10:09:23 +0000806 break;
807 }
njnb3507ea2005-08-02 23:07:02 +0000808
sewardj5155dec2005-10-12 10:09:23 +0000809 case Ist_Dirty: {
810 Int dataSize;
811 IRDirty* d = st->Ist.Dirty.details;
812 if (d->mFx != Ifx_None) {
njnfd9f6222005-10-16 00:17:37 +0000813 /* This dirty helper accesses memory. Collect the details. */
sewardj5155dec2005-10-12 10:09:23 +0000814 tl_assert(d->mAddr != NULL);
815 tl_assert(d->mSize != 0);
816 dataSize = d->mSize;
817 // Large (eg. 28B, 108B, 512B on x86) data-sized
818 // instructions will be done inaccurately, but they're
819 // very rare and this avoids errors from hitting more
820 // than two cache lines in the simulation.
821 if (dataSize > MIN_LINE_SIZE)
822 dataSize = MIN_LINE_SIZE;
823 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
njnfd9f6222005-10-16 00:17:37 +0000824 addEvent_Dr( &cgs, curr_inode, dataSize, d->mAddr );
sewardj5155dec2005-10-12 10:09:23 +0000825 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
njnfd9f6222005-10-16 00:17:37 +0000826 addEvent_Dw( &cgs, curr_inode, dataSize, d->mAddr );
sewardj5155dec2005-10-12 10:09:23 +0000827 } else {
828 tl_assert(d->mAddr == NULL);
829 tl_assert(d->mSize == 0);
830 }
831 break;
832 }
njn6a3009b2005-03-20 00:20:06 +0000833
sewardj5155dec2005-10-12 10:09:23 +0000834 case Ist_Exit:
835 /* We may never reach the next statement, so need to flush
836 all outstanding transactions now. */
837 flushEvents( &cgs );
838 break;
839
840 default:
841 tl_assert(0);
842 break;
njnb3507ea2005-08-02 23:07:02 +0000843 }
njn6a3009b2005-03-20 00:20:06 +0000844
sewardj5155dec2005-10-12 10:09:23 +0000845 /* Copy the original statement */
sewardj0b9d74a2006-12-24 02:24:11 +0000846 addStmtToIRSB( cgs.sbOut, st );
njn6a3009b2005-03-20 00:20:06 +0000847
sewardj5155dec2005-10-12 10:09:23 +0000848 if (DEBUG_CG) {
849 ppIRStmt(st);
850 VG_(printf)("\n");
851 }
852 }
853
854 /* At the end of the bb. Flush outstandings. */
sewardj5155dec2005-10-12 10:09:23 +0000855 flushEvents( &cgs );
856
sewardj5155dec2005-10-12 10:09:23 +0000857 /* done. stay sane ... */
sewardj0b9d74a2006-12-24 02:24:11 +0000858 tl_assert(cgs.sbInfo_i == cgs.sbInfo->n_instrs);
sewardj5155dec2005-10-12 10:09:23 +0000859
860 if (DEBUG_CG) {
861 VG_(printf)( "goto {");
sewardj0b9d74a2006-12-24 02:24:11 +0000862 ppIRJumpKind(sbIn->jumpkind);
sewardj5155dec2005-10-12 10:09:23 +0000863 VG_(printf)( "} ");
sewardj0b9d74a2006-12-24 02:24:11 +0000864 ppIRExpr( sbIn->next );
sewardj5155dec2005-10-12 10:09:23 +0000865 VG_(printf)( "}\n");
866 }
867
sewardj0b9d74a2006-12-24 02:24:11 +0000868 return cgs.sbOut;
njn14d01ce2004-11-26 11:30:14 +0000869}
njn4f9c9342002-04-29 16:03:24 +0000870
871/*------------------------------------------------------------*/
nethercoteb35a8b92004-09-11 16:45:27 +0000872/*--- Cache configuration ---*/
njn4f9c9342002-04-29 16:03:24 +0000873/*------------------------------------------------------------*/
874
sewardjb5f6f512005-03-10 23:59:00 +0000875#define UNDEFINED_CACHE { -1, -1, -1 }
njn25e49d8e72002-09-23 09:36:25 +0000876
877static cache_t clo_I1_cache = UNDEFINED_CACHE;
878static cache_t clo_D1_cache = UNDEFINED_CACHE;
879static cache_t clo_L2_cache = UNDEFINED_CACHE;
880
njn7cf0bd32002-06-08 13:36:03 +0000881/* Checks cache config is ok; makes it so if not. */
sewardj07133bf2002-06-13 10:25:56 +0000882static
njna1d1a642004-11-26 18:36:02 +0000883void check_cache(cache_t* cache, Char *name)
njn7cf0bd32002-06-08 13:36:03 +0000884{
885 /* First check they're all powers of two */
sewardj07133bf2002-06-13 10:25:56 +0000886 if (-1 == VG_(log2)(cache->size)) {
njn7cf0bd32002-06-08 13:36:03 +0000887 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000888 "error: %s size of %dB not a power of two; aborting.",
889 name, cache->size);
890 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000891 }
892
sewardj07133bf2002-06-13 10:25:56 +0000893 if (-1 == VG_(log2)(cache->assoc)) {
njn7cf0bd32002-06-08 13:36:03 +0000894 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000895 "error: %s associativity of %d not a power of two; aborting.",
896 name, cache->assoc);
897 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000898 }
899
sewardj07133bf2002-06-13 10:25:56 +0000900 if (-1 == VG_(log2)(cache->line_size)) {
njn7cf0bd32002-06-08 13:36:03 +0000901 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000902 "error: %s line size of %dB not a power of two; aborting.",
903 name, cache->line_size);
904 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000905 }
906
njn6a3009b2005-03-20 00:20:06 +0000907 // Then check line size >= 16 -- any smaller and a single instruction could
908 // straddle three cache lines, which breaks a simulation assertion and is
909 // stupid anyway.
njn7cf0bd32002-06-08 13:36:03 +0000910 if (cache->line_size < MIN_LINE_SIZE) {
911 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000912 "error: %s line size of %dB too small; aborting.",
913 name, cache->line_size);
914 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000915 }
916
917 /* Then check cache size > line size (causes seg faults if not). */
918 if (cache->size <= cache->line_size) {
919 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000920 "error: %s cache size of %dB <= line size of %dB; aborting.",
921 name, cache->size, cache->line_size);
922 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000923 }
924
925 /* Then check assoc <= (size / line size) (seg faults otherwise). */
926 if (cache->assoc > (cache->size / cache->line_size)) {
927 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000928 "warning: %s associativity > (size / line size); aborting.", name);
929 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000930 }
931}
932
sewardj07133bf2002-06-13 10:25:56 +0000933static
nethercoteb35a8b92004-09-11 16:45:27 +0000934void configure_caches(cache_t* I1c, cache_t* D1c, cache_t* L2c)
njn7cf0bd32002-06-08 13:36:03 +0000935{
nethercote9313ac42004-07-06 21:54:20 +0000936#define DEFINED(L) (-1 != L.size || -1 != L.assoc || -1 != L.line_size)
937
nethercoteb35a8b92004-09-11 16:45:27 +0000938 Int n_clos = 0;
nethercote9313ac42004-07-06 21:54:20 +0000939
nethercoteb35a8b92004-09-11 16:45:27 +0000940 // Count how many were defined on the command line.
941 if (DEFINED(clo_I1_cache)) { n_clos++; }
942 if (DEFINED(clo_D1_cache)) { n_clos++; }
943 if (DEFINED(clo_L2_cache)) { n_clos++; }
njn7cf0bd32002-06-08 13:36:03 +0000944
njna1d1a642004-11-26 18:36:02 +0000945 // Set the cache config (using auto-detection, if supported by the
946 // architecture)
njnaf839f52005-06-23 03:27:57 +0000947 VG_(configure_caches)( I1c, D1c, L2c, (3 == n_clos) );
sewardjb1a77a42002-07-13 13:31:20 +0000948
nethercote9313ac42004-07-06 21:54:20 +0000949 // Then replace with any defined on the command line.
nethercoteb35a8b92004-09-11 16:45:27 +0000950 if (DEFINED(clo_I1_cache)) { *I1c = clo_I1_cache; }
951 if (DEFINED(clo_D1_cache)) { *D1c = clo_D1_cache; }
952 if (DEFINED(clo_L2_cache)) { *L2c = clo_L2_cache; }
njn7cf0bd32002-06-08 13:36:03 +0000953
nethercote9313ac42004-07-06 21:54:20 +0000954 // Then check values and fix if not acceptable.
njna1d1a642004-11-26 18:36:02 +0000955 check_cache(I1c, "I1");
956 check_cache(D1c, "D1");
957 check_cache(L2c, "L2");
njn7cf0bd32002-06-08 13:36:03 +0000958
959 if (VG_(clo_verbosity) > 1) {
960 VG_(message)(Vg_UserMsg, "Cache configuration used:");
961 VG_(message)(Vg_UserMsg, " I1: %dB, %d-way, %dB lines",
962 I1c->size, I1c->assoc, I1c->line_size);
963 VG_(message)(Vg_UserMsg, " D1: %dB, %d-way, %dB lines",
964 D1c->size, D1c->assoc, D1c->line_size);
965 VG_(message)(Vg_UserMsg, " L2: %dB, %d-way, %dB lines",
966 L2c->size, L2c->assoc, L2c->line_size);
967 }
nethercote9313ac42004-07-06 21:54:20 +0000968#undef CMD_LINE_DEFINED
njn7cf0bd32002-06-08 13:36:03 +0000969}
970
njn4f9c9342002-04-29 16:03:24 +0000971/*------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +0000972/*--- cg_fini() and related function ---*/
njn4f9c9342002-04-29 16:03:24 +0000973/*------------------------------------------------------------*/
974
nethercote9313ac42004-07-06 21:54:20 +0000975// Total reads/writes/misses. Calculated during CC traversal at the end.
976// All auto-zeroed.
977static CC Ir_total;
978static CC Dr_total;
979static CC Dw_total;
980
sewardje1216cb2007-02-07 19:55:30 +0000981// The output file base name specified by the user using the
982// --cachegrind-out-file switch. This is combined with the
983// process ID and optional user-supplied qualifier (from
984// --log-file-qualifier) to produce the name stored in
985// cachegrind_out_file.
986static Char* cachegrind_out_file_basename = "cachegrind.out";
987
988// The final, completed name for the output file.
989static Char* cachegrind_out_file = NULL;
990
nethercote9313ac42004-07-06 21:54:20 +0000991
nethercote9313ac42004-07-06 21:54:20 +0000992static void fprint_CC_table_and_calc_totals(void)
993{
njnd3bef4f2005-10-15 17:46:18 +0000994 Int i, fd;
sewardj92645592005-07-23 09:18:34 +0000995 SysRes sres;
njnd3bef4f2005-10-15 17:46:18 +0000996 Char buf[512], *currFile = NULL, *currFn = NULL;
997 LineCC* lineCC;
njn4f9c9342002-04-29 16:03:24 +0000998
sewardj92645592005-07-23 09:18:34 +0000999 sres = VG_(open)(cachegrind_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
1000 VKI_S_IRUSR|VKI_S_IWUSR);
1001 if (sres.isError) {
nethercote9313ac42004-07-06 21:54:20 +00001002 // If the file can't be opened for whatever reason (conflict
1003 // between multiple cachegrinded processes?), give up now.
njnee0e6a32005-04-24 00:21:01 +00001004 VG_(message)(Vg_UserMsg,
njn02bc4b82005-05-15 17:28:26 +00001005 "error: can't open cache simulation output file '%s'",
njnee0e6a32005-04-24 00:21:01 +00001006 cachegrind_out_file );
1007 VG_(message)(Vg_UserMsg,
1008 " ... so simulation results will be missing.");
sewardj0744b6c2002-12-11 00:45:42 +00001009 return;
sewardj92645592005-07-23 09:18:34 +00001010 } else {
sewardje8089302006-10-17 02:15:17 +00001011 fd = sres.res;
sewardj0744b6c2002-12-11 00:45:42 +00001012 }
njn4f9c9342002-04-29 16:03:24 +00001013
nethercote9313ac42004-07-06 21:54:20 +00001014 // "desc:" lines (giving I1/D1/L2 cache configuration). The spaces after
1015 // the 2nd colon makes cg_annotate's output look nicer.
1016 VG_(sprintf)(buf, "desc: I1 cache: %s\n"
1017 "desc: D1 cache: %s\n"
1018 "desc: L2 cache: %s\n",
1019 I1.desc_line, D1.desc_line, L2.desc_line);
njn7cf0bd32002-06-08 13:36:03 +00001020 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njn4f9c9342002-04-29 16:03:24 +00001021
nethercote9313ac42004-07-06 21:54:20 +00001022 // "cmd:" line
njn4f9c9342002-04-29 16:03:24 +00001023 VG_(strcpy)(buf, "cmd:");
1024 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
sewardj45f4e7c2005-09-27 19:20:21 +00001025 if (VG_(args_the_exename)) {
1026 VG_(write)(fd, " ", 1);
1027 VG_(write)(fd, VG_(args_the_exename),
1028 VG_(strlen)( VG_(args_the_exename) ));
1029 }
sewardj14c7cc52007-02-25 15:08:24 +00001030 for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
1031 HChar* arg = * (HChar**) VG_(indexXA)( VG_(args_for_client), i );
1032 if (arg) {
sewardj45f4e7c2005-09-27 19:20:21 +00001033 VG_(write)(fd, " ", 1);
sewardj14c7cc52007-02-25 15:08:24 +00001034 VG_(write)(fd, arg, VG_(strlen)( arg ));
sewardj45f4e7c2005-09-27 19:20:21 +00001035 }
njn4f9c9342002-04-29 16:03:24 +00001036 }
nethercote9313ac42004-07-06 21:54:20 +00001037 // "events:" line
njn4f9c9342002-04-29 16:03:24 +00001038 VG_(sprintf)(buf, "\nevents: Ir I1mr I2mr Dr D1mr D2mr Dw D1mw D2mw\n");
1039 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1040
njnd3bef4f2005-10-15 17:46:18 +00001041 // Traverse every lineCC
1042 VG_(OSet_ResetIter)(CC_table);
1043 while ( (lineCC = VG_(OSet_Next)(CC_table)) ) {
njn4311fe62005-12-08 23:18:50 +00001044 Bool just_hit_a_new_file = False;
njnd3bef4f2005-10-15 17:46:18 +00001045 // If we've hit a new file, print a "fl=" line. Note that because
1046 // each string is stored exactly once in the string table, we can use
1047 // pointer comparison rather than strcmp() to test for equality, which
1048 // is good because most of the time the comparisons are equal and so
njn4311fe62005-12-08 23:18:50 +00001049 // the whole strings would have to be checked.
njnd3bef4f2005-10-15 17:46:18 +00001050 if ( lineCC->loc.file != currFile ) {
1051 currFile = lineCC->loc.file;
1052 VG_(sprintf)(buf, "fl=%s\n", currFile);
njn4f9c9342002-04-29 16:03:24 +00001053 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njnd3bef4f2005-10-15 17:46:18 +00001054 distinct_files++;
njn4311fe62005-12-08 23:18:50 +00001055 just_hit_a_new_file = True;
njn4f9c9342002-04-29 16:03:24 +00001056 }
njn4311fe62005-12-08 23:18:50 +00001057 // If we've hit a new function, print a "fn=" line. We know to do
1058 // this when the function name changes, and also every time we hit a
1059 // new file (in which case the new function name might be the same as
1060 // in the old file, hence the just_hit_a_new_file test).
1061 if ( just_hit_a_new_file || lineCC->loc.fn != currFn ) {
njnd3bef4f2005-10-15 17:46:18 +00001062 currFn = lineCC->loc.fn;
1063 VG_(sprintf)(buf, "fn=%s\n", currFn);
1064 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1065 distinct_fns++;
njn4311fe62005-12-08 23:18:50 +00001066 just_hit_a_new_file = False;
njnd3bef4f2005-10-15 17:46:18 +00001067 }
1068
1069 // Print the LineCC
1070 VG_(sprintf)(buf, "%u %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
1071 lineCC->loc.line,
1072 lineCC->Ir.a, lineCC->Ir.m1, lineCC->Ir.m2,
1073 lineCC->Dr.a, lineCC->Dr.m1, lineCC->Dr.m2,
1074 lineCC->Dw.a, lineCC->Dw.m1, lineCC->Dw.m2);
1075 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1076
1077 // Update summary stats
1078 Ir_total.a += lineCC->Ir.a;
1079 Ir_total.m1 += lineCC->Ir.m1;
1080 Ir_total.m2 += lineCC->Ir.m2;
1081 Dr_total.a += lineCC->Dr.a;
1082 Dr_total.m1 += lineCC->Dr.m1;
1083 Dr_total.m2 += lineCC->Dr.m2;
1084 Dw_total.a += lineCC->Dw.a;
1085 Dw_total.m1 += lineCC->Dw.m1;
1086 Dw_total.m2 += lineCC->Dw.m2;
1087
1088 distinct_lines++;
njn4f9c9342002-04-29 16:03:24 +00001089 }
1090
nethercote9313ac42004-07-06 21:54:20 +00001091 // Summary stats must come after rest of table, since we calculate them
1092 // during traversal. */
njn4f9c9342002-04-29 16:03:24 +00001093 VG_(sprintf)(buf, "summary: "
nethercote9313ac42004-07-06 21:54:20 +00001094 "%llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
njn4f9c9342002-04-29 16:03:24 +00001095 Ir_total.a, Ir_total.m1, Ir_total.m2,
1096 Dr_total.a, Dr_total.m1, Dr_total.m2,
1097 Dw_total.a, Dw_total.m1, Dw_total.m2);
1098 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1099 VG_(close)(fd);
1100}
1101
njn607adfc2003-09-30 14:15:44 +00001102static UInt ULong_width(ULong n)
njn4f9c9342002-04-29 16:03:24 +00001103{
njn607adfc2003-09-30 14:15:44 +00001104 UInt w = 0;
1105 while (n > 0) {
1106 n = n / 10;
1107 w++;
njn4f9c9342002-04-29 16:03:24 +00001108 }
sewardj46c59b12005-11-01 02:20:19 +00001109 if (w == 0) w = 1;
njn607adfc2003-09-30 14:15:44 +00001110 return w + (w-1)/3; // add space for commas
njn4f9c9342002-04-29 16:03:24 +00001111}
1112
njn51d827b2005-05-09 01:02:08 +00001113static void cg_fini(Int exitcode)
njn4f9c9342002-04-29 16:03:24 +00001114{
njn1baf7db2006-04-18 22:34:48 +00001115 static Char buf1[128], buf2[128], buf3[128], buf4[123], fmt[128];
njn607adfc2003-09-30 14:15:44 +00001116
njn4f9c9342002-04-29 16:03:24 +00001117 CC D_total;
njn1d021fa2002-05-02 13:56:34 +00001118 ULong L2_total_m, L2_total_mr, L2_total_mw,
1119 L2_total, L2_total_r, L2_total_w;
njn4f9c9342002-04-29 16:03:24 +00001120 Int l1, l2, l3;
1121 Int p;
1122
nethercote9313ac42004-07-06 21:54:20 +00001123 fprint_CC_table_and_calc_totals();
njn4f9c9342002-04-29 16:03:24 +00001124
njn7cf0bd32002-06-08 13:36:03 +00001125 if (VG_(clo_verbosity) == 0)
1126 return;
1127
njn4f9c9342002-04-29 16:03:24 +00001128 /* I cache results. Use the I_refs value to determine the first column
1129 * width. */
njn607adfc2003-09-30 14:15:44 +00001130 l1 = ULong_width(Ir_total.a);
1131 l2 = ULong_width(Dr_total.a);
1132 l3 = ULong_width(Dw_total.a);
njn4f9c9342002-04-29 16:03:24 +00001133
njn607adfc2003-09-30 14:15:44 +00001134 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001135 VG_(sprintf)(fmt, "%%s %%,%dllu", l1);
njnd3bef4f2005-10-15 17:46:18 +00001136
njn607adfc2003-09-30 14:15:44 +00001137 VG_(message)(Vg_UserMsg, fmt, "I refs: ", Ir_total.a);
1138 VG_(message)(Vg_UserMsg, fmt, "I1 misses: ", Ir_total.m1);
1139 VG_(message)(Vg_UserMsg, fmt, "L2i misses: ", Ir_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001140
1141 p = 100;
1142
njn25e49d8e72002-09-23 09:36:25 +00001143 if (0 == Ir_total.a) Ir_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001144 VG_(percentify)(Ir_total.m1, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001145 VG_(message)(Vg_UserMsg, "I1 miss rate: %s", buf1);
njnd3bef4f2005-10-15 17:46:18 +00001146
njn856c54e2005-06-26 18:43:40 +00001147 VG_(percentify)(Ir_total.m2, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001148 VG_(message)(Vg_UserMsg, "L2i miss rate: %s", buf1);
1149 VG_(message)(Vg_UserMsg, "");
1150
1151 /* D cache results. Use the D_refs.rd and D_refs.wr values to determine the
1152 * width of columns 2 & 3. */
1153 D_total.a = Dr_total.a + Dw_total.a;
1154 D_total.m1 = Dr_total.m1 + Dw_total.m1;
1155 D_total.m2 = Dr_total.m2 + Dw_total.m2;
njnd3bef4f2005-10-15 17:46:18 +00001156
njn607adfc2003-09-30 14:15:44 +00001157 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001158 VG_(sprintf)(fmt, "%%s %%,%dllu (%%,%dllu rd + %%,%dllu wr)", l1, l2, l3);
njn4f9c9342002-04-29 16:03:24 +00001159
njn607adfc2003-09-30 14:15:44 +00001160 VG_(message)(Vg_UserMsg, fmt, "D refs: ",
1161 D_total.a, Dr_total.a, Dw_total.a);
1162 VG_(message)(Vg_UserMsg, fmt, "D1 misses: ",
1163 D_total.m1, Dr_total.m1, Dw_total.m1);
1164 VG_(message)(Vg_UserMsg, fmt, "L2d misses: ",
1165 D_total.m2, Dr_total.m2, Dw_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001166
1167 p = 10;
njnd3bef4f2005-10-15 17:46:18 +00001168
njn25e49d8e72002-09-23 09:36:25 +00001169 if (0 == D_total.a) D_total.a = 1;
1170 if (0 == Dr_total.a) Dr_total.a = 1;
1171 if (0 == Dw_total.a) Dw_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001172 VG_(percentify)( D_total.m1, D_total.a, 1, l1+1, buf1);
1173 VG_(percentify)(Dr_total.m1, Dr_total.a, 1, l2+1, buf2);
1174 VG_(percentify)(Dw_total.m1, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001175 VG_(message)(Vg_UserMsg, "D1 miss rate: %s (%s + %s )", buf1, buf2,buf3);
1176
njn856c54e2005-06-26 18:43:40 +00001177 VG_(percentify)( D_total.m2, D_total.a, 1, l1+1, buf1);
1178 VG_(percentify)(Dr_total.m2, Dr_total.a, 1, l2+1, buf2);
1179 VG_(percentify)(Dw_total.m2, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001180 VG_(message)(Vg_UserMsg, "L2d miss rate: %s (%s + %s )", buf1, buf2,buf3);
1181 VG_(message)(Vg_UserMsg, "");
1182
1183 /* L2 overall results */
njn1d021fa2002-05-02 13:56:34 +00001184
1185 L2_total = Dr_total.m1 + Dw_total.m1 + Ir_total.m1;
1186 L2_total_r = Dr_total.m1 + Ir_total.m1;
1187 L2_total_w = Dw_total.m1;
njn607adfc2003-09-30 14:15:44 +00001188 VG_(message)(Vg_UserMsg, fmt, "L2 refs: ",
1189 L2_total, L2_total_r, L2_total_w);
njn1d021fa2002-05-02 13:56:34 +00001190
njn4f9c9342002-04-29 16:03:24 +00001191 L2_total_m = Dr_total.m2 + Dw_total.m2 + Ir_total.m2;
1192 L2_total_mr = Dr_total.m2 + Ir_total.m2;
1193 L2_total_mw = Dw_total.m2;
njn607adfc2003-09-30 14:15:44 +00001194 VG_(message)(Vg_UserMsg, fmt, "L2 misses: ",
1195 L2_total_m, L2_total_mr, L2_total_mw);
njn4f9c9342002-04-29 16:03:24 +00001196
njn856c54e2005-06-26 18:43:40 +00001197 VG_(percentify)(L2_total_m, (Ir_total.a + D_total.a), 1, l1+1, buf1);
1198 VG_(percentify)(L2_total_mr, (Ir_total.a + Dr_total.a), 1, l2+1, buf2);
1199 VG_(percentify)(L2_total_mw, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001200 VG_(message)(Vg_UserMsg, "L2 miss rate: %s (%s + %s )", buf1, buf2,buf3);
njnd3bef4f2005-10-15 17:46:18 +00001201
njn4f9c9342002-04-29 16:03:24 +00001202
nethercote9313ac42004-07-06 21:54:20 +00001203 // Various stats
njn4f9c9342002-04-29 16:03:24 +00001204 if (VG_(clo_verbosity) > 1) {
njn1baf7db2006-04-18 22:34:48 +00001205 Int debug_lookups = full_debugs + fn_debugs +
1206 file_line_debugs + no_debugs;
njnd3bef4f2005-10-15 17:46:18 +00001207
njn1baf7db2006-04-18 22:34:48 +00001208 VG_(message)(Vg_DebugMsg, "");
1209 VG_(message)(Vg_DebugMsg, "cachegrind: distinct files: %d", distinct_files);
1210 VG_(message)(Vg_DebugMsg, "cachegrind: distinct fns: %d", distinct_fns);
1211 VG_(message)(Vg_DebugMsg, "cachegrind: distinct lines: %d", distinct_lines);
1212 VG_(message)(Vg_DebugMsg, "cachegrind: distinct instrs:%d", distinct_instrs);
1213 VG_(message)(Vg_DebugMsg, "cachegrind: debug lookups : %d", debug_lookups);
1214
1215 VG_(percentify)(full_debugs, debug_lookups, 1, 6, buf1);
1216 VG_(percentify)(file_line_debugs, debug_lookups, 1, 6, buf2);
1217 VG_(percentify)(fn_debugs, debug_lookups, 1, 6, buf3);
1218 VG_(percentify)(no_debugs, debug_lookups, 1, 6, buf4);
1219 VG_(message)(Vg_DebugMsg, "cachegrind: with full info:%s (%d)",
1220 buf1, full_debugs);
1221 VG_(message)(Vg_DebugMsg, "cachegrind: with file/line info:%s (%d)",
1222 buf2, file_line_debugs);
1223 VG_(message)(Vg_DebugMsg, "cachegrind: with fn name info:%s (%d)",
1224 buf3, fn_debugs);
1225 VG_(message)(Vg_DebugMsg, "cachegrind: with zero info:%s (%d)",
1226 buf4, no_debugs);
1227
1228 VG_(message)(Vg_DebugMsg, "cachegrind: string table size: %u",
1229 VG_(OSet_Size)(stringTable));
1230 VG_(message)(Vg_DebugMsg, "cachegrind: CC table size: %u",
1231 VG_(OSet_Size)(CC_table));
1232 VG_(message)(Vg_DebugMsg, "cachegrind: InstrInfo table size: %u",
1233 VG_(OSet_Size)(instrInfoTable));
njn4f9c9342002-04-29 16:03:24 +00001234 }
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.
sewardj4ba057c2005-10-18 12:04:18 +00001244static
sewardj0b9d74a2006-12-24 02:24:11 +00001245void cg_discard_superblock_info ( Addr64 orig_addr64, VexGuestExtents vge )
sewardj18d75132002-05-16 11:06:21 +00001246{
sewardj0b9d74a2006-12-24 02:24:11 +00001247 SB_info* sbInfo;
sewardj3a384b32006-01-22 01:12:51 +00001248 Addr orig_addr = (Addr)vge.base[0];
njn4294fd42002-06-05 14:41:10 +00001249
sewardj5155dec2005-10-12 10:09:23 +00001250 tl_assert(vge.n_used > 0);
1251
1252 if (DEBUG_CG)
sewardj4ba057c2005-10-18 12:04:18 +00001253 VG_(printf)( "discard_basic_block_info: %p, %p, %llu\n",
1254 (void*)(Addr)orig_addr,
sewardj5155dec2005-10-12 10:09:23 +00001255 (void*)(Addr)vge.base[0], (ULong)vge.len[0]);
njn4294fd42002-06-05 14:41:10 +00001256
sewardj4ba057c2005-10-18 12:04:18 +00001257 // Get BB info, remove from table, free BB info. Simple! Note that we
1258 // use orig_addr, not the first instruction address in vge.
sewardj0b9d74a2006-12-24 02:24:11 +00001259 sbInfo = VG_(OSet_Remove)(instrInfoTable, &orig_addr);
1260 tl_assert(NULL != sbInfo);
1261 VG_(OSet_FreeNode)(instrInfoTable, sbInfo);
sewardj18d75132002-05-16 11:06:21 +00001262}
1263
1264/*--------------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001265/*--- Command line processing ---*/
1266/*--------------------------------------------------------------------*/
1267
njn0103de52005-10-10 16:49:01 +00001268static void parse_cache_opt ( cache_t* cache, Char* opt )
njn25e49d8e72002-09-23 09:36:25 +00001269{
njn0103de52005-10-10 16:49:01 +00001270 Int i = 0, i2, i3;
njn25e49d8e72002-09-23 09:36:25 +00001271
nethercote9313ac42004-07-06 21:54:20 +00001272 // Option argument looks like "65536,2,64".
1273 // Find commas, replace with NULs to make three independent
1274 // strings, then extract numbers, put NULs back. Yuck.
njn25e49d8e72002-09-23 09:36:25 +00001275 while (VG_(isdigit)(opt[i])) i++;
1276 if (',' == opt[i]) {
1277 opt[i++] = '\0';
1278 i2 = i;
1279 } else goto bad;
1280 while (VG_(isdigit)(opt[i])) i++;
1281 if (',' == opt[i]) {
1282 opt[i++] = '\0';
1283 i3 = i;
1284 } else goto bad;
1285 while (VG_(isdigit)(opt[i])) i++;
1286 if ('\0' != opt[i]) goto bad;
1287
nethercote9313ac42004-07-06 21:54:20 +00001288 cache->size = (Int)VG_(atoll)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001289 cache->assoc = (Int)VG_(atoll)(opt + i2);
1290 cache->line_size = (Int)VG_(atoll)(opt + i3);
1291
nethercote9313ac42004-07-06 21:54:20 +00001292 opt[i2-1] = ',';
1293 opt[i3-1] = ',';
njn25e49d8e72002-09-23 09:36:25 +00001294 return;
1295
1296 bad:
sewardj6893d652006-10-15 01:25:13 +00001297 VG_(err_bad_option)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001298}
1299
njn51d827b2005-05-09 01:02:08 +00001300static Bool cg_process_cmd_line_option(Char* arg)
njn25e49d8e72002-09-23 09:36:25 +00001301{
nethercote9313ac42004-07-06 21:54:20 +00001302 // 5 is length of "--I1="
njn39c86652003-05-21 10:13:39 +00001303 if (VG_CLO_STREQN(5, arg, "--I1="))
nethercote9313ac42004-07-06 21:54:20 +00001304 parse_cache_opt(&clo_I1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001305 else if (VG_CLO_STREQN(5, arg, "--D1="))
nethercote9313ac42004-07-06 21:54:20 +00001306 parse_cache_opt(&clo_D1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001307 else if (VG_CLO_STREQN(5, arg, "--L2="))
nethercote9313ac42004-07-06 21:54:20 +00001308 parse_cache_opt(&clo_L2_cache, &arg[5]);
sewardje1216cb2007-02-07 19:55:30 +00001309 else if (VG_CLO_STREQN(22, arg, "--cachegrind-out-file=")) {
1310 cachegrind_out_file_basename = &arg[22];
1311 }
njn25e49d8e72002-09-23 09:36:25 +00001312 else
1313 return False;
1314
1315 return True;
1316}
1317
njn51d827b2005-05-09 01:02:08 +00001318static void cg_print_usage(void)
njn25e49d8e72002-09-23 09:36:25 +00001319{
njn3e884182003-04-15 13:03:23 +00001320 VG_(printf)(
njn25e49d8e72002-09-23 09:36:25 +00001321" --I1=<size>,<assoc>,<line_size> set I1 cache manually\n"
1322" --D1=<size>,<assoc>,<line_size> set D1 cache manually\n"
njn3e884182003-04-15 13:03:23 +00001323" --L2=<size>,<assoc>,<line_size> set L2 cache manually\n"
sewardje1216cb2007-02-07 19:55:30 +00001324" --cachegrind-out-file=<file> write profile data to <file>.<pid>\n"
1325" [cachegrind.out.<pid>]\n"
njn3e884182003-04-15 13:03:23 +00001326 );
1327}
1328
njn51d827b2005-05-09 01:02:08 +00001329static void cg_print_debug_usage(void)
njn3e884182003-04-15 13:03:23 +00001330{
1331 VG_(printf)(
1332" (none)\n"
1333 );
njn25e49d8e72002-09-23 09:36:25 +00001334}
1335
1336/*--------------------------------------------------------------------*/
1337/*--- Setup ---*/
1338/*--------------------------------------------------------------------*/
1339
njn57ca7ab2005-06-21 23:44:58 +00001340static Char base_dir[VKI_PATH_MAX];
1341
sewardje1216cb2007-02-07 19:55:30 +00001342static void cg_post_clo_init(void); /* just below */
1343
njn51d827b2005-05-09 01:02:08 +00001344static void cg_pre_clo_init(void)
1345{
njn51d827b2005-05-09 01:02:08 +00001346 VG_(details_name) ("Cachegrind");
1347 VG_(details_version) (NULL);
1348 VG_(details_description) ("an I1/D1/L2 cache profiler");
1349 VG_(details_copyright_author)(
sewardj9ebd6e02007-01-08 06:01:59 +00001350 "Copyright (C) 2002-2007, and GNU GPL'd, by Nicholas Nethercote et al.");
njn51d827b2005-05-09 01:02:08 +00001351 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardje8089302006-10-17 02:15:17 +00001352 VG_(details_avg_translation_sizeB) ( 500 );
njn51d827b2005-05-09 01:02:08 +00001353
1354 VG_(basic_tool_funcs) (cg_post_clo_init,
1355 cg_instrument,
1356 cg_fini);
1357
sewardj0b9d74a2006-12-24 02:24:11 +00001358 VG_(needs_superblock_discards)(cg_discard_superblock_info);
njn51d827b2005-05-09 01:02:08 +00001359 VG_(needs_command_line_options)(cg_process_cmd_line_option,
1360 cg_print_usage,
1361 cg_print_debug_usage);
sewardje1216cb2007-02-07 19:55:30 +00001362}
1363
1364static void cg_post_clo_init(void)
1365{
1366 HChar* qual = NULL;
1367 cache_t I1c, D1c, L2c;
1368 Int filename_szB;
njn51d827b2005-05-09 01:02:08 +00001369
1370 /* Get working directory */
njn57ca7ab2005-06-21 23:44:58 +00001371 tl_assert( VG_(getcwd)(base_dir, VKI_PATH_MAX) );
njn51d827b2005-05-09 01:02:08 +00001372
sewardje1216cb2007-02-07 19:55:30 +00001373 /* Do we have a --log-file-qualifier= to consider? */
1374 if (VG_(clo_log_file_qualifier)) {
1375 qual = VG_(getenv)(VG_(clo_log_file_qualifier));
1376 }
1377
1378 /* Block is big enough for
1379 dir name ++ cachegrind_out_file_basename
1380 ++ ".<pid>"
1381 ++ the log file qualifier, if in use */
1382 filename_szB
1383 = VG_(strlen)(base_dir)
1384 + 1 /* "/" */
1385 + VG_(strlen)(cachegrind_out_file_basename)
1386 + 11 /* "." <pid>, assuming sizeof(pid) <= 4 */
1387 + (qual ? (10 + VG_(strlen)(qual)) : 0)
1388 + 1; /* to guarantee checkable zero at the end */
1389
1390 tl_assert(filename_szB > 0);
1391 cachegrind_out_file
1392 = VG_(calloc)( sizeof(Char), filename_szB );
1393
1394 if (qual) {
1395 VG_(sprintf)(cachegrind_out_file, "%s/%s.%d.lfq.%s",
1396 base_dir, cachegrind_out_file_basename,
1397 VG_(getpid)(), qual);
1398 } else {
1399 VG_(sprintf)(cachegrind_out_file, "%s/%s.%d",
1400 base_dir, cachegrind_out_file_basename,
1401 VG_(getpid)());
1402 }
1403
1404 tl_assert( cachegrind_out_file[filename_szB-1] == 0 );
njn51d827b2005-05-09 01:02:08 +00001405
njnd3bef4f2005-10-15 17:46:18 +00001406 CC_table = VG_(OSet_Create)(offsetof(LineCC, loc),
1407 cmp_CodeLoc_LineCC,
1408 VG_(malloc), VG_(free));
sewardj4ba057c2005-10-18 12:04:18 +00001409 instrInfoTable = VG_(OSet_Create)(/*keyOff*/0,
njnd3bef4f2005-10-15 17:46:18 +00001410 NULL,
1411 VG_(malloc), VG_(free));
1412 stringTable = VG_(OSet_Create)(/*keyOff*/0,
1413 stringCmp,
1414 VG_(malloc), VG_(free));
sewardje1216cb2007-02-07 19:55:30 +00001415
1416 configure_caches(&I1c, &D1c, &L2c);
1417
1418 cachesim_I1_initcache(I1c);
1419 cachesim_D1_initcache(D1c);
1420 cachesim_L2_initcache(L2c);
njn51d827b2005-05-09 01:02:08 +00001421}
1422
sewardj45f4e7c2005-09-27 19:20:21 +00001423VG_DETERMINE_INTERFACE_VERSION(cg_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00001424
njn25e49d8e72002-09-23 09:36:25 +00001425/*--------------------------------------------------------------------*/
njnf69f9452005-07-03 17:53:11 +00001426/*--- end ---*/
sewardj18d75132002-05-16 11:06:21 +00001427/*--------------------------------------------------------------------*/
njnd3bef4f2005-10-15 17:46:18 +00001428