blob: 78c9d6062719c5851d3f3dc4993c48775e1455a5 [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
sewardj03f8d3f2012-08-05 15:46:46 +000011 Copyright (C) 2002-2012 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"
sewardj8badbaa2007-05-08 09:20:25 +000051#include "cg_branchpred.c"
njn4f9c9342002-04-29 16:03:24 +000052
njn25e49d8e72002-09-23 09:36:25 +000053/*------------------------------------------------------------*/
54/*--- Constants ---*/
55/*------------------------------------------------------------*/
njn4f9c9342002-04-29 16:03:24 +000056
sewardj5155dec2005-10-12 10:09:23 +000057/* Set to 1 for very verbose debugging */
58#define DEBUG_CG 0
59
nethercote9313ac42004-07-06 21:54:20 +000060#define MIN_LINE_SIZE 16
njnd3bef4f2005-10-15 17:46:18 +000061#define FILE_LEN VKI_PATH_MAX
nethercote9313ac42004-07-06 21:54:20 +000062#define FN_LEN 256
njn7cf0bd32002-06-08 13:36:03 +000063
64/*------------------------------------------------------------*/
sewardj8badbaa2007-05-08 09:20:25 +000065/*--- Options ---*/
66/*------------------------------------------------------------*/
67
njn374a36d2007-11-23 01:41:32 +000068static Bool clo_cache_sim = True; /* do cache simulation? */
69static Bool clo_branch_sim = False; /* do branch simulation? */
florianee90c8a2012-10-21 02:39:42 +000070static HChar* clo_cachegrind_out_file = "cachegrind.out.%p";
sewardj8badbaa2007-05-08 09:20:25 +000071
72/*------------------------------------------------------------*/
sewardj98763d52012-06-03 22:40:07 +000073/*--- Cachesim configuration ---*/
74/*------------------------------------------------------------*/
75
76static Int min_line_size = 0; /* min of L1 and LL cache line sizes */
77
78/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +000079/*--- Types and Data Structures ---*/
njn4f9c9342002-04-29 16:03:24 +000080/*------------------------------------------------------------*/
81
sewardj8badbaa2007-05-08 09:20:25 +000082typedef
83 struct {
84 ULong a; /* total # memory accesses of this kind */
85 ULong m1; /* misses in the first level cache */
njn2d853a12010-10-06 22:46:31 +000086 ULong mL; /* misses in the second level cache */
sewardj8badbaa2007-05-08 09:20:25 +000087 }
88 CacheCC;
89
90typedef
91 struct {
92 ULong b; /* total # branches of this kind */
93 ULong mp; /* number of branches mispredicted */
94 }
95 BranchCC;
njn4f9c9342002-04-29 16:03:24 +000096
nethercote9313ac42004-07-06 21:54:20 +000097//------------------------------------------------------------
98// Primary data structure #1: CC table
99// - Holds the per-source-line hit/miss stats, grouped by file/function/line.
njnd3bef4f2005-10-15 17:46:18 +0000100// - an ordered set of CCs. CC indexing done by file/function/line (as
101// determined from the instrAddr).
nethercote9313ac42004-07-06 21:54:20 +0000102// - Traversed for dumping stats at end in file/func/line hierarchy.
njn4f9c9342002-04-29 16:03:24 +0000103
njnd3bef4f2005-10-15 17:46:18 +0000104typedef struct {
105 Char* file;
106 Char* fn;
107 Int line;
108}
109CodeLoc;
njn4f9c9342002-04-29 16:03:24 +0000110
sewardj8badbaa2007-05-08 09:20:25 +0000111typedef struct {
112 CodeLoc loc; /* Source location that these counts pertain to */
113 CacheCC Ir; /* Insn read counts */
114 CacheCC Dr; /* Data read counts */
115 CacheCC Dw; /* Data write/modify counts */
116 BranchCC Bc; /* Conditional branch counts */
117 BranchCC Bi; /* Indirect branch counts */
118} LineCC;
njn4f9c9342002-04-29 16:03:24 +0000119
njnd3bef4f2005-10-15 17:46:18 +0000120// First compare file, then fn, then line.
tom5a835d52007-12-30 12:28:26 +0000121static Word cmp_CodeLoc_LineCC(const void *vloc, const void *vcc)
njnd3bef4f2005-10-15 17:46:18 +0000122{
njnafa12262005-12-24 03:10:56 +0000123 Word res;
njnd3bef4f2005-10-15 17:46:18 +0000124 CodeLoc* a = (CodeLoc*)vloc;
125 CodeLoc* b = &(((LineCC*)vcc)->loc);
njn4f9c9342002-04-29 16:03:24 +0000126
njnd3bef4f2005-10-15 17:46:18 +0000127 res = VG_(strcmp)(a->file, b->file);
128 if (0 != res)
129 return res;
njn4f9c9342002-04-29 16:03:24 +0000130
njnd3bef4f2005-10-15 17:46:18 +0000131 res = VG_(strcmp)(a->fn, b->fn);
132 if (0 != res)
133 return res;
134
135 return a->line - b->line;
136}
137
138static OSet* CC_table;
njn4f9c9342002-04-29 16:03:24 +0000139
nethercote9313ac42004-07-06 21:54:20 +0000140//------------------------------------------------------------
njnd3bef4f2005-10-15 17:46:18 +0000141// Primary data structure #2: InstrInfo table
nethercote9313ac42004-07-06 21:54:20 +0000142// - Holds the cached info about each instr that is used for simulation.
sewardj0b9d74a2006-12-24 02:24:11 +0000143// - table(SB_start_addr, list(InstrInfo))
144// - For each SB, each InstrInfo in the list holds info about the
njnd3bef4f2005-10-15 17:46:18 +0000145// instruction (instrLen, instrAddr, etc), plus a pointer to its line
nethercote9313ac42004-07-06 21:54:20 +0000146// CC. This node is what's passed to the simulation function.
sewardj0b9d74a2006-12-24 02:24:11 +0000147// - When SBs are discarded the relevant list(instr_details) is freed.
nethercote9313ac42004-07-06 21:54:20 +0000148
njnd3bef4f2005-10-15 17:46:18 +0000149typedef struct _InstrInfo InstrInfo;
150struct _InstrInfo {
nethercoteca1f2dc2004-07-21 08:49:02 +0000151 Addr instr_addr;
njn6a3009b2005-03-20 00:20:06 +0000152 UChar instr_len;
njnd3bef4f2005-10-15 17:46:18 +0000153 LineCC* parent; // parent line-CC
nethercote9313ac42004-07-06 21:54:20 +0000154};
155
sewardj0b9d74a2006-12-24 02:24:11 +0000156typedef struct _SB_info SB_info;
157struct _SB_info {
158 Addr SB_addr; // key; MUST BE FIRST
njnd3bef4f2005-10-15 17:46:18 +0000159 Int n_instrs;
160 InstrInfo instrs[0];
nethercote9313ac42004-07-06 21:54:20 +0000161};
162
njnd3bef4f2005-10-15 17:46:18 +0000163static OSet* instrInfoTable;
164
165//------------------------------------------------------------
166// Secondary data structure: string table
167// - holds strings, avoiding dups
168// - used for filenames and function names, each of which will be
169// pointed to by one or more CCs.
170// - it also allows equality checks just by pointer comparison, which
171// is good when printing the output file at the end.
172
173static OSet* stringTable;
nethercote9313ac42004-07-06 21:54:20 +0000174
175//------------------------------------------------------------
176// Stats
sewardj4f29ddf2002-05-03 22:29:04 +0000177static Int distinct_files = 0;
178static Int distinct_fns = 0;
nethercote9313ac42004-07-06 21:54:20 +0000179static Int distinct_lines = 0;
sewardj4f29ddf2002-05-03 22:29:04 +0000180static Int distinct_instrs = 0;
nethercote9313ac42004-07-06 21:54:20 +0000181
njnd3bef4f2005-10-15 17:46:18 +0000182static Int full_debugs = 0;
183static Int file_line_debugs = 0;
184static Int fn_debugs = 0;
185static Int no_debugs = 0;
njn4f9c9342002-04-29 16:03:24 +0000186
nethercote9313ac42004-07-06 21:54:20 +0000187/*------------------------------------------------------------*/
njnd3bef4f2005-10-15 17:46:18 +0000188/*--- String table operations ---*/
189/*------------------------------------------------------------*/
190
tom5a835d52007-12-30 12:28:26 +0000191static Word stringCmp( const void* key, const void* elem )
njnd3bef4f2005-10-15 17:46:18 +0000192{
193 return VG_(strcmp)(*(Char**)key, *(Char**)elem);
194}
195
196// Get a permanent string; either pull it out of the string table if it's
197// been encountered before, or dup it and put it into the string table.
198static Char* get_perm_string(Char* s)
199{
njne2a9ad32007-09-17 05:30:48 +0000200 Char** s_ptr = VG_(OSetGen_Lookup)(stringTable, &s);
njnd3bef4f2005-10-15 17:46:18 +0000201 if (s_ptr) {
202 return *s_ptr;
203 } else {
njne2a9ad32007-09-17 05:30:48 +0000204 Char** s_node = VG_(OSetGen_AllocNode)(stringTable, sizeof(Char*));
sewardj9c606bd2008-09-18 18:12:50 +0000205 *s_node = VG_(strdup)("cg.main.gps.1", s);
njne2a9ad32007-09-17 05:30:48 +0000206 VG_(OSetGen_Insert)(stringTable, s_node);
njnd3bef4f2005-10-15 17:46:18 +0000207 return *s_node;
208 }
209}
210
211/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +0000212/*--- CC table operations ---*/
213/*------------------------------------------------------------*/
njn4294fd42002-06-05 14:41:10 +0000214
nethercote9313ac42004-07-06 21:54:20 +0000215static void get_debug_info(Addr instr_addr, Char file[FILE_LEN],
216 Char fn[FN_LEN], Int* line)
njn4f9c9342002-04-29 16:03:24 +0000217{
njnf3b61d62007-09-17 00:41:07 +0000218 Char dir[FILE_LEN];
219 Bool found_dirname;
sewardj7cee6f92005-06-13 17:39:06 +0000220 Bool found_file_line = VG_(get_filename_linenum)(
221 instr_addr,
222 file, FILE_LEN,
njnf3b61d62007-09-17 00:41:07 +0000223 dir, FILE_LEN, &found_dirname,
sewardj7cee6f92005-06-13 17:39:06 +0000224 line
225 );
nethercote9313ac42004-07-06 21:54:20 +0000226 Bool found_fn = VG_(get_fnname)(instr_addr, fn, FN_LEN);
njn4f9c9342002-04-29 16:03:24 +0000227
nethercote9313ac42004-07-06 21:54:20 +0000228 if (!found_file_line) {
229 VG_(strcpy)(file, "???");
230 *line = 0;
231 }
232 if (!found_fn) {
233 VG_(strcpy)(fn, "???");
234 }
njnf3b61d62007-09-17 00:41:07 +0000235
236 if (found_dirname) {
237 // +1 for the '/'.
238 tl_assert(VG_(strlen)(dir) + VG_(strlen)(file) + 1 < FILE_LEN);
239 VG_(strcat)(dir, "/"); // Append '/'
240 VG_(strcat)(dir, file); // Append file to dir
241 VG_(strcpy)(file, dir); // Move dir+file to file
242 }
243
nethercote9313ac42004-07-06 21:54:20 +0000244 if (found_file_line) {
njnd3bef4f2005-10-15 17:46:18 +0000245 if (found_fn) full_debugs++;
246 else file_line_debugs++;
nethercote9313ac42004-07-06 21:54:20 +0000247 } else {
njnd3bef4f2005-10-15 17:46:18 +0000248 if (found_fn) fn_debugs++;
249 else no_debugs++;
njn4f9c9342002-04-29 16:03:24 +0000250 }
251}
252
nethercote9313ac42004-07-06 21:54:20 +0000253// Do a three step traversal: by file, then fn, then line.
njnd3bef4f2005-10-15 17:46:18 +0000254// Returns a pointer to the line CC, creates a new one if necessary.
255static LineCC* get_lineCC(Addr origAddr)
nethercote9313ac42004-07-06 21:54:20 +0000256{
nethercote9313ac42004-07-06 21:54:20 +0000257 Char file[FILE_LEN], fn[FN_LEN];
258 Int line;
njnd3bef4f2005-10-15 17:46:18 +0000259 CodeLoc loc;
260 LineCC* lineCC;
nethercote9313ac42004-07-06 21:54:20 +0000261
njn6a3009b2005-03-20 00:20:06 +0000262 get_debug_info(origAddr, file, fn, &line);
nethercote9313ac42004-07-06 21:54:20 +0000263
njnd3bef4f2005-10-15 17:46:18 +0000264 loc.file = file;
265 loc.fn = fn;
266 loc.line = line;
njn4f9c9342002-04-29 16:03:24 +0000267
njne2a9ad32007-09-17 05:30:48 +0000268 lineCC = VG_(OSetGen_Lookup)(CC_table, &loc);
njnd3bef4f2005-10-15 17:46:18 +0000269 if (!lineCC) {
270 // Allocate and zero a new node.
njne2a9ad32007-09-17 05:30:48 +0000271 lineCC = VG_(OSetGen_AllocNode)(CC_table, sizeof(LineCC));
njnd3bef4f2005-10-15 17:46:18 +0000272 lineCC->loc.file = get_perm_string(loc.file);
273 lineCC->loc.fn = get_perm_string(loc.fn);
274 lineCC->loc.line = loc.line;
njn0a8db5c2007-04-02 03:11:41 +0000275 lineCC->Ir.a = 0;
276 lineCC->Ir.m1 = 0;
njn2d853a12010-10-06 22:46:31 +0000277 lineCC->Ir.mL = 0;
njn0a8db5c2007-04-02 03:11:41 +0000278 lineCC->Dr.a = 0;
279 lineCC->Dr.m1 = 0;
njn2d853a12010-10-06 22:46:31 +0000280 lineCC->Dr.mL = 0;
njn0a8db5c2007-04-02 03:11:41 +0000281 lineCC->Dw.a = 0;
282 lineCC->Dw.m1 = 0;
njn2d853a12010-10-06 22:46:31 +0000283 lineCC->Dw.mL = 0;
sewardj8badbaa2007-05-08 09:20:25 +0000284 lineCC->Bc.b = 0;
285 lineCC->Bc.mp = 0;
286 lineCC->Bi.b = 0;
287 lineCC->Bi.mp = 0;
njne2a9ad32007-09-17 05:30:48 +0000288 VG_(OSetGen_Insert)(CC_table, lineCC);
njn4f9c9342002-04-29 16:03:24 +0000289 }
nethercote9313ac42004-07-06 21:54:20 +0000290
njnd3bef4f2005-10-15 17:46:18 +0000291 return lineCC;
njn4f9c9342002-04-29 16:03:24 +0000292}
293
294/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +0000295/*--- Cache simulation functions ---*/
njn4f9c9342002-04-29 16:03:24 +0000296/*------------------------------------------------------------*/
297
njnc52b9322010-09-27 02:20:38 +0000298// Only used with --cache-sim=no.
299static VG_REGPARM(1)
300void log_1I(InstrInfo* n)
301{
302 n->parent->Ir.a++;
303}
304
305// Only used with --cache-sim=no.
306static VG_REGPARM(2)
307void log_2I(InstrInfo* n, InstrInfo* n2)
308{
309 n->parent->Ir.a++;
310 n2->parent->Ir.a++;
311}
312
313// Only used with --cache-sim=no.
314static VG_REGPARM(3)
315void log_3I(InstrInfo* n, InstrInfo* n2, InstrInfo* n3)
316{
317 n->parent->Ir.a++;
318 n2->parent->Ir.a++;
319 n3->parent->Ir.a++;
320}
321
njnaf839f52005-06-23 03:27:57 +0000322static VG_REGPARM(1)
njnd3bef4f2005-10-15 17:46:18 +0000323void log_1I_0D_cache_access(InstrInfo* n)
njn25e49d8e72002-09-23 09:36:25 +0000324{
sewardj5155dec2005-10-12 10:09:23 +0000325 //VG_(printf)("1I_0D : CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n",
326 // n, n->instr_addr, n->instr_len);
njn6a3009b2005-03-20 00:20:06 +0000327 cachesim_I1_doref(n->instr_addr, n->instr_len,
njn2d853a12010-10-06 22:46:31 +0000328 &n->parent->Ir.m1, &n->parent->Ir.mL);
nethercote9313ac42004-07-06 21:54:20 +0000329 n->parent->Ir.a++;
njn25e49d8e72002-09-23 09:36:25 +0000330}
331
njnaf839f52005-06-23 03:27:57 +0000332static VG_REGPARM(2)
njnd3bef4f2005-10-15 17:46:18 +0000333void log_2I_0D_cache_access(InstrInfo* n, InstrInfo* n2)
njn25e49d8e72002-09-23 09:36:25 +0000334{
sewardj5155dec2005-10-12 10:09:23 +0000335 //VG_(printf)("2I_0D : CC1addr=0x%010lx, i1addr=0x%010lx, i1size=%lu\n"
336 // " CC2addr=0x%010lx, i2addr=0x%010lx, i2size=%lu\n",
337 // n, n->instr_addr, n->instr_len,
338 // n2, n2->instr_addr, n2->instr_len);
sewardj5155dec2005-10-12 10:09:23 +0000339 cachesim_I1_doref(n->instr_addr, n->instr_len,
njn2d853a12010-10-06 22:46:31 +0000340 &n->parent->Ir.m1, &n->parent->Ir.mL);
sewardj5155dec2005-10-12 10:09:23 +0000341 n->parent->Ir.a++;
342 cachesim_I1_doref(n2->instr_addr, n2->instr_len,
njn2d853a12010-10-06 22:46:31 +0000343 &n2->parent->Ir.m1, &n2->parent->Ir.mL);
sewardj5155dec2005-10-12 10:09:23 +0000344 n2->parent->Ir.a++;
sewardj5155dec2005-10-12 10:09:23 +0000345}
346
347static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000348void log_3I_0D_cache_access(InstrInfo* n, InstrInfo* n2, InstrInfo* n3)
sewardj5155dec2005-10-12 10:09:23 +0000349{
350 //VG_(printf)("3I_0D : CC1addr=0x%010lx, i1addr=0x%010lx, i1size=%lu\n"
351 // " CC2addr=0x%010lx, i2addr=0x%010lx, i2size=%lu\n"
352 // " CC3addr=0x%010lx, i3addr=0x%010lx, i3size=%lu\n",
353 // n, n->instr_addr, n->instr_len,
354 // n2, n2->instr_addr, n2->instr_len,
355 // n3, n3->instr_addr, n3->instr_len);
sewardj5155dec2005-10-12 10:09:23 +0000356 cachesim_I1_doref(n->instr_addr, n->instr_len,
njn2d853a12010-10-06 22:46:31 +0000357 &n->parent->Ir.m1, &n->parent->Ir.mL);
sewardj5155dec2005-10-12 10:09:23 +0000358 n->parent->Ir.a++;
359 cachesim_I1_doref(n2->instr_addr, n2->instr_len,
njn2d853a12010-10-06 22:46:31 +0000360 &n2->parent->Ir.m1, &n2->parent->Ir.mL);
sewardj5155dec2005-10-12 10:09:23 +0000361 n2->parent->Ir.a++;
362 cachesim_I1_doref(n3->instr_addr, n3->instr_len,
njn2d853a12010-10-06 22:46:31 +0000363 &n3->parent->Ir.m1, &n3->parent->Ir.mL);
sewardj5155dec2005-10-12 10:09:23 +0000364 n3->parent->Ir.a++;
sewardj5155dec2005-10-12 10:09:23 +0000365}
366
367static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000368void log_1I_1Dr_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
sewardj5155dec2005-10-12 10:09:23 +0000369{
370 //VG_(printf)("1I_1Dr: CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n"
371 // " daddr=0x%010lx, dsize=%lu\n",
372 // n, n->instr_addr, n->instr_len, data_addr, data_size);
njn6a3009b2005-03-20 00:20:06 +0000373 cachesim_I1_doref(n->instr_addr, n->instr_len,
njn2d853a12010-10-06 22:46:31 +0000374 &n->parent->Ir.m1, &n->parent->Ir.mL);
nethercote9313ac42004-07-06 21:54:20 +0000375 n->parent->Ir.a++;
njn25e49d8e72002-09-23 09:36:25 +0000376
sewardj5155dec2005-10-12 10:09:23 +0000377 cachesim_D1_doref(data_addr, data_size,
njn2d853a12010-10-06 22:46:31 +0000378 &n->parent->Dr.m1, &n->parent->Dr.mL);
nethercote9313ac42004-07-06 21:54:20 +0000379 n->parent->Dr.a++;
njn25e49d8e72002-09-23 09:36:25 +0000380}
381
sewardj5155dec2005-10-12 10:09:23 +0000382static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000383void log_1I_1Dw_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
njn25e49d8e72002-09-23 09:36:25 +0000384{
sewardj5155dec2005-10-12 10:09:23 +0000385 //VG_(printf)("1I_1Dw: CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n"
386 // " daddr=0x%010lx, dsize=%lu\n",
387 // n, n->instr_addr, n->instr_len, data_addr, data_size);
njn6a3009b2005-03-20 00:20:06 +0000388 cachesim_I1_doref(n->instr_addr, n->instr_len,
njn2d853a12010-10-06 22:46:31 +0000389 &n->parent->Ir.m1, &n->parent->Ir.mL);
nethercote9313ac42004-07-06 21:54:20 +0000390 n->parent->Ir.a++;
391
sewardj5155dec2005-10-12 10:09:23 +0000392 cachesim_D1_doref(data_addr, data_size,
njn2d853a12010-10-06 22:46:31 +0000393 &n->parent->Dw.m1, &n->parent->Dw.mL);
nethercote9313ac42004-07-06 21:54:20 +0000394 n->parent->Dw.a++;
njn25e49d8e72002-09-23 09:36:25 +0000395}
396
njnaf839f52005-06-23 03:27:57 +0000397static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000398void log_0I_1Dr_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
njn25e49d8e72002-09-23 09:36:25 +0000399{
sewardj5155dec2005-10-12 10:09:23 +0000400 //VG_(printf)("0I_1Dr: CCaddr=0x%010lx, daddr=0x%010lx, dsize=%lu\n",
401 // n, data_addr, data_size);
sewardj5155dec2005-10-12 10:09:23 +0000402 cachesim_D1_doref(data_addr, data_size,
njn2d853a12010-10-06 22:46:31 +0000403 &n->parent->Dr.m1, &n->parent->Dr.mL);
nethercote9313ac42004-07-06 21:54:20 +0000404 n->parent->Dr.a++;
sewardj5155dec2005-10-12 10:09:23 +0000405}
406
407static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000408void log_0I_1Dw_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
sewardj5155dec2005-10-12 10:09:23 +0000409{
410 //VG_(printf)("0I_1Dw: CCaddr=0x%010lx, daddr=0x%010lx, dsize=%lu\n",
411 // n, data_addr, data_size);
sewardj5155dec2005-10-12 10:09:23 +0000412 cachesim_D1_doref(data_addr, data_size,
njn2d853a12010-10-06 22:46:31 +0000413 &n->parent->Dw.m1, &n->parent->Dw.mL);
nethercote9313ac42004-07-06 21:54:20 +0000414 n->parent->Dw.a++;
njn25e49d8e72002-09-23 09:36:25 +0000415}
416
sewardj8badbaa2007-05-08 09:20:25 +0000417/* For branches, we consult two different predictors, one which
418 predicts taken/untaken for conditional branches, and the other
419 which predicts the branch target address for indirect branches
420 (jump-to-register style ones). */
421
422static VG_REGPARM(2)
423void log_cond_branch(InstrInfo* n, Word taken)
424{
425 //VG_(printf)("cbrnch: CCaddr=0x%010lx, taken=0x%010lx\n",
426 // n, taken);
427 n->parent->Bc.b++;
428 n->parent->Bc.mp
429 += (1 & do_cond_branch_predict(n->instr_addr, taken));
430}
431
432static VG_REGPARM(2)
433void log_ind_branch(InstrInfo* n, UWord actual_dst)
434{
435 //VG_(printf)("ibrnch: CCaddr=0x%010lx, dst=0x%010lx\n",
436 // n, actual_dst);
437 n->parent->Bi.b++;
438 n->parent->Bi.mp
439 += (1 & do_ind_branch_predict(n->instr_addr, actual_dst));
440}
441
442
nethercote9313ac42004-07-06 21:54:20 +0000443/*------------------------------------------------------------*/
sewardj5155dec2005-10-12 10:09:23 +0000444/*--- Instrumentation types and structures ---*/
445/*------------------------------------------------------------*/
446
447/* Maintain an ordered list of memory events which are outstanding, in
448 the sense that no IR has yet been generated to do the relevant
449 helper calls. The BB is scanned top to bottom and memory events
450 are added to the end of the list, merging with the most recent
451 notified event where possible (Dw immediately following Dr and
452 having the same size and EA can be merged).
453
454 This merging is done so that for architectures which have
455 load-op-store instructions (x86, amd64), the insn is treated as if
456 it makes just one memory reference (a modify), rather than two (a
457 read followed by a write at the same address).
458
459 At various points the list will need to be flushed, that is, IR
460 generated from it. That must happen before any possible exit from
461 the block (the end, or an IRStmt_Exit). Flushing also takes place
462 when there is no space to add a new event.
463
464 If we require the simulation statistics to be up to date with
465 respect to possible memory exceptions, then the list would have to
466 be flushed before each memory reference. That would however lose
467 performance by inhibiting event-merging during flushing.
468
469 Flushing the list consists of walking it start to end and emitting
470 instrumentation IR for each event, in the order in which they
471 appear. It may be possible to emit a single call for two adjacent
472 events in order to reduce the number of helper function calls made.
473 For example, it could well be profitable to handle two adjacent Ir
474 events with a single helper call. */
475
476typedef
477 IRExpr
478 IRAtom;
479
480typedef
sewardj8badbaa2007-05-08 09:20:25 +0000481 enum {
482 Ev_Ir, // Instruction read
483 Ev_Dr, // Data read
484 Ev_Dw, // Data write
485 Ev_Dm, // Data modify (read then write)
486 Ev_Bc, // branch conditional
487 Ev_Bi // branch indirect (to unknown destination)
488 }
489 EventTag;
sewardj5155dec2005-10-12 10:09:23 +0000490
491typedef
492 struct {
sewardj8badbaa2007-05-08 09:20:25 +0000493 EventTag tag;
494 InstrInfo* inode;
495 union {
496 struct {
497 } Ir;
498 struct {
499 IRAtom* ea;
500 Int szB;
501 } Dr;
502 struct {
503 IRAtom* ea;
504 Int szB;
505 } Dw;
506 struct {
507 IRAtom* ea;
508 Int szB;
509 } Dm;
510 struct {
511 IRAtom* taken; /* :: Ity_I1 */
512 } Bc;
513 struct {
514 IRAtom* dst;
515 } Bi;
516 } Ev;
sewardj5155dec2005-10-12 10:09:23 +0000517 }
518 Event;
519
sewardj8badbaa2007-05-08 09:20:25 +0000520static void init_Event ( Event* ev ) {
521 VG_(memset)(ev, 0, sizeof(Event));
522}
523
524static IRAtom* get_Event_dea ( Event* ev ) {
525 switch (ev->tag) {
526 case Ev_Dr: return ev->Ev.Dr.ea;
527 case Ev_Dw: return ev->Ev.Dw.ea;
528 case Ev_Dm: return ev->Ev.Dm.ea;
529 default: tl_assert(0);
530 }
531}
532
533static Int get_Event_dszB ( Event* ev ) {
534 switch (ev->tag) {
535 case Ev_Dr: return ev->Ev.Dr.szB;
536 case Ev_Dw: return ev->Ev.Dw.szB;
537 case Ev_Dm: return ev->Ev.Dm.szB;
538 default: tl_assert(0);
539 }
540}
541
542
sewardj5155dec2005-10-12 10:09:23 +0000543/* Up to this many unnotified events are allowed. Number is
544 arbitrary. Larger numbers allow more event merging to occur, but
545 potentially induce more spilling due to extending live ranges of
546 address temporaries. */
547#define N_EVENTS 16
548
549
550/* A struct which holds all the running state during instrumentation.
551 Mostly to avoid passing loads of parameters everywhere. */
552typedef
553 struct {
554 /* The current outstanding-memory-event list. */
555 Event events[N_EVENTS];
556 Int events_used;
557
njnd3bef4f2005-10-15 17:46:18 +0000558 /* The array of InstrInfo bins for the BB. */
sewardj0b9d74a2006-12-24 02:24:11 +0000559 SB_info* sbInfo;
sewardj5155dec2005-10-12 10:09:23 +0000560
njnd3bef4f2005-10-15 17:46:18 +0000561 /* Number InstrInfo bins 'used' so far. */
sewardj0b9d74a2006-12-24 02:24:11 +0000562 Int sbInfo_i;
sewardj5155dec2005-10-12 10:09:23 +0000563
sewardj0b9d74a2006-12-24 02:24:11 +0000564 /* The output SB being constructed. */
565 IRSB* sbOut;
sewardj5155dec2005-10-12 10:09:23 +0000566 }
567 CgState;
568
569
sewardj5155dec2005-10-12 10:09:23 +0000570/*------------------------------------------------------------*/
571/*--- Instrumentation main ---*/
nethercote9313ac42004-07-06 21:54:20 +0000572/*------------------------------------------------------------*/
573
sewardj4ba057c2005-10-18 12:04:18 +0000574// Note that origAddr is the real origAddr, not the address of the first
575// instruction in the block (they can be different due to redirection).
nethercote564b2b02004-08-07 15:54:53 +0000576static
sewardj0b9d74a2006-12-24 02:24:11 +0000577SB_info* get_SB_info(IRSB* sbIn, Addr origAddr)
nethercote9313ac42004-07-06 21:54:20 +0000578{
njn4bd67b52005-08-11 00:47:10 +0000579 Int i, n_instrs;
580 IRStmt* st;
sewardj0b9d74a2006-12-24 02:24:11 +0000581 SB_info* sbInfo;
njnd3bef4f2005-10-15 17:46:18 +0000582
sewardj0b9d74a2006-12-24 02:24:11 +0000583 // Count number of original instrs in SB
njn6a3009b2005-03-20 00:20:06 +0000584 n_instrs = 0;
sewardj0b9d74a2006-12-24 02:24:11 +0000585 for (i = 0; i < sbIn->stmts_used; i++) {
586 st = sbIn->stmts[i];
njn6a3009b2005-03-20 00:20:06 +0000587 if (Ist_IMark == st->tag) n_instrs++;
nethercote9313ac42004-07-06 21:54:20 +0000588 }
589
njnf7d26092005-10-12 16:45:17 +0000590 // Check that we don't have an entry for this BB in the instr-info table.
591 // If this assertion fails, there has been some screwup: some
592 // translations must have been discarded but Cachegrind hasn't discarded
593 // the corresponding entries in the instr-info table.
njne2a9ad32007-09-17 05:30:48 +0000594 sbInfo = VG_(OSetGen_Lookup)(instrInfoTable, &origAddr);
sewardj0b9d74a2006-12-24 02:24:11 +0000595 tl_assert(NULL == sbInfo);
sewardja3a29a52005-10-12 16:16:03 +0000596
njnd3bef4f2005-10-15 17:46:18 +0000597 // BB never translated before (at this address, at least; could have
598 // been unloaded and then reloaded elsewhere in memory)
njne2a9ad32007-09-17 05:30:48 +0000599 sbInfo = VG_(OSetGen_AllocNode)(instrInfoTable,
sewardj0b9d74a2006-12-24 02:24:11 +0000600 sizeof(SB_info) + n_instrs*sizeof(InstrInfo));
601 sbInfo->SB_addr = origAddr;
602 sbInfo->n_instrs = n_instrs;
njne2a9ad32007-09-17 05:30:48 +0000603 VG_(OSetGen_Insert)( instrInfoTable, sbInfo );
sewardja3a29a52005-10-12 16:16:03 +0000604 distinct_instrs++;
605
sewardj0b9d74a2006-12-24 02:24:11 +0000606 return sbInfo;
nethercote9313ac42004-07-06 21:54:20 +0000607}
njn6a3009b2005-03-20 00:20:06 +0000608
nethercote9313ac42004-07-06 21:54:20 +0000609
sewardj5155dec2005-10-12 10:09:23 +0000610static void showEvent ( Event* ev )
nethercote9313ac42004-07-06 21:54:20 +0000611{
sewardj8badbaa2007-05-08 09:20:25 +0000612 switch (ev->tag) {
613 case Ev_Ir:
njnfd9f6222005-10-16 00:17:37 +0000614 VG_(printf)("Ir %p\n", ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000615 break;
sewardj8badbaa2007-05-08 09:20:25 +0000616 case Ev_Dr:
617 VG_(printf)("Dr %p %d EA=", ev->inode, ev->Ev.Dr.szB);
618 ppIRExpr(ev->Ev.Dr.ea);
sewardj5155dec2005-10-12 10:09:23 +0000619 VG_(printf)("\n");
620 break;
sewardj8badbaa2007-05-08 09:20:25 +0000621 case Ev_Dw:
622 VG_(printf)("Dw %p %d EA=", ev->inode, ev->Ev.Dw.szB);
623 ppIRExpr(ev->Ev.Dw.ea);
sewardj5155dec2005-10-12 10:09:23 +0000624 VG_(printf)("\n");
625 break;
sewardj8badbaa2007-05-08 09:20:25 +0000626 case Ev_Dm:
627 VG_(printf)("Dm %p %d EA=", ev->inode, ev->Ev.Dm.szB);
628 ppIRExpr(ev->Ev.Dm.ea);
629 VG_(printf)("\n");
630 break;
631 case Ev_Bc:
632 VG_(printf)("Bc %p GA=", ev->inode);
633 ppIRExpr(ev->Ev.Bc.taken);
634 VG_(printf)("\n");
635 break;
636 case Ev_Bi:
637 VG_(printf)("Bi %p DST=", ev->inode);
638 ppIRExpr(ev->Ev.Bi.dst);
sewardj5155dec2005-10-12 10:09:23 +0000639 VG_(printf)("\n");
640 break;
641 default:
642 tl_assert(0);
643 break;
644 }
njn6a3009b2005-03-20 00:20:06 +0000645}
646
njnfd9f6222005-10-16 00:17:37 +0000647// Reserve and initialise an InstrInfo for the first mention of a new insn.
648static
649InstrInfo* setup_InstrInfo ( CgState* cgs, Addr instr_addr, UInt instr_len )
njn6a3009b2005-03-20 00:20:06 +0000650{
njnd3bef4f2005-10-15 17:46:18 +0000651 InstrInfo* i_node;
sewardj0b9d74a2006-12-24 02:24:11 +0000652 tl_assert(cgs->sbInfo_i >= 0);
653 tl_assert(cgs->sbInfo_i < cgs->sbInfo->n_instrs);
654 i_node = &cgs->sbInfo->instrs[ cgs->sbInfo_i ];
njnfd9f6222005-10-16 00:17:37 +0000655 i_node->instr_addr = instr_addr;
656 i_node->instr_len = instr_len;
657 i_node->parent = get_lineCC(instr_addr);
sewardj0b9d74a2006-12-24 02:24:11 +0000658 cgs->sbInfo_i++;
sewardj5155dec2005-10-12 10:09:23 +0000659 return i_node;
660}
sewardj17a56bf2005-03-21 01:35:02 +0000661
sewardj17a56bf2005-03-21 01:35:02 +0000662
sewardj5155dec2005-10-12 10:09:23 +0000663/* Generate code for all outstanding memory events, and mark the queue
664 empty. Code is generated into cgs->bbOut, and this activity
sewardj0b9d74a2006-12-24 02:24:11 +0000665 'consumes' slots in cgs->sbInfo. */
njn6a3009b2005-03-20 00:20:06 +0000666
sewardj5155dec2005-10-12 10:09:23 +0000667static void flushEvents ( CgState* cgs )
668{
njnd3bef4f2005-10-15 17:46:18 +0000669 Int i, regparms;
florianee90c8a2012-10-21 02:39:42 +0000670 const HChar* helperName;
njnd3bef4f2005-10-15 17:46:18 +0000671 void* helperAddr;
672 IRExpr** argv;
673 IRExpr* i_node_expr;
njnd3bef4f2005-10-15 17:46:18 +0000674 IRDirty* di;
njnc285dca2005-10-15 22:07:28 +0000675 Event* ev;
676 Event* ev2;
677 Event* ev3;
njn6a3009b2005-03-20 00:20:06 +0000678
sewardj5155dec2005-10-12 10:09:23 +0000679 i = 0;
680 while (i < cgs->events_used) {
njn6a3009b2005-03-20 00:20:06 +0000681
sewardj5155dec2005-10-12 10:09:23 +0000682 helperName = NULL;
683 helperAddr = NULL;
684 argv = NULL;
685 regparms = 0;
686
687 /* generate IR to notify event i and possibly the ones
688 immediately following it. */
689 tl_assert(i >= 0 && i < cgs->events_used);
njnc285dca2005-10-15 22:07:28 +0000690
691 ev = &cgs->events[i];
692 ev2 = ( i < cgs->events_used-1 ? &cgs->events[i+1] : NULL );
693 ev3 = ( i < cgs->events_used-2 ? &cgs->events[i+2] : NULL );
694
sewardj5155dec2005-10-12 10:09:23 +0000695 if (DEBUG_CG) {
696 VG_(printf)(" flush ");
njnc285dca2005-10-15 22:07:28 +0000697 showEvent( ev );
njn4f9c9342002-04-29 16:03:24 +0000698 }
sewardj5155dec2005-10-12 10:09:23 +0000699
njnfd9f6222005-10-16 00:17:37 +0000700 i_node_expr = mkIRExpr_HWord( (HWord)ev->inode );
sewardj5155dec2005-10-12 10:09:23 +0000701
702 /* Decide on helper fn to call and args to pass it, and advance
703 i appropriately. */
sewardj8badbaa2007-05-08 09:20:25 +0000704 switch (ev->tag) {
705 case Ev_Ir:
706 /* Merge an Ir with a following Dr/Dm. */
707 if (ev2 && (ev2->tag == Ev_Dr || ev2->tag == Ev_Dm)) {
708 /* Why is this true? It's because we're merging an Ir
709 with a following Dr or Dm. The Ir derives from the
710 instruction's IMark and the Dr/Dm from data
711 references which follow it. In short it holds
712 because each insn starts with an IMark, hence an
713 Ev_Ir, and so these Dr/Dm must pertain to the
714 immediately preceding Ir. Same applies to analogous
715 assertions in the subsequent cases. */
njnfd9f6222005-10-16 00:17:37 +0000716 tl_assert(ev2->inode == ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000717 helperName = "log_1I_1Dr_cache_access";
718 helperAddr = &log_1I_1Dr_cache_access;
719 argv = mkIRExprVec_3( i_node_expr,
sewardj8badbaa2007-05-08 09:20:25 +0000720 get_Event_dea(ev2),
721 mkIRExpr_HWord( get_Event_dszB(ev2) ) );
sewardj5155dec2005-10-12 10:09:23 +0000722 regparms = 3;
723 i += 2;
724 }
sewardj8badbaa2007-05-08 09:20:25 +0000725 /* Merge an Ir with a following Dw. */
sewardj5155dec2005-10-12 10:09:23 +0000726 else
sewardj8badbaa2007-05-08 09:20:25 +0000727 if (ev2 && ev2->tag == Ev_Dw) {
njnfd9f6222005-10-16 00:17:37 +0000728 tl_assert(ev2->inode == ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000729 helperName = "log_1I_1Dw_cache_access";
730 helperAddr = &log_1I_1Dw_cache_access;
731 argv = mkIRExprVec_3( i_node_expr,
sewardj8badbaa2007-05-08 09:20:25 +0000732 get_Event_dea(ev2),
733 mkIRExpr_HWord( get_Event_dszB(ev2) ) );
sewardj5155dec2005-10-12 10:09:23 +0000734 regparms = 3;
735 i += 2;
736 }
sewardj8badbaa2007-05-08 09:20:25 +0000737 /* Merge an Ir with two following Irs. */
sewardj5155dec2005-10-12 10:09:23 +0000738 else
sewardj8badbaa2007-05-08 09:20:25 +0000739 if (ev2 && ev3 && ev2->tag == Ev_Ir && ev3->tag == Ev_Ir)
njnc285dca2005-10-15 22:07:28 +0000740 {
njnc52b9322010-09-27 02:20:38 +0000741 if (clo_cache_sim) {
742 helperName = "log_3I_0D_cache_access";
743 helperAddr = &log_3I_0D_cache_access;
744 } else {
745 helperName = "log_3I";
746 helperAddr = &log_3I;
747 }
njnfd9f6222005-10-16 00:17:37 +0000748 argv = mkIRExprVec_3( i_node_expr,
749 mkIRExpr_HWord( (HWord)ev2->inode ),
750 mkIRExpr_HWord( (HWord)ev3->inode ) );
sewardj5155dec2005-10-12 10:09:23 +0000751 regparms = 3;
752 i += 3;
753 }
sewardj8badbaa2007-05-08 09:20:25 +0000754 /* Merge an Ir with one following Ir. */
sewardj5155dec2005-10-12 10:09:23 +0000755 else
sewardj8badbaa2007-05-08 09:20:25 +0000756 if (ev2 && ev2->tag == Ev_Ir) {
njnc52b9322010-09-27 02:20:38 +0000757 if (clo_cache_sim) {
758 helperName = "log_2I_0D_cache_access";
759 helperAddr = &log_2I_0D_cache_access;
760 } else {
761 helperName = "log_2I";
762 helperAddr = &log_2I;
763 }
njnfd9f6222005-10-16 00:17:37 +0000764 argv = mkIRExprVec_2( i_node_expr,
765 mkIRExpr_HWord( (HWord)ev2->inode ) );
sewardj5155dec2005-10-12 10:09:23 +0000766 regparms = 2;
767 i += 2;
768 }
769 /* No merging possible; emit as-is. */
770 else {
njnc52b9322010-09-27 02:20:38 +0000771 if (clo_cache_sim) {
772 helperName = "log_1I_0D_cache_access";
773 helperAddr = &log_1I_0D_cache_access;
774 } else {
775 helperName = "log_1I";
776 helperAddr = &log_1I;
777 }
sewardj5155dec2005-10-12 10:09:23 +0000778 argv = mkIRExprVec_1( i_node_expr );
779 regparms = 1;
780 i++;
781 }
782 break;
sewardj8badbaa2007-05-08 09:20:25 +0000783 case Ev_Dr:
784 case Ev_Dm:
785 /* Data read or modify */
sewardj5155dec2005-10-12 10:09:23 +0000786 helperName = "log_0I_1Dr_cache_access";
787 helperAddr = &log_0I_1Dr_cache_access;
788 argv = mkIRExprVec_3( i_node_expr,
sewardj8badbaa2007-05-08 09:20:25 +0000789 get_Event_dea(ev),
790 mkIRExpr_HWord( get_Event_dszB(ev) ) );
sewardj5155dec2005-10-12 10:09:23 +0000791 regparms = 3;
792 i++;
793 break;
sewardj8badbaa2007-05-08 09:20:25 +0000794 case Ev_Dw:
795 /* Data write */
sewardj5155dec2005-10-12 10:09:23 +0000796 helperName = "log_0I_1Dw_cache_access";
797 helperAddr = &log_0I_1Dw_cache_access;
798 argv = mkIRExprVec_3( i_node_expr,
sewardj8badbaa2007-05-08 09:20:25 +0000799 get_Event_dea(ev),
800 mkIRExpr_HWord( get_Event_dszB(ev) ) );
sewardj5155dec2005-10-12 10:09:23 +0000801 regparms = 3;
802 i++;
803 break;
sewardj8badbaa2007-05-08 09:20:25 +0000804 case Ev_Bc:
805 /* Conditional branch */
806 helperName = "log_cond_branch";
807 helperAddr = &log_cond_branch;
808 argv = mkIRExprVec_2( i_node_expr, ev->Ev.Bc.taken );
809 regparms = 2;
810 i++;
811 break;
812 case Ev_Bi:
813 /* Branch to an unknown destination */
814 helperName = "log_ind_branch";
815 helperAddr = &log_ind_branch;
816 argv = mkIRExprVec_2( i_node_expr, ev->Ev.Bi.dst );
817 regparms = 2;
818 i++;
819 break;
sewardj5155dec2005-10-12 10:09:23 +0000820 default:
821 tl_assert(0);
822 }
823
824 /* Add the helper. */
825 tl_assert(helperName);
826 tl_assert(helperAddr);
827 tl_assert(argv);
sewardj5bb86822005-12-23 12:47:42 +0000828 di = unsafeIRDirty_0_N( regparms,
829 helperName, VG_(fnptr_to_fnentry)( helperAddr ),
830 argv );
sewardj0b9d74a2006-12-24 02:24:11 +0000831 addStmtToIRSB( cgs->sbOut, IRStmt_Dirty(di) );
njn4f9c9342002-04-29 16:03:24 +0000832 }
833
sewardj5155dec2005-10-12 10:09:23 +0000834 cgs->events_used = 0;
njn4f9c9342002-04-29 16:03:24 +0000835}
njn14d01ce2004-11-26 11:30:14 +0000836
njnfd9f6222005-10-16 00:17:37 +0000837static void addEvent_Ir ( CgState* cgs, InstrInfo* inode )
sewardj5155dec2005-10-12 10:09:23 +0000838{
839 Event* evt;
sewardj5155dec2005-10-12 10:09:23 +0000840 if (cgs->events_used == N_EVENTS)
841 flushEvents(cgs);
842 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
843 evt = &cgs->events[cgs->events_used];
sewardj8badbaa2007-05-08 09:20:25 +0000844 init_Event(evt);
845 evt->tag = Ev_Ir;
njnfd9f6222005-10-16 00:17:37 +0000846 evt->inode = inode;
sewardj5155dec2005-10-12 10:09:23 +0000847 cgs->events_used++;
848}
849
njnfd9f6222005-10-16 00:17:37 +0000850static
851void addEvent_Dr ( CgState* cgs, InstrInfo* inode, Int datasize, IRAtom* ea )
sewardj5155dec2005-10-12 10:09:23 +0000852{
njnfd9f6222005-10-16 00:17:37 +0000853 Event* evt;
sewardj5155dec2005-10-12 10:09:23 +0000854 tl_assert(isIRAtom(ea));
sewardj98763d52012-06-03 22:40:07 +0000855 tl_assert(datasize >= 1 && datasize <= min_line_size);
sewardj8badbaa2007-05-08 09:20:25 +0000856 if (!clo_cache_sim)
857 return;
njnfd9f6222005-10-16 00:17:37 +0000858 if (cgs->events_used == N_EVENTS)
859 flushEvents(cgs);
860 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
861 evt = &cgs->events[cgs->events_used];
sewardj8badbaa2007-05-08 09:20:25 +0000862 init_Event(evt);
863 evt->tag = Ev_Dr;
864 evt->inode = inode;
865 evt->Ev.Dr.szB = datasize;
866 evt->Ev.Dr.ea = ea;
njnfd9f6222005-10-16 00:17:37 +0000867 cgs->events_used++;
868}
sewardj5155dec2005-10-12 10:09:23 +0000869
njnfd9f6222005-10-16 00:17:37 +0000870static
871void addEvent_Dw ( CgState* cgs, InstrInfo* inode, Int datasize, IRAtom* ea )
872{
873 Event* lastEvt;
874 Event* evt;
875
876 tl_assert(isIRAtom(ea));
sewardj98763d52012-06-03 22:40:07 +0000877 tl_assert(datasize >= 1 && datasize <= min_line_size);
njnfd9f6222005-10-16 00:17:37 +0000878
sewardj8badbaa2007-05-08 09:20:25 +0000879 if (!clo_cache_sim)
880 return;
881
njnfd9f6222005-10-16 00:17:37 +0000882 /* Is it possible to merge this write with the preceding read? */
883 lastEvt = &cgs->events[cgs->events_used-1];
sewardj5155dec2005-10-12 10:09:23 +0000884 if (cgs->events_used > 0
sewardj8badbaa2007-05-08 09:20:25 +0000885 && lastEvt->tag == Ev_Dr
886 && lastEvt->Ev.Dr.szB == datasize
887 && lastEvt->inode == inode
888 && eqIRAtom(lastEvt->Ev.Dr.ea, ea))
njnfd9f6222005-10-16 00:17:37 +0000889 {
sewardj8badbaa2007-05-08 09:20:25 +0000890 lastEvt->tag = Ev_Dm;
sewardj5155dec2005-10-12 10:09:23 +0000891 return;
892 }
893
894 /* No. Add as normal. */
895 if (cgs->events_used == N_EVENTS)
896 flushEvents(cgs);
897 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
njnfd9f6222005-10-16 00:17:37 +0000898 evt = &cgs->events[cgs->events_used];
sewardj8badbaa2007-05-08 09:20:25 +0000899 init_Event(evt);
900 evt->tag = Ev_Dw;
901 evt->inode = inode;
902 evt->Ev.Dw.szB = datasize;
903 evt->Ev.Dw.ea = ea;
904 cgs->events_used++;
905}
906
907static
908void addEvent_Bc ( CgState* cgs, InstrInfo* inode, IRAtom* guard )
909{
910 Event* evt;
911 tl_assert(isIRAtom(guard));
912 tl_assert(typeOfIRExpr(cgs->sbOut->tyenv, guard)
913 == (sizeof(HWord)==4 ? Ity_I32 : Ity_I64));
914 if (!clo_branch_sim)
915 return;
916 if (cgs->events_used == N_EVENTS)
917 flushEvents(cgs);
918 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
919 evt = &cgs->events[cgs->events_used];
920 init_Event(evt);
921 evt->tag = Ev_Bc;
922 evt->inode = inode;
923 evt->Ev.Bc.taken = guard;
924 cgs->events_used++;
925}
926
927static
928void addEvent_Bi ( CgState* cgs, InstrInfo* inode, IRAtom* whereTo )
929{
930 Event* evt;
931 tl_assert(isIRAtom(whereTo));
932 tl_assert(typeOfIRExpr(cgs->sbOut->tyenv, whereTo)
933 == (sizeof(HWord)==4 ? Ity_I32 : Ity_I64));
934 if (!clo_branch_sim)
935 return;
936 if (cgs->events_used == N_EVENTS)
937 flushEvents(cgs);
938 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
939 evt = &cgs->events[cgs->events_used];
940 init_Event(evt);
941 evt->tag = Ev_Bi;
942 evt->inode = inode;
943 evt->Ev.Bi.dst = whereTo;
sewardj5155dec2005-10-12 10:09:23 +0000944 cgs->events_used++;
945}
946
947////////////////////////////////////////////////////////////
948
949
sewardj4ba057c2005-10-18 12:04:18 +0000950static
sewardj0b9d74a2006-12-24 02:24:11 +0000951IRSB* cg_instrument ( VgCallbackClosure* closure,
952 IRSB* sbIn,
sewardj461df9c2006-01-17 02:06:39 +0000953 VexGuestLayout* layout,
954 VexGuestExtents* vge,
florianca503be2012-10-07 21:59:42 +0000955 VexArchInfo* archinfo_host,
sewardj4ba057c2005-10-18 12:04:18 +0000956 IRType gWordTy, IRType hWordTy )
njn14d01ce2004-11-26 11:30:14 +0000957{
njnfd9f6222005-10-16 00:17:37 +0000958 Int i, isize;
sewardj5155dec2005-10-12 10:09:23 +0000959 IRStmt* st;
960 Addr64 cia; /* address of current insn */
961 CgState cgs;
sewardj0b9d74a2006-12-24 02:24:11 +0000962 IRTypeEnv* tyenv = sbIn->tyenv;
njnfd9f6222005-10-16 00:17:37 +0000963 InstrInfo* curr_inode = NULL;
sewardj5155dec2005-10-12 10:09:23 +0000964
sewardjd54babf2005-03-21 00:55:49 +0000965 if (gWordTy != hWordTy) {
966 /* We don't currently support this case. */
967 VG_(tool_panic)("host/guest word size mismatch");
968 }
969
sewardj0b9d74a2006-12-24 02:24:11 +0000970 // Set up new SB
971 cgs.sbOut = deepCopyIRSBExceptStmts(sbIn);
njn6a3009b2005-03-20 00:20:06 +0000972
sewardja9f538c2005-10-23 12:06:55 +0000973 // Copy verbatim any IR preamble preceding the first IMark
njn6a3009b2005-03-20 00:20:06 +0000974 i = 0;
sewardj0b9d74a2006-12-24 02:24:11 +0000975 while (i < sbIn->stmts_used && sbIn->stmts[i]->tag != Ist_IMark) {
976 addStmtToIRSB( cgs.sbOut, sbIn->stmts[i] );
sewardja9f538c2005-10-23 12:06:55 +0000977 i++;
978 }
979
980 // Get the first statement, and initial cia from it
sewardj0b9d74a2006-12-24 02:24:11 +0000981 tl_assert(sbIn->stmts_used > 0);
982 tl_assert(i < sbIn->stmts_used);
983 st = sbIn->stmts[i];
njn6a3009b2005-03-20 00:20:06 +0000984 tl_assert(Ist_IMark == st->tag);
sewardj8badbaa2007-05-08 09:20:25 +0000985
986 cia = st->Ist.IMark.addr;
987 isize = st->Ist.IMark.len;
988 // If Vex fails to decode an instruction, the size will be zero.
989 // Pretend otherwise.
990 if (isize == 0) isize = VG_MIN_INSTR_SZB;
njn6a3009b2005-03-20 00:20:06 +0000991
sewardj5155dec2005-10-12 10:09:23 +0000992 // Set up running state and get block info
sewardj3a384b32006-01-22 01:12:51 +0000993 tl_assert(closure->readdr == vge->base[0]);
sewardj5155dec2005-10-12 10:09:23 +0000994 cgs.events_used = 0;
sewardj0b9d74a2006-12-24 02:24:11 +0000995 cgs.sbInfo = get_SB_info(sbIn, (Addr)closure->readdr);
996 cgs.sbInfo_i = 0;
njn6a3009b2005-03-20 00:20:06 +0000997
sewardj5155dec2005-10-12 10:09:23 +0000998 if (DEBUG_CG)
999 VG_(printf)("\n\n---------- cg_instrument ----------\n");
njn6a3009b2005-03-20 00:20:06 +00001000
njnfd9f6222005-10-16 00:17:37 +00001001 // Traverse the block, initialising inodes, adding events and flushing as
1002 // necessary.
sewardj0b9d74a2006-12-24 02:24:11 +00001003 for (/*use current i*/; i < sbIn->stmts_used; i++) {
njn6a3009b2005-03-20 00:20:06 +00001004
sewardj0b9d74a2006-12-24 02:24:11 +00001005 st = sbIn->stmts[i];
sewardj5155dec2005-10-12 10:09:23 +00001006 tl_assert(isFlatIRStmt(st));
njnb3507ea2005-08-02 23:07:02 +00001007
sewardj5155dec2005-10-12 10:09:23 +00001008 switch (st->tag) {
1009 case Ist_NoOp:
1010 case Ist_AbiHint:
1011 case Ist_Put:
1012 case Ist_PutI:
sewardj72d75132007-11-09 23:06:35 +00001013 case Ist_MBE:
sewardj5155dec2005-10-12 10:09:23 +00001014 break;
njn20677cc2005-08-12 23:47:51 +00001015
sewardj5155dec2005-10-12 10:09:23 +00001016 case Ist_IMark:
njnfd9f6222005-10-16 00:17:37 +00001017 cia = st->Ist.IMark.addr;
1018 isize = st->Ist.IMark.len;
1019
1020 // If Vex fails to decode an instruction, the size will be zero.
1021 // Pretend otherwise.
1022 if (isize == 0) isize = VG_MIN_INSTR_SZB;
1023
njna5ad9ba2005-11-10 15:20:37 +00001024 // Sanity-check size.
1025 tl_assert( (VG_MIN_INSTR_SZB <= isize && isize <= VG_MAX_INSTR_SZB)
1026 || VG_CLREQ_SZB == isize );
njnfd9f6222005-10-16 00:17:37 +00001027
1028 // Get space for and init the inode, record it as the current one.
1029 // Subsequent Dr/Dw/Dm events from the same instruction will
1030 // also use it.
1031 curr_inode = setup_InstrInfo(&cgs, cia, isize);
1032
1033 addEvent_Ir( &cgs, curr_inode );
sewardj5155dec2005-10-12 10:09:23 +00001034 break;
1035
sewardj0b9d74a2006-12-24 02:24:11 +00001036 case Ist_WrTmp: {
1037 IRExpr* data = st->Ist.WrTmp.data;
sewardj5155dec2005-10-12 10:09:23 +00001038 if (data->tag == Iex_Load) {
1039 IRExpr* aexpr = data->Iex.Load.addr;
sewardj5155dec2005-10-12 10:09:23 +00001040 // Note also, endianness info is ignored. I guess
1041 // that's not interesting.
njnfd9f6222005-10-16 00:17:37 +00001042 addEvent_Dr( &cgs, curr_inode, sizeofIRType(data->Iex.Load.ty),
1043 aexpr );
sewardj5155dec2005-10-12 10:09:23 +00001044 }
1045 break;
njnb3507ea2005-08-02 23:07:02 +00001046 }
1047
sewardj5155dec2005-10-12 10:09:23 +00001048 case Ist_Store: {
1049 IRExpr* data = st->Ist.Store.data;
1050 IRExpr* aexpr = st->Ist.Store.addr;
njnfd9f6222005-10-16 00:17:37 +00001051 addEvent_Dw( &cgs, curr_inode,
1052 sizeofIRType(typeOfIRExpr(tyenv, data)), aexpr );
sewardj5155dec2005-10-12 10:09:23 +00001053 break;
1054 }
njnb3507ea2005-08-02 23:07:02 +00001055
sewardj5155dec2005-10-12 10:09:23 +00001056 case Ist_Dirty: {
1057 Int dataSize;
1058 IRDirty* d = st->Ist.Dirty.details;
1059 if (d->mFx != Ifx_None) {
njnfd9f6222005-10-16 00:17:37 +00001060 /* This dirty helper accesses memory. Collect the details. */
sewardj5155dec2005-10-12 10:09:23 +00001061 tl_assert(d->mAddr != NULL);
1062 tl_assert(d->mSize != 0);
1063 dataSize = d->mSize;
1064 // Large (eg. 28B, 108B, 512B on x86) data-sized
1065 // instructions will be done inaccurately, but they're
1066 // very rare and this avoids errors from hitting more
1067 // than two cache lines in the simulation.
sewardj98763d52012-06-03 22:40:07 +00001068 if (dataSize > min_line_size)
1069 dataSize = min_line_size;
sewardj5155dec2005-10-12 10:09:23 +00001070 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
njnfd9f6222005-10-16 00:17:37 +00001071 addEvent_Dr( &cgs, curr_inode, dataSize, d->mAddr );
sewardj5155dec2005-10-12 10:09:23 +00001072 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
njnfd9f6222005-10-16 00:17:37 +00001073 addEvent_Dw( &cgs, curr_inode, dataSize, d->mAddr );
sewardj5155dec2005-10-12 10:09:23 +00001074 } else {
1075 tl_assert(d->mAddr == NULL);
1076 tl_assert(d->mSize == 0);
1077 }
1078 break;
1079 }
njn6a3009b2005-03-20 00:20:06 +00001080
sewardj1c0ce7a2009-07-01 08:10:49 +00001081 case Ist_CAS: {
1082 /* We treat it as a read and a write of the location. I
1083 think that is the same behaviour as it was before IRCAS
1084 was introduced, since prior to that point, the Vex
1085 front ends would translate a lock-prefixed instruction
1086 into a (normal) read followed by a (normal) write. */
1087 Int dataSize;
1088 IRCAS* cas = st->Ist.CAS.details;
1089 tl_assert(cas->addr != NULL);
1090 tl_assert(cas->dataLo != NULL);
1091 dataSize = sizeofIRType(typeOfIRExpr(tyenv, cas->dataLo));
1092 if (cas->dataHi != NULL)
1093 dataSize *= 2; /* since it's a doubleword-CAS */
1094 /* I don't think this can ever happen, but play safe. */
sewardj98763d52012-06-03 22:40:07 +00001095 if (dataSize > min_line_size)
1096 dataSize = min_line_size;
sewardj1c0ce7a2009-07-01 08:10:49 +00001097 addEvent_Dr( &cgs, curr_inode, dataSize, cas->addr );
1098 addEvent_Dw( &cgs, curr_inode, dataSize, cas->addr );
1099 break;
1100 }
1101
sewardjdb5907d2009-11-26 17:20:21 +00001102 case Ist_LLSC: {
1103 IRType dataTy;
1104 if (st->Ist.LLSC.storedata == NULL) {
1105 /* LL */
1106 dataTy = typeOfIRTemp(tyenv, st->Ist.LLSC.result);
1107 addEvent_Dr( &cgs, curr_inode,
1108 sizeofIRType(dataTy), st->Ist.LLSC.addr );
1109 } else {
1110 /* SC */
1111 dataTy = typeOfIRExpr(tyenv, st->Ist.LLSC.storedata);
1112 addEvent_Dw( &cgs, curr_inode,
1113 sizeofIRType(dataTy), st->Ist.LLSC.addr );
1114 }
1115 break;
1116 }
1117
sewardj8badbaa2007-05-08 09:20:25 +00001118 case Ist_Exit: {
weidendo374a48f2010-09-02 17:06:49 +00001119 // call branch predictor only if this is a branch in guest code
1120 if ( (st->Ist.Exit.jk == Ijk_Boring) ||
1121 (st->Ist.Exit.jk == Ijk_Call) ||
1122 (st->Ist.Exit.jk == Ijk_Ret) )
1123 {
1124 /* Stuff to widen the guard expression to a host word, so
1125 we can pass it to the branch predictor simulation
1126 functions easily. */
1127 Bool inverted;
1128 Addr64 nia, sea;
1129 IRConst* dst;
1130 IRType tyW = hWordTy;
1131 IROp widen = tyW==Ity_I32 ? Iop_1Uto32 : Iop_1Uto64;
1132 IROp opXOR = tyW==Ity_I32 ? Iop_Xor32 : Iop_Xor64;
1133 IRTemp guard1 = newIRTemp(cgs.sbOut->tyenv, Ity_I1);
1134 IRTemp guardW = newIRTemp(cgs.sbOut->tyenv, tyW);
1135 IRTemp guard = newIRTemp(cgs.sbOut->tyenv, tyW);
1136 IRExpr* one = tyW==Ity_I32 ? IRExpr_Const(IRConst_U32(1))
1137 : IRExpr_Const(IRConst_U64(1));
sewardj8badbaa2007-05-08 09:20:25 +00001138
weidendo374a48f2010-09-02 17:06:49 +00001139 /* First we need to figure out whether the side exit got
1140 inverted by the ir optimiser. To do that, figure out
1141 the next (fallthrough) instruction's address and the
1142 side exit address and see if they are the same. */
1143 nia = cia + (Addr64)isize;
1144 if (tyW == Ity_I32)
1145 nia &= 0xFFFFFFFFULL;
sewardj8badbaa2007-05-08 09:20:25 +00001146
weidendo374a48f2010-09-02 17:06:49 +00001147 /* Side exit address */
1148 dst = st->Ist.Exit.dst;
1149 if (tyW == Ity_I32) {
1150 tl_assert(dst->tag == Ico_U32);
1151 sea = (Addr64)(UInt)dst->Ico.U32;
1152 } else {
1153 tl_assert(tyW == Ity_I64);
1154 tl_assert(dst->tag == Ico_U64);
1155 sea = dst->Ico.U64;
1156 }
1157
1158 inverted = nia == sea;
1159
1160 /* Widen the guard expression. */
1161 addStmtToIRSB( cgs.sbOut,
1162 IRStmt_WrTmp( guard1, st->Ist.Exit.guard ));
1163 addStmtToIRSB( cgs.sbOut,
1164 IRStmt_WrTmp( guardW,
1165 IRExpr_Unop(widen,
1166 IRExpr_RdTmp(guard1))) );
1167 /* If the exit is inverted, invert the sense of the guard. */
1168 addStmtToIRSB(
1169 cgs.sbOut,
1170 IRStmt_WrTmp(
1171 guard,
1172 inverted ? IRExpr_Binop(opXOR, IRExpr_RdTmp(guardW), one)
1173 : IRExpr_RdTmp(guardW)
1174 ));
1175 /* And post the event. */
1176 addEvent_Bc( &cgs, curr_inode, IRExpr_RdTmp(guard) );
sewardj8badbaa2007-05-08 09:20:25 +00001177 }
1178
sewardj5155dec2005-10-12 10:09:23 +00001179 /* We may never reach the next statement, so need to flush
1180 all outstanding transactions now. */
1181 flushEvents( &cgs );
1182 break;
sewardj8badbaa2007-05-08 09:20:25 +00001183 }
sewardj5155dec2005-10-12 10:09:23 +00001184
1185 default:
1186 tl_assert(0);
1187 break;
njnb3507ea2005-08-02 23:07:02 +00001188 }
njn6a3009b2005-03-20 00:20:06 +00001189
sewardj5155dec2005-10-12 10:09:23 +00001190 /* Copy the original statement */
sewardj0b9d74a2006-12-24 02:24:11 +00001191 addStmtToIRSB( cgs.sbOut, st );
njn6a3009b2005-03-20 00:20:06 +00001192
sewardj5155dec2005-10-12 10:09:23 +00001193 if (DEBUG_CG) {
1194 ppIRStmt(st);
1195 VG_(printf)("\n");
1196 }
1197 }
1198
sewardj8badbaa2007-05-08 09:20:25 +00001199 /* Deal with branches to unknown destinations. Except ignore ones
1200 which are function returns as we assume the return stack
1201 predictor never mispredicts. */
weidendo374a48f2010-09-02 17:06:49 +00001202 if ((sbIn->jumpkind == Ijk_Boring) || (sbIn->jumpkind == Ijk_Call)) {
sewardj8badbaa2007-05-08 09:20:25 +00001203 if (0) { ppIRExpr( sbIn->next ); VG_(printf)("\n"); }
1204 switch (sbIn->next->tag) {
1205 case Iex_Const:
1206 break; /* boring - branch to known address */
1207 case Iex_RdTmp:
1208 /* looks like an indirect branch (branch to unknown) */
1209 addEvent_Bi( &cgs, curr_inode, sbIn->next );
1210 break;
1211 default:
1212 /* shouldn't happen - if the incoming IR is properly
1213 flattened, should only have tmp and const cases to
1214 consider. */
1215 tl_assert(0);
1216 }
1217 }
1218
sewardj5155dec2005-10-12 10:09:23 +00001219 /* At the end of the bb. Flush outstandings. */
sewardj5155dec2005-10-12 10:09:23 +00001220 flushEvents( &cgs );
1221
sewardj5155dec2005-10-12 10:09:23 +00001222 /* done. stay sane ... */
sewardj0b9d74a2006-12-24 02:24:11 +00001223 tl_assert(cgs.sbInfo_i == cgs.sbInfo->n_instrs);
sewardj5155dec2005-10-12 10:09:23 +00001224
1225 if (DEBUG_CG) {
1226 VG_(printf)( "goto {");
sewardj0b9d74a2006-12-24 02:24:11 +00001227 ppIRJumpKind(sbIn->jumpkind);
sewardj5155dec2005-10-12 10:09:23 +00001228 VG_(printf)( "} ");
sewardj0b9d74a2006-12-24 02:24:11 +00001229 ppIRExpr( sbIn->next );
sewardj5155dec2005-10-12 10:09:23 +00001230 VG_(printf)( "}\n");
1231 }
1232
sewardj0b9d74a2006-12-24 02:24:11 +00001233 return cgs.sbOut;
njn14d01ce2004-11-26 11:30:14 +00001234}
njn4f9c9342002-04-29 16:03:24 +00001235
1236/*------------------------------------------------------------*/
nethercoteb35a8b92004-09-11 16:45:27 +00001237/*--- Cache configuration ---*/
njn4f9c9342002-04-29 16:03:24 +00001238/*------------------------------------------------------------*/
1239
sewardjb5f6f512005-03-10 23:59:00 +00001240#define UNDEFINED_CACHE { -1, -1, -1 }
njn25e49d8e72002-09-23 09:36:25 +00001241
1242static cache_t clo_I1_cache = UNDEFINED_CACHE;
1243static cache_t clo_D1_cache = UNDEFINED_CACHE;
njn2d853a12010-10-06 22:46:31 +00001244static cache_t clo_LL_cache = UNDEFINED_CACHE;
njn25e49d8e72002-09-23 09:36:25 +00001245
njn4f9c9342002-04-29 16:03:24 +00001246/*------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +00001247/*--- cg_fini() and related function ---*/
njn4f9c9342002-04-29 16:03:24 +00001248/*------------------------------------------------------------*/
1249
nethercote9313ac42004-07-06 21:54:20 +00001250// Total reads/writes/misses. Calculated during CC traversal at the end.
1251// All auto-zeroed.
sewardj8badbaa2007-05-08 09:20:25 +00001252static CacheCC Ir_total;
1253static CacheCC Dr_total;
1254static CacheCC Dw_total;
1255static BranchCC Bc_total;
1256static BranchCC Bi_total;
nethercote9313ac42004-07-06 21:54:20 +00001257
nethercote9313ac42004-07-06 21:54:20 +00001258static void fprint_CC_table_and_calc_totals(void)
1259{
njnd3bef4f2005-10-15 17:46:18 +00001260 Int i, fd;
sewardj92645592005-07-23 09:18:34 +00001261 SysRes sres;
njnd3bef4f2005-10-15 17:46:18 +00001262 Char buf[512], *currFile = NULL, *currFn = NULL;
1263 LineCC* lineCC;
njn4f9c9342002-04-29 16:03:24 +00001264
njn7064fb22008-05-29 23:09:52 +00001265 // Setup output filename. Nb: it's important to do this now, ie. as late
1266 // as possible. If we do it at start-up and the program forks and the
1267 // output file format string contains a %p (pid) specifier, both the
1268 // parent and child will incorrectly write to the same file; this
1269 // happened in 3.3.0.
1270 Char* cachegrind_out_file =
1271 VG_(expand_file_name)("--cachegrind-out-file", clo_cachegrind_out_file);
1272
sewardj92645592005-07-23 09:18:34 +00001273 sres = VG_(open)(cachegrind_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
1274 VKI_S_IRUSR|VKI_S_IWUSR);
njncda2f0f2009-05-18 02:12:08 +00001275 if (sr_isError(sres)) {
nethercote9313ac42004-07-06 21:54:20 +00001276 // If the file can't be opened for whatever reason (conflict
1277 // between multiple cachegrinded processes?), give up now.
sewardjb2c985b2009-07-15 14:51:17 +00001278 VG_(umsg)("error: can't open cache simulation output file '%s'\n",
1279 cachegrind_out_file );
1280 VG_(umsg)(" ... so simulation results will be missing.\n");
njn7064fb22008-05-29 23:09:52 +00001281 VG_(free)(cachegrind_out_file);
sewardj0744b6c2002-12-11 00:45:42 +00001282 return;
sewardj92645592005-07-23 09:18:34 +00001283 } else {
njncda2f0f2009-05-18 02:12:08 +00001284 fd = sr_Res(sres);
njn7064fb22008-05-29 23:09:52 +00001285 VG_(free)(cachegrind_out_file);
sewardj0744b6c2002-12-11 00:45:42 +00001286 }
njn4f9c9342002-04-29 16:03:24 +00001287
njn2d853a12010-10-06 22:46:31 +00001288 // "desc:" lines (giving I1/D1/LL cache configuration). The spaces after
nethercote9313ac42004-07-06 21:54:20 +00001289 // the 2nd colon makes cg_annotate's output look nicer.
1290 VG_(sprintf)(buf, "desc: I1 cache: %s\n"
1291 "desc: D1 cache: %s\n"
njn2d853a12010-10-06 22:46:31 +00001292 "desc: LL cache: %s\n",
1293 I1.desc_line, D1.desc_line, LL.desc_line);
njn7cf0bd32002-06-08 13:36:03 +00001294 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njn4f9c9342002-04-29 16:03:24 +00001295
nethercote9313ac42004-07-06 21:54:20 +00001296 // "cmd:" line
njn4f9c9342002-04-29 16:03:24 +00001297 VG_(strcpy)(buf, "cmd:");
1298 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
sewardj45f4e7c2005-09-27 19:20:21 +00001299 if (VG_(args_the_exename)) {
1300 VG_(write)(fd, " ", 1);
1301 VG_(write)(fd, VG_(args_the_exename),
1302 VG_(strlen)( VG_(args_the_exename) ));
1303 }
sewardj14c7cc52007-02-25 15:08:24 +00001304 for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
1305 HChar* arg = * (HChar**) VG_(indexXA)( VG_(args_for_client), i );
1306 if (arg) {
sewardj45f4e7c2005-09-27 19:20:21 +00001307 VG_(write)(fd, " ", 1);
sewardj14c7cc52007-02-25 15:08:24 +00001308 VG_(write)(fd, arg, VG_(strlen)( arg ));
sewardj45f4e7c2005-09-27 19:20:21 +00001309 }
njn4f9c9342002-04-29 16:03:24 +00001310 }
nethercote9313ac42004-07-06 21:54:20 +00001311 // "events:" line
sewardj8badbaa2007-05-08 09:20:25 +00001312 if (clo_cache_sim && clo_branch_sim) {
njn2d853a12010-10-06 22:46:31 +00001313 VG_(sprintf)(buf, "\nevents: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw "
sewardj8badbaa2007-05-08 09:20:25 +00001314 "Bc Bcm Bi Bim\n");
1315 }
1316 else if (clo_cache_sim && !clo_branch_sim) {
njn2d853a12010-10-06 22:46:31 +00001317 VG_(sprintf)(buf, "\nevents: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw "
sewardj8badbaa2007-05-08 09:20:25 +00001318 "\n");
1319 }
1320 else if (!clo_cache_sim && clo_branch_sim) {
1321 VG_(sprintf)(buf, "\nevents: Ir "
1322 "Bc Bcm Bi Bim\n");
1323 }
njne90711c2010-09-27 01:04:20 +00001324 else {
1325 VG_(sprintf)(buf, "\nevents: Ir\n");
1326 }
sewardj8badbaa2007-05-08 09:20:25 +00001327
njn4f9c9342002-04-29 16:03:24 +00001328 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1329
njnd3bef4f2005-10-15 17:46:18 +00001330 // Traverse every lineCC
njne2a9ad32007-09-17 05:30:48 +00001331 VG_(OSetGen_ResetIter)(CC_table);
1332 while ( (lineCC = VG_(OSetGen_Next)(CC_table)) ) {
njn4311fe62005-12-08 23:18:50 +00001333 Bool just_hit_a_new_file = False;
njnd3bef4f2005-10-15 17:46:18 +00001334 // If we've hit a new file, print a "fl=" line. Note that because
1335 // each string is stored exactly once in the string table, we can use
1336 // pointer comparison rather than strcmp() to test for equality, which
1337 // is good because most of the time the comparisons are equal and so
njn4311fe62005-12-08 23:18:50 +00001338 // the whole strings would have to be checked.
njnd3bef4f2005-10-15 17:46:18 +00001339 if ( lineCC->loc.file != currFile ) {
1340 currFile = lineCC->loc.file;
1341 VG_(sprintf)(buf, "fl=%s\n", currFile);
njn4f9c9342002-04-29 16:03:24 +00001342 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njnd3bef4f2005-10-15 17:46:18 +00001343 distinct_files++;
njn4311fe62005-12-08 23:18:50 +00001344 just_hit_a_new_file = True;
njn4f9c9342002-04-29 16:03:24 +00001345 }
njn4311fe62005-12-08 23:18:50 +00001346 // If we've hit a new function, print a "fn=" line. We know to do
1347 // this when the function name changes, and also every time we hit a
1348 // new file (in which case the new function name might be the same as
1349 // in the old file, hence the just_hit_a_new_file test).
1350 if ( just_hit_a_new_file || lineCC->loc.fn != currFn ) {
njnd3bef4f2005-10-15 17:46:18 +00001351 currFn = lineCC->loc.fn;
1352 VG_(sprintf)(buf, "fn=%s\n", currFn);
1353 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1354 distinct_fns++;
1355 }
1356
1357 // Print the LineCC
sewardj8badbaa2007-05-08 09:20:25 +00001358 if (clo_cache_sim && clo_branch_sim) {
1359 VG_(sprintf)(buf, "%u %llu %llu %llu"
1360 " %llu %llu %llu"
1361 " %llu %llu %llu"
1362 " %llu %llu %llu %llu\n",
1363 lineCC->loc.line,
njn2d853a12010-10-06 22:46:31 +00001364 lineCC->Ir.a, lineCC->Ir.m1, lineCC->Ir.mL,
1365 lineCC->Dr.a, lineCC->Dr.m1, lineCC->Dr.mL,
1366 lineCC->Dw.a, lineCC->Dw.m1, lineCC->Dw.mL,
sewardj8badbaa2007-05-08 09:20:25 +00001367 lineCC->Bc.b, lineCC->Bc.mp,
1368 lineCC->Bi.b, lineCC->Bi.mp);
1369 }
1370 else if (clo_cache_sim && !clo_branch_sim) {
1371 VG_(sprintf)(buf, "%u %llu %llu %llu"
1372 " %llu %llu %llu"
1373 " %llu %llu %llu\n",
1374 lineCC->loc.line,
njn2d853a12010-10-06 22:46:31 +00001375 lineCC->Ir.a, lineCC->Ir.m1, lineCC->Ir.mL,
1376 lineCC->Dr.a, lineCC->Dr.m1, lineCC->Dr.mL,
1377 lineCC->Dw.a, lineCC->Dw.m1, lineCC->Dw.mL);
sewardj8badbaa2007-05-08 09:20:25 +00001378 }
1379 else if (!clo_cache_sim && clo_branch_sim) {
1380 VG_(sprintf)(buf, "%u %llu"
1381 " %llu %llu %llu %llu\n",
1382 lineCC->loc.line,
1383 lineCC->Ir.a,
1384 lineCC->Bc.b, lineCC->Bc.mp,
1385 lineCC->Bi.b, lineCC->Bi.mp);
1386 }
njne90711c2010-09-27 01:04:20 +00001387 else {
1388 VG_(sprintf)(buf, "%u %llu\n",
1389 lineCC->loc.line,
1390 lineCC->Ir.a);
1391 }
sewardj8badbaa2007-05-08 09:20:25 +00001392
njnd3bef4f2005-10-15 17:46:18 +00001393 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1394
1395 // Update summary stats
1396 Ir_total.a += lineCC->Ir.a;
1397 Ir_total.m1 += lineCC->Ir.m1;
njn2d853a12010-10-06 22:46:31 +00001398 Ir_total.mL += lineCC->Ir.mL;
njnd3bef4f2005-10-15 17:46:18 +00001399 Dr_total.a += lineCC->Dr.a;
1400 Dr_total.m1 += lineCC->Dr.m1;
njn2d853a12010-10-06 22:46:31 +00001401 Dr_total.mL += lineCC->Dr.mL;
njnd3bef4f2005-10-15 17:46:18 +00001402 Dw_total.a += lineCC->Dw.a;
1403 Dw_total.m1 += lineCC->Dw.m1;
njn2d853a12010-10-06 22:46:31 +00001404 Dw_total.mL += lineCC->Dw.mL;
sewardj8badbaa2007-05-08 09:20:25 +00001405 Bc_total.b += lineCC->Bc.b;
1406 Bc_total.mp += lineCC->Bc.mp;
1407 Bi_total.b += lineCC->Bi.b;
1408 Bi_total.mp += lineCC->Bi.mp;
njnd3bef4f2005-10-15 17:46:18 +00001409
1410 distinct_lines++;
njn4f9c9342002-04-29 16:03:24 +00001411 }
1412
nethercote9313ac42004-07-06 21:54:20 +00001413 // Summary stats must come after rest of table, since we calculate them
sewardj8badbaa2007-05-08 09:20:25 +00001414 // during traversal. */
1415 if (clo_cache_sim && clo_branch_sim) {
1416 VG_(sprintf)(buf, "summary:"
1417 " %llu %llu %llu"
1418 " %llu %llu %llu"
1419 " %llu %llu %llu"
1420 " %llu %llu %llu %llu\n",
njn2d853a12010-10-06 22:46:31 +00001421 Ir_total.a, Ir_total.m1, Ir_total.mL,
1422 Dr_total.a, Dr_total.m1, Dr_total.mL,
1423 Dw_total.a, Dw_total.m1, Dw_total.mL,
sewardj8badbaa2007-05-08 09:20:25 +00001424 Bc_total.b, Bc_total.mp,
1425 Bi_total.b, Bi_total.mp);
1426 }
1427 else if (clo_cache_sim && !clo_branch_sim) {
1428 VG_(sprintf)(buf, "summary:"
1429 " %llu %llu %llu"
1430 " %llu %llu %llu"
1431 " %llu %llu %llu\n",
njn2d853a12010-10-06 22:46:31 +00001432 Ir_total.a, Ir_total.m1, Ir_total.mL,
1433 Dr_total.a, Dr_total.m1, Dr_total.mL,
1434 Dw_total.a, Dw_total.m1, Dw_total.mL);
sewardj8badbaa2007-05-08 09:20:25 +00001435 }
1436 else if (!clo_cache_sim && clo_branch_sim) {
1437 VG_(sprintf)(buf, "summary:"
1438 " %llu"
1439 " %llu %llu %llu %llu\n",
1440 Ir_total.a,
1441 Bc_total.b, Bc_total.mp,
1442 Bi_total.b, Bi_total.mp);
1443 }
njne90711c2010-09-27 01:04:20 +00001444 else {
1445 VG_(sprintf)(buf, "summary:"
1446 " %llu\n",
1447 Ir_total.a);
1448 }
sewardj8badbaa2007-05-08 09:20:25 +00001449
njn4f9c9342002-04-29 16:03:24 +00001450 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1451 VG_(close)(fd);
1452}
1453
njn607adfc2003-09-30 14:15:44 +00001454static UInt ULong_width(ULong n)
njn4f9c9342002-04-29 16:03:24 +00001455{
njn607adfc2003-09-30 14:15:44 +00001456 UInt w = 0;
1457 while (n > 0) {
1458 n = n / 10;
1459 w++;
njn4f9c9342002-04-29 16:03:24 +00001460 }
sewardj46c59b12005-11-01 02:20:19 +00001461 if (w == 0) w = 1;
njn607adfc2003-09-30 14:15:44 +00001462 return w + (w-1)/3; // add space for commas
njn4f9c9342002-04-29 16:03:24 +00001463}
1464
njn51d827b2005-05-09 01:02:08 +00001465static void cg_fini(Int exitcode)
njn4f9c9342002-04-29 16:03:24 +00001466{
florianee90c8a2012-10-21 02:39:42 +00001467 static Char buf1[128], buf2[128], buf3[128], buf4[123];
1468 static HChar fmt[128];
njn607adfc2003-09-30 14:15:44 +00001469
sewardj8badbaa2007-05-08 09:20:25 +00001470 CacheCC D_total;
1471 BranchCC B_total;
njn2d853a12010-10-06 22:46:31 +00001472 ULong LL_total_m, LL_total_mr, LL_total_mw,
1473 LL_total, LL_total_r, LL_total_w;
njn4c245e52009-03-15 23:25:38 +00001474 Int l1, l2, l3;
njn4f9c9342002-04-29 16:03:24 +00001475
nethercote9313ac42004-07-06 21:54:20 +00001476 fprint_CC_table_and_calc_totals();
njn4f9c9342002-04-29 16:03:24 +00001477
njn7cf0bd32002-06-08 13:36:03 +00001478 if (VG_(clo_verbosity) == 0)
1479 return;
1480
njnf76d27a2009-05-28 01:53:07 +00001481 // Nb: this isn't called "MAX" because that overshadows a global on Darwin.
1482 #define CG_MAX(a, b) ((a) >= (b) ? (a) : (b))
njn4c245e52009-03-15 23:25:38 +00001483
njn4f9c9342002-04-29 16:03:24 +00001484 /* I cache results. Use the I_refs value to determine the first column
1485 * width. */
njn607adfc2003-09-30 14:15:44 +00001486 l1 = ULong_width(Ir_total.a);
njnf76d27a2009-05-28 01:53:07 +00001487 l2 = ULong_width(CG_MAX(Dr_total.a, Bc_total.b));
1488 l3 = ULong_width(CG_MAX(Dw_total.a, Bi_total.b));
njn4f9c9342002-04-29 16:03:24 +00001489
njn607adfc2003-09-30 14:15:44 +00001490 /* Make format string, getting width right for numbers */
sewardjb2c985b2009-07-15 14:51:17 +00001491 VG_(sprintf)(fmt, "%%s %%,%dllu\n", l1);
njnd3bef4f2005-10-15 17:46:18 +00001492
sewardj8badbaa2007-05-08 09:20:25 +00001493 /* Always print this */
sewardjb2c985b2009-07-15 14:51:17 +00001494 VG_(umsg)(fmt, "I refs: ", Ir_total.a);
njn4f9c9342002-04-29 16:03:24 +00001495
sewardj8badbaa2007-05-08 09:20:25 +00001496 /* If cache profiling is enabled, show D access numbers and all
1497 miss numbers */
1498 if (clo_cache_sim) {
sewardjb2c985b2009-07-15 14:51:17 +00001499 VG_(umsg)(fmt, "I1 misses: ", Ir_total.m1);
njn2d853a12010-10-06 22:46:31 +00001500 VG_(umsg)(fmt, "LLi misses: ", Ir_total.mL);
njn4f9c9342002-04-29 16:03:24 +00001501
sewardj8badbaa2007-05-08 09:20:25 +00001502 if (0 == Ir_total.a) Ir_total.a = 1;
1503 VG_(percentify)(Ir_total.m1, Ir_total.a, 2, l1+1, buf1);
sewardjb2c985b2009-07-15 14:51:17 +00001504 VG_(umsg)("I1 miss rate: %s\n", buf1);
njn4f9c9342002-04-29 16:03:24 +00001505
njn2d853a12010-10-06 22:46:31 +00001506 VG_(percentify)(Ir_total.mL, Ir_total.a, 2, l1+1, buf1);
1507 VG_(umsg)("LLi miss rate: %s\n", buf1);
sewardjb2c985b2009-07-15 14:51:17 +00001508 VG_(umsg)("\n");
njnd3bef4f2005-10-15 17:46:18 +00001509
sewardj8badbaa2007-05-08 09:20:25 +00001510 /* D cache results. Use the D_refs.rd and D_refs.wr values to
1511 * determine the width of columns 2 & 3. */
1512 D_total.a = Dr_total.a + Dw_total.a;
1513 D_total.m1 = Dr_total.m1 + Dw_total.m1;
njn2d853a12010-10-06 22:46:31 +00001514 D_total.mL = Dr_total.mL + Dw_total.mL;
njn4f9c9342002-04-29 16:03:24 +00001515
sewardj8badbaa2007-05-08 09:20:25 +00001516 /* Make format string, getting width right for numbers */
sewardjb2c985b2009-07-15 14:51:17 +00001517 VG_(sprintf)(fmt, "%%s %%,%dllu (%%,%dllu rd + %%,%dllu wr)\n",
1518 l1, l2, l3);
njn4f9c9342002-04-29 16:03:24 +00001519
sewardjb2c985b2009-07-15 14:51:17 +00001520 VG_(umsg)(fmt, "D refs: ",
1521 D_total.a, Dr_total.a, Dw_total.a);
1522 VG_(umsg)(fmt, "D1 misses: ",
1523 D_total.m1, Dr_total.m1, Dw_total.m1);
njn2d853a12010-10-06 22:46:31 +00001524 VG_(umsg)(fmt, "LLd misses: ",
1525 D_total.mL, Dr_total.mL, Dw_total.mL);
njnd3bef4f2005-10-15 17:46:18 +00001526
sewardj8badbaa2007-05-08 09:20:25 +00001527 if (0 == D_total.a) D_total.a = 1;
1528 if (0 == Dr_total.a) Dr_total.a = 1;
1529 if (0 == Dw_total.a) Dw_total.a = 1;
1530 VG_(percentify)( D_total.m1, D_total.a, 1, l1+1, buf1);
1531 VG_(percentify)(Dr_total.m1, Dr_total.a, 1, l2+1, buf2);
1532 VG_(percentify)(Dw_total.m1, Dw_total.a, 1, l3+1, buf3);
sewardjb2c985b2009-07-15 14:51:17 +00001533 VG_(umsg)("D1 miss rate: %s (%s + %s )\n", buf1, buf2,buf3);
njn4f9c9342002-04-29 16:03:24 +00001534
njn2d853a12010-10-06 22:46:31 +00001535 VG_(percentify)( D_total.mL, D_total.a, 1, l1+1, buf1);
1536 VG_(percentify)(Dr_total.mL, Dr_total.a, 1, l2+1, buf2);
1537 VG_(percentify)(Dw_total.mL, Dw_total.a, 1, l3+1, buf3);
1538 VG_(umsg)("LLd miss rate: %s (%s + %s )\n", buf1, buf2,buf3);
sewardjb2c985b2009-07-15 14:51:17 +00001539 VG_(umsg)("\n");
njn1d021fa2002-05-02 13:56:34 +00001540
njn2d853a12010-10-06 22:46:31 +00001541 /* LL overall results */
njn1d021fa2002-05-02 13:56:34 +00001542
njn2d853a12010-10-06 22:46:31 +00001543 LL_total = Dr_total.m1 + Dw_total.m1 + Ir_total.m1;
1544 LL_total_r = Dr_total.m1 + Ir_total.m1;
1545 LL_total_w = Dw_total.m1;
1546 VG_(umsg)(fmt, "LL refs: ",
1547 LL_total, LL_total_r, LL_total_w);
njn4f9c9342002-04-29 16:03:24 +00001548
njn2d853a12010-10-06 22:46:31 +00001549 LL_total_m = Dr_total.mL + Dw_total.mL + Ir_total.mL;
1550 LL_total_mr = Dr_total.mL + Ir_total.mL;
1551 LL_total_mw = Dw_total.mL;
1552 VG_(umsg)(fmt, "LL misses: ",
1553 LL_total_m, LL_total_mr, LL_total_mw);
njnd3bef4f2005-10-15 17:46:18 +00001554
njn2d853a12010-10-06 22:46:31 +00001555 VG_(percentify)(LL_total_m, (Ir_total.a + D_total.a), 1, l1+1, buf1);
1556 VG_(percentify)(LL_total_mr, (Ir_total.a + Dr_total.a), 1, l2+1, buf2);
1557 VG_(percentify)(LL_total_mw, Dw_total.a, 1, l3+1, buf3);
1558 VG_(umsg)("LL miss rate: %s (%s + %s )\n", buf1, buf2,buf3);
sewardj8badbaa2007-05-08 09:20:25 +00001559 }
1560
1561 /* If branch profiling is enabled, show branch overall results. */
1562 if (clo_branch_sim) {
1563 /* Make format string, getting width right for numbers */
sewardjb2c985b2009-07-15 14:51:17 +00001564 VG_(sprintf)(fmt, "%%s %%,%dllu (%%,%dllu cond + %%,%dllu ind)\n",
1565 l1, l2, l3);
sewardj8badbaa2007-05-08 09:20:25 +00001566
1567 if (0 == Bc_total.b) Bc_total.b = 1;
1568 if (0 == Bi_total.b) Bi_total.b = 1;
1569 B_total.b = Bc_total.b + Bi_total.b;
1570 B_total.mp = Bc_total.mp + Bi_total.mp;
1571
sewardjb2c985b2009-07-15 14:51:17 +00001572 VG_(umsg)("\n");
1573 VG_(umsg)(fmt, "Branches: ",
1574 B_total.b, Bc_total.b, Bi_total.b);
sewardj8badbaa2007-05-08 09:20:25 +00001575
sewardjb2c985b2009-07-15 14:51:17 +00001576 VG_(umsg)(fmt, "Mispredicts: ",
1577 B_total.mp, Bc_total.mp, Bi_total.mp);
sewardj8badbaa2007-05-08 09:20:25 +00001578
1579 VG_(percentify)(B_total.mp, B_total.b, 1, l1+1, buf1);
1580 VG_(percentify)(Bc_total.mp, Bc_total.b, 1, l2+1, buf2);
1581 VG_(percentify)(Bi_total.mp, Bi_total.b, 1, l3+1, buf3);
1582
sewardjb2c985b2009-07-15 14:51:17 +00001583 VG_(umsg)("Mispred rate: %s (%s + %s )\n", buf1, buf2,buf3);
sewardj8badbaa2007-05-08 09:20:25 +00001584 }
njn4f9c9342002-04-29 16:03:24 +00001585
nethercote9313ac42004-07-06 21:54:20 +00001586 // Various stats
sewardj2d9e8742009-08-07 15:46:56 +00001587 if (VG_(clo_stats)) {
njn1baf7db2006-04-18 22:34:48 +00001588 Int debug_lookups = full_debugs + fn_debugs +
1589 file_line_debugs + no_debugs;
njnd3bef4f2005-10-15 17:46:18 +00001590
sewardjb2c985b2009-07-15 14:51:17 +00001591 VG_(dmsg)("\n");
1592 VG_(dmsg)("cachegrind: distinct files: %d\n", distinct_files);
1593 VG_(dmsg)("cachegrind: distinct fns: %d\n", distinct_fns);
1594 VG_(dmsg)("cachegrind: distinct lines: %d\n", distinct_lines);
1595 VG_(dmsg)("cachegrind: distinct instrs:%d\n", distinct_instrs);
1596 VG_(dmsg)("cachegrind: debug lookups : %d\n", debug_lookups);
njn1baf7db2006-04-18 22:34:48 +00001597
1598 VG_(percentify)(full_debugs, debug_lookups, 1, 6, buf1);
1599 VG_(percentify)(file_line_debugs, debug_lookups, 1, 6, buf2);
1600 VG_(percentify)(fn_debugs, debug_lookups, 1, 6, buf3);
1601 VG_(percentify)(no_debugs, debug_lookups, 1, 6, buf4);
sewardjb2c985b2009-07-15 14:51:17 +00001602 VG_(dmsg)("cachegrind: with full info:%s (%d)\n",
1603 buf1, full_debugs);
1604 VG_(dmsg)("cachegrind: with file/line info:%s (%d)\n",
1605 buf2, file_line_debugs);
1606 VG_(dmsg)("cachegrind: with fn name info:%s (%d)\n",
1607 buf3, fn_debugs);
1608 VG_(dmsg)("cachegrind: with zero info:%s (%d)\n",
1609 buf4, no_debugs);
njn1baf7db2006-04-18 22:34:48 +00001610
sewardjb2c985b2009-07-15 14:51:17 +00001611 VG_(dmsg)("cachegrind: string table size: %lu\n",
1612 VG_(OSetGen_Size)(stringTable));
1613 VG_(dmsg)("cachegrind: CC table size: %lu\n",
1614 VG_(OSetGen_Size)(CC_table));
1615 VG_(dmsg)("cachegrind: InstrInfo table size: %lu\n",
1616 VG_(OSetGen_Size)(instrInfoTable));
njn4f9c9342002-04-29 16:03:24 +00001617 }
njn4f9c9342002-04-29 16:03:24 +00001618}
1619
nethercote9313ac42004-07-06 21:54:20 +00001620/*--------------------------------------------------------------------*/
1621/*--- Discarding BB info ---*/
1622/*--------------------------------------------------------------------*/
sewardj18d75132002-05-16 11:06:21 +00001623
sewardja3a29a52005-10-12 16:16:03 +00001624// Called when a translation is removed from the translation cache for
1625// any reason at all: to free up space, because the guest code was
1626// unmapped or modified, or for any arbitrary reason.
sewardj4ba057c2005-10-18 12:04:18 +00001627static
sewardj0b9d74a2006-12-24 02:24:11 +00001628void cg_discard_superblock_info ( Addr64 orig_addr64, VexGuestExtents vge )
sewardj18d75132002-05-16 11:06:21 +00001629{
sewardj0b9d74a2006-12-24 02:24:11 +00001630 SB_info* sbInfo;
sewardj3a384b32006-01-22 01:12:51 +00001631 Addr orig_addr = (Addr)vge.base[0];
njn4294fd42002-06-05 14:41:10 +00001632
sewardj5155dec2005-10-12 10:09:23 +00001633 tl_assert(vge.n_used > 0);
1634
1635 if (DEBUG_CG)
sewardj4ba057c2005-10-18 12:04:18 +00001636 VG_(printf)( "discard_basic_block_info: %p, %p, %llu\n",
1637 (void*)(Addr)orig_addr,
sewardj5155dec2005-10-12 10:09:23 +00001638 (void*)(Addr)vge.base[0], (ULong)vge.len[0]);
njn4294fd42002-06-05 14:41:10 +00001639
sewardj4ba057c2005-10-18 12:04:18 +00001640 // Get BB info, remove from table, free BB info. Simple! Note that we
1641 // use orig_addr, not the first instruction address in vge.
njne2a9ad32007-09-17 05:30:48 +00001642 sbInfo = VG_(OSetGen_Remove)(instrInfoTable, &orig_addr);
sewardj0b9d74a2006-12-24 02:24:11 +00001643 tl_assert(NULL != sbInfo);
njne2a9ad32007-09-17 05:30:48 +00001644 VG_(OSetGen_FreeNode)(instrInfoTable, sbInfo);
sewardj18d75132002-05-16 11:06:21 +00001645}
1646
1647/*--------------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001648/*--- Command line processing ---*/
1649/*--------------------------------------------------------------------*/
1650
njn51d827b2005-05-09 01:02:08 +00001651static Bool cg_process_cmd_line_option(Char* arg)
njn25e49d8e72002-09-23 09:36:25 +00001652{
weidendo23642272011-09-06 19:08:31 +00001653 if (VG_(str_clo_cache_opt)(arg,
1654 &clo_I1_cache,
1655 &clo_D1_cache,
1656 &clo_LL_cache)) {}
njn83df0b62009-02-25 01:01:05 +00001657
1658 else if VG_STR_CLO( arg, "--cachegrind-out-file", clo_cachegrind_out_file) {}
1659 else if VG_BOOL_CLO(arg, "--cache-sim", clo_cache_sim) {}
1660 else if VG_BOOL_CLO(arg, "--branch-sim", clo_branch_sim) {}
njn25e49d8e72002-09-23 09:36:25 +00001661 else
1662 return False;
1663
1664 return True;
1665}
1666
njn51d827b2005-05-09 01:02:08 +00001667static void cg_print_usage(void)
njn25e49d8e72002-09-23 09:36:25 +00001668{
weidendo23642272011-09-06 19:08:31 +00001669 VG_(print_cache_clo_opts)();
njn3e884182003-04-15 13:03:23 +00001670 VG_(printf)(
sewardj8badbaa2007-05-08 09:20:25 +00001671" --cache-sim=yes|no [yes] collect cache stats?\n"
1672" --branch-sim=yes|no [no] collect branch prediction stats?\n"
njn374a36d2007-11-23 01:41:32 +00001673" --cachegrind-out-file=<file> output file name [cachegrind.out.%%p]\n"
njn3e884182003-04-15 13:03:23 +00001674 );
1675}
1676
njn51d827b2005-05-09 01:02:08 +00001677static void cg_print_debug_usage(void)
njn3e884182003-04-15 13:03:23 +00001678{
1679 VG_(printf)(
1680" (none)\n"
1681 );
njn25e49d8e72002-09-23 09:36:25 +00001682}
1683
1684/*--------------------------------------------------------------------*/
1685/*--- Setup ---*/
1686/*--------------------------------------------------------------------*/
1687
sewardje1216cb2007-02-07 19:55:30 +00001688static void cg_post_clo_init(void); /* just below */
1689
njn51d827b2005-05-09 01:02:08 +00001690static void cg_pre_clo_init(void)
1691{
njn51d827b2005-05-09 01:02:08 +00001692 VG_(details_name) ("Cachegrind");
1693 VG_(details_version) (NULL);
sewardj8badbaa2007-05-08 09:20:25 +00001694 VG_(details_description) ("a cache and branch-prediction profiler");
njn51d827b2005-05-09 01:02:08 +00001695 VG_(details_copyright_author)(
sewardj03f8d3f2012-08-05 15:46:46 +00001696 "Copyright (C) 2002-2012, and GNU GPL'd, by Nicholas Nethercote et al.");
njn51d827b2005-05-09 01:02:08 +00001697 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardje8089302006-10-17 02:15:17 +00001698 VG_(details_avg_translation_sizeB) ( 500 );
njn51d827b2005-05-09 01:02:08 +00001699
philippe5b240c22012-08-14 22:28:31 +00001700 VG_(clo_vex_control).iropt_register_updates
1701 = VexRegUpdSpAtMemAccess; // overridable by the user.
njn51d827b2005-05-09 01:02:08 +00001702 VG_(basic_tool_funcs) (cg_post_clo_init,
1703 cg_instrument,
1704 cg_fini);
1705
sewardj0b9d74a2006-12-24 02:24:11 +00001706 VG_(needs_superblock_discards)(cg_discard_superblock_info);
njn51d827b2005-05-09 01:02:08 +00001707 VG_(needs_command_line_options)(cg_process_cmd_line_option,
1708 cg_print_usage,
1709 cg_print_debug_usage);
sewardje1216cb2007-02-07 19:55:30 +00001710}
1711
1712static void cg_post_clo_init(void)
1713{
njn2d853a12010-10-06 22:46:31 +00001714 cache_t I1c, D1c, LLc;
njn51d827b2005-05-09 01:02:08 +00001715
njne2a9ad32007-09-17 05:30:48 +00001716 CC_table =
1717 VG_(OSetGen_Create)(offsetof(LineCC, loc),
1718 cmp_CodeLoc_LineCC,
sewardj9c606bd2008-09-18 18:12:50 +00001719 VG_(malloc), "cg.main.cpci.1",
1720 VG_(free));
njne2a9ad32007-09-17 05:30:48 +00001721 instrInfoTable =
1722 VG_(OSetGen_Create)(/*keyOff*/0,
1723 NULL,
sewardj9c606bd2008-09-18 18:12:50 +00001724 VG_(malloc), "cg.main.cpci.2",
1725 VG_(free));
njne2a9ad32007-09-17 05:30:48 +00001726 stringTable =
1727 VG_(OSetGen_Create)(/*keyOff*/0,
1728 stringCmp,
sewardj9c606bd2008-09-18 18:12:50 +00001729 VG_(malloc), "cg.main.cpci.3",
1730 VG_(free));
sewardje1216cb2007-02-07 19:55:30 +00001731
weidendo23642272011-09-06 19:08:31 +00001732 VG_(post_clo_init_configure_caches)(&I1c, &D1c, &LLc,
1733 &clo_I1_cache,
1734 &clo_D1_cache,
1735 &clo_LL_cache);
sewardje1216cb2007-02-07 19:55:30 +00001736
sewardj98763d52012-06-03 22:40:07 +00001737 // min_line_size is used to make sure that we never feed
1738 // accesses to the simulator straddling more than two
1739 // cache lines at any cache level
1740 min_line_size = (I1c.line_size < D1c.line_size) ? I1c.line_size : D1c.line_size;
1741 min_line_size = (LLc.line_size < min_line_size) ? LLc.line_size : min_line_size;
1742
1743 Int largest_load_or_store_size
1744 = VG_(machine_get_size_of_largest_guest_register)();
1745 if (min_line_size < largest_load_or_store_size) {
1746 /* We can't continue, because the cache simulation might
1747 straddle more than 2 lines, and it will assert. So let's
1748 just stop before we start. */
1749 VG_(umsg)("Cachegrind: cannot continue: the minimum line size (%d)\n",
1750 (Int)min_line_size);
1751 VG_(umsg)(" must be equal to or larger than the maximum register size (%d)\n",
1752 largest_load_or_store_size );
1753 VG_(umsg)(" but it is not. Exiting now.\n");
1754 VG_(exit)(1);
1755 }
1756
weidendoc1e94262012-10-05 23:58:17 +00001757 cachesim_initcaches(I1c, D1c, LLc);
njn51d827b2005-05-09 01:02:08 +00001758}
1759
sewardj45f4e7c2005-09-27 19:20:21 +00001760VG_DETERMINE_INTERFACE_VERSION(cg_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00001761
njn25e49d8e72002-09-23 09:36:25 +00001762/*--------------------------------------------------------------------*/
njnf69f9452005-07-03 17:53:11 +00001763/*--- end ---*/
sewardj18d75132002-05-16 11:06:21 +00001764/*--------------------------------------------------------------------*/
njnd3bef4f2005-10-15 17:46:18 +00001765