blob: 8e439365c70d15fc5e98586ad93d3c05469247ab [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
sewardj9eecbbb2010-05-03 21:37:12 +000011 Copyright (C) 2002-2010 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? */
70static Char* clo_cachegrind_out_file = "cachegrind.out.%p";
sewardj8badbaa2007-05-08 09:20:25 +000071
72/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +000073/*--- Types and Data Structures ---*/
njn4f9c9342002-04-29 16:03:24 +000074/*------------------------------------------------------------*/
75
sewardj8badbaa2007-05-08 09:20:25 +000076typedef
77 struct {
78 ULong a; /* total # memory accesses of this kind */
79 ULong m1; /* misses in the first level cache */
njn2d853a12010-10-06 22:46:31 +000080 ULong mL; /* misses in the second level cache */
sewardj8badbaa2007-05-08 09:20:25 +000081 }
82 CacheCC;
83
84typedef
85 struct {
86 ULong b; /* total # branches of this kind */
87 ULong mp; /* number of branches mispredicted */
88 }
89 BranchCC;
njn4f9c9342002-04-29 16:03:24 +000090
nethercote9313ac42004-07-06 21:54:20 +000091//------------------------------------------------------------
92// Primary data structure #1: CC table
93// - Holds the per-source-line hit/miss stats, grouped by file/function/line.
njnd3bef4f2005-10-15 17:46:18 +000094// - an ordered set of CCs. CC indexing done by file/function/line (as
95// determined from the instrAddr).
nethercote9313ac42004-07-06 21:54:20 +000096// - Traversed for dumping stats at end in file/func/line hierarchy.
njn4f9c9342002-04-29 16:03:24 +000097
njnd3bef4f2005-10-15 17:46:18 +000098typedef struct {
99 Char* file;
100 Char* fn;
101 Int line;
102}
103CodeLoc;
njn4f9c9342002-04-29 16:03:24 +0000104
sewardj8badbaa2007-05-08 09:20:25 +0000105typedef struct {
106 CodeLoc loc; /* Source location that these counts pertain to */
107 CacheCC Ir; /* Insn read counts */
108 CacheCC Dr; /* Data read counts */
109 CacheCC Dw; /* Data write/modify counts */
110 BranchCC Bc; /* Conditional branch counts */
111 BranchCC Bi; /* Indirect branch counts */
112} LineCC;
njn4f9c9342002-04-29 16:03:24 +0000113
njnd3bef4f2005-10-15 17:46:18 +0000114// First compare file, then fn, then line.
tom5a835d52007-12-30 12:28:26 +0000115static Word cmp_CodeLoc_LineCC(const void *vloc, const void *vcc)
njnd3bef4f2005-10-15 17:46:18 +0000116{
njnafa12262005-12-24 03:10:56 +0000117 Word res;
njnd3bef4f2005-10-15 17:46:18 +0000118 CodeLoc* a = (CodeLoc*)vloc;
119 CodeLoc* b = &(((LineCC*)vcc)->loc);
njn4f9c9342002-04-29 16:03:24 +0000120
njnd3bef4f2005-10-15 17:46:18 +0000121 res = VG_(strcmp)(a->file, b->file);
122 if (0 != res)
123 return res;
njn4f9c9342002-04-29 16:03:24 +0000124
njnd3bef4f2005-10-15 17:46:18 +0000125 res = VG_(strcmp)(a->fn, b->fn);
126 if (0 != res)
127 return res;
128
129 return a->line - b->line;
130}
131
132static OSet* CC_table;
njn4f9c9342002-04-29 16:03:24 +0000133
nethercote9313ac42004-07-06 21:54:20 +0000134//------------------------------------------------------------
njnd3bef4f2005-10-15 17:46:18 +0000135// Primary data structure #2: InstrInfo table
nethercote9313ac42004-07-06 21:54:20 +0000136// - Holds the cached info about each instr that is used for simulation.
sewardj0b9d74a2006-12-24 02:24:11 +0000137// - table(SB_start_addr, list(InstrInfo))
138// - For each SB, each InstrInfo in the list holds info about the
njnd3bef4f2005-10-15 17:46:18 +0000139// instruction (instrLen, instrAddr, etc), plus a pointer to its line
nethercote9313ac42004-07-06 21:54:20 +0000140// CC. This node is what's passed to the simulation function.
sewardj0b9d74a2006-12-24 02:24:11 +0000141// - When SBs are discarded the relevant list(instr_details) is freed.
nethercote9313ac42004-07-06 21:54:20 +0000142
njnd3bef4f2005-10-15 17:46:18 +0000143typedef struct _InstrInfo InstrInfo;
144struct _InstrInfo {
nethercoteca1f2dc2004-07-21 08:49:02 +0000145 Addr instr_addr;
njn6a3009b2005-03-20 00:20:06 +0000146 UChar instr_len;
njnd3bef4f2005-10-15 17:46:18 +0000147 LineCC* parent; // parent line-CC
nethercote9313ac42004-07-06 21:54:20 +0000148};
149
sewardj0b9d74a2006-12-24 02:24:11 +0000150typedef struct _SB_info SB_info;
151struct _SB_info {
152 Addr SB_addr; // key; MUST BE FIRST
njnd3bef4f2005-10-15 17:46:18 +0000153 Int n_instrs;
154 InstrInfo instrs[0];
nethercote9313ac42004-07-06 21:54:20 +0000155};
156
njnd3bef4f2005-10-15 17:46:18 +0000157static OSet* instrInfoTable;
158
159//------------------------------------------------------------
160// Secondary data structure: string table
161// - holds strings, avoiding dups
162// - used for filenames and function names, each of which will be
163// pointed to by one or more CCs.
164// - it also allows equality checks just by pointer comparison, which
165// is good when printing the output file at the end.
166
167static OSet* stringTable;
nethercote9313ac42004-07-06 21:54:20 +0000168
169//------------------------------------------------------------
170// Stats
sewardj4f29ddf2002-05-03 22:29:04 +0000171static Int distinct_files = 0;
172static Int distinct_fns = 0;
nethercote9313ac42004-07-06 21:54:20 +0000173static Int distinct_lines = 0;
sewardj4f29ddf2002-05-03 22:29:04 +0000174static Int distinct_instrs = 0;
nethercote9313ac42004-07-06 21:54:20 +0000175
njnd3bef4f2005-10-15 17:46:18 +0000176static Int full_debugs = 0;
177static Int file_line_debugs = 0;
178static Int fn_debugs = 0;
179static Int no_debugs = 0;
njn4f9c9342002-04-29 16:03:24 +0000180
nethercote9313ac42004-07-06 21:54:20 +0000181/*------------------------------------------------------------*/
njnd3bef4f2005-10-15 17:46:18 +0000182/*--- String table operations ---*/
183/*------------------------------------------------------------*/
184
tom5a835d52007-12-30 12:28:26 +0000185static Word stringCmp( const void* key, const void* elem )
njnd3bef4f2005-10-15 17:46:18 +0000186{
187 return VG_(strcmp)(*(Char**)key, *(Char**)elem);
188}
189
190// Get a permanent string; either pull it out of the string table if it's
191// been encountered before, or dup it and put it into the string table.
192static Char* get_perm_string(Char* s)
193{
njne2a9ad32007-09-17 05:30:48 +0000194 Char** s_ptr = VG_(OSetGen_Lookup)(stringTable, &s);
njnd3bef4f2005-10-15 17:46:18 +0000195 if (s_ptr) {
196 return *s_ptr;
197 } else {
njne2a9ad32007-09-17 05:30:48 +0000198 Char** s_node = VG_(OSetGen_AllocNode)(stringTable, sizeof(Char*));
sewardj9c606bd2008-09-18 18:12:50 +0000199 *s_node = VG_(strdup)("cg.main.gps.1", s);
njne2a9ad32007-09-17 05:30:48 +0000200 VG_(OSetGen_Insert)(stringTable, s_node);
njnd3bef4f2005-10-15 17:46:18 +0000201 return *s_node;
202 }
203}
204
205/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +0000206/*--- CC table operations ---*/
207/*------------------------------------------------------------*/
njn4294fd42002-06-05 14:41:10 +0000208
nethercote9313ac42004-07-06 21:54:20 +0000209static void get_debug_info(Addr instr_addr, Char file[FILE_LEN],
210 Char fn[FN_LEN], Int* line)
njn4f9c9342002-04-29 16:03:24 +0000211{
njnf3b61d62007-09-17 00:41:07 +0000212 Char dir[FILE_LEN];
213 Bool found_dirname;
sewardj7cee6f92005-06-13 17:39:06 +0000214 Bool found_file_line = VG_(get_filename_linenum)(
215 instr_addr,
216 file, FILE_LEN,
njnf3b61d62007-09-17 00:41:07 +0000217 dir, FILE_LEN, &found_dirname,
sewardj7cee6f92005-06-13 17:39:06 +0000218 line
219 );
nethercote9313ac42004-07-06 21:54:20 +0000220 Bool found_fn = VG_(get_fnname)(instr_addr, fn, FN_LEN);
njn4f9c9342002-04-29 16:03:24 +0000221
nethercote9313ac42004-07-06 21:54:20 +0000222 if (!found_file_line) {
223 VG_(strcpy)(file, "???");
224 *line = 0;
225 }
226 if (!found_fn) {
227 VG_(strcpy)(fn, "???");
228 }
njnf3b61d62007-09-17 00:41:07 +0000229
230 if (found_dirname) {
231 // +1 for the '/'.
232 tl_assert(VG_(strlen)(dir) + VG_(strlen)(file) + 1 < FILE_LEN);
233 VG_(strcat)(dir, "/"); // Append '/'
234 VG_(strcat)(dir, file); // Append file to dir
235 VG_(strcpy)(file, dir); // Move dir+file to file
236 }
237
nethercote9313ac42004-07-06 21:54:20 +0000238 if (found_file_line) {
njnd3bef4f2005-10-15 17:46:18 +0000239 if (found_fn) full_debugs++;
240 else file_line_debugs++;
nethercote9313ac42004-07-06 21:54:20 +0000241 } else {
njnd3bef4f2005-10-15 17:46:18 +0000242 if (found_fn) fn_debugs++;
243 else no_debugs++;
njn4f9c9342002-04-29 16:03:24 +0000244 }
245}
246
nethercote9313ac42004-07-06 21:54:20 +0000247// Do a three step traversal: by file, then fn, then line.
njnd3bef4f2005-10-15 17:46:18 +0000248// Returns a pointer to the line CC, creates a new one if necessary.
249static LineCC* get_lineCC(Addr origAddr)
nethercote9313ac42004-07-06 21:54:20 +0000250{
nethercote9313ac42004-07-06 21:54:20 +0000251 Char file[FILE_LEN], fn[FN_LEN];
252 Int line;
njnd3bef4f2005-10-15 17:46:18 +0000253 CodeLoc loc;
254 LineCC* lineCC;
nethercote9313ac42004-07-06 21:54:20 +0000255
njn6a3009b2005-03-20 00:20:06 +0000256 get_debug_info(origAddr, file, fn, &line);
nethercote9313ac42004-07-06 21:54:20 +0000257
njnd3bef4f2005-10-15 17:46:18 +0000258 loc.file = file;
259 loc.fn = fn;
260 loc.line = line;
njn4f9c9342002-04-29 16:03:24 +0000261
njne2a9ad32007-09-17 05:30:48 +0000262 lineCC = VG_(OSetGen_Lookup)(CC_table, &loc);
njnd3bef4f2005-10-15 17:46:18 +0000263 if (!lineCC) {
264 // Allocate and zero a new node.
njne2a9ad32007-09-17 05:30:48 +0000265 lineCC = VG_(OSetGen_AllocNode)(CC_table, sizeof(LineCC));
njnd3bef4f2005-10-15 17:46:18 +0000266 lineCC->loc.file = get_perm_string(loc.file);
267 lineCC->loc.fn = get_perm_string(loc.fn);
268 lineCC->loc.line = loc.line;
njn0a8db5c2007-04-02 03:11:41 +0000269 lineCC->Ir.a = 0;
270 lineCC->Ir.m1 = 0;
njn2d853a12010-10-06 22:46:31 +0000271 lineCC->Ir.mL = 0;
njn0a8db5c2007-04-02 03:11:41 +0000272 lineCC->Dr.a = 0;
273 lineCC->Dr.m1 = 0;
njn2d853a12010-10-06 22:46:31 +0000274 lineCC->Dr.mL = 0;
njn0a8db5c2007-04-02 03:11:41 +0000275 lineCC->Dw.a = 0;
276 lineCC->Dw.m1 = 0;
njn2d853a12010-10-06 22:46:31 +0000277 lineCC->Dw.mL = 0;
sewardj8badbaa2007-05-08 09:20:25 +0000278 lineCC->Bc.b = 0;
279 lineCC->Bc.mp = 0;
280 lineCC->Bi.b = 0;
281 lineCC->Bi.mp = 0;
njne2a9ad32007-09-17 05:30:48 +0000282 VG_(OSetGen_Insert)(CC_table, lineCC);
njn4f9c9342002-04-29 16:03:24 +0000283 }
nethercote9313ac42004-07-06 21:54:20 +0000284
njnd3bef4f2005-10-15 17:46:18 +0000285 return lineCC;
njn4f9c9342002-04-29 16:03:24 +0000286}
287
288/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +0000289/*--- Cache simulation functions ---*/
njn4f9c9342002-04-29 16:03:24 +0000290/*------------------------------------------------------------*/
291
njnc52b9322010-09-27 02:20:38 +0000292// Only used with --cache-sim=no.
293static VG_REGPARM(1)
294void log_1I(InstrInfo* n)
295{
296 n->parent->Ir.a++;
297}
298
299// Only used with --cache-sim=no.
300static VG_REGPARM(2)
301void log_2I(InstrInfo* n, InstrInfo* n2)
302{
303 n->parent->Ir.a++;
304 n2->parent->Ir.a++;
305}
306
307// Only used with --cache-sim=no.
308static VG_REGPARM(3)
309void log_3I(InstrInfo* n, InstrInfo* n2, InstrInfo* n3)
310{
311 n->parent->Ir.a++;
312 n2->parent->Ir.a++;
313 n3->parent->Ir.a++;
314}
315
njnaf839f52005-06-23 03:27:57 +0000316static VG_REGPARM(1)
njnd3bef4f2005-10-15 17:46:18 +0000317void log_1I_0D_cache_access(InstrInfo* n)
njn25e49d8e72002-09-23 09:36:25 +0000318{
sewardj5155dec2005-10-12 10:09:23 +0000319 //VG_(printf)("1I_0D : CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n",
320 // n, n->instr_addr, n->instr_len);
njn6a3009b2005-03-20 00:20:06 +0000321 cachesim_I1_doref(n->instr_addr, n->instr_len,
njn2d853a12010-10-06 22:46:31 +0000322 &n->parent->Ir.m1, &n->parent->Ir.mL);
nethercote9313ac42004-07-06 21:54:20 +0000323 n->parent->Ir.a++;
njn25e49d8e72002-09-23 09:36:25 +0000324}
325
njnaf839f52005-06-23 03:27:57 +0000326static VG_REGPARM(2)
njnd3bef4f2005-10-15 17:46:18 +0000327void log_2I_0D_cache_access(InstrInfo* n, InstrInfo* n2)
njn25e49d8e72002-09-23 09:36:25 +0000328{
sewardj5155dec2005-10-12 10:09:23 +0000329 //VG_(printf)("2I_0D : CC1addr=0x%010lx, i1addr=0x%010lx, i1size=%lu\n"
330 // " CC2addr=0x%010lx, i2addr=0x%010lx, i2size=%lu\n",
331 // n, n->instr_addr, n->instr_len,
332 // n2, n2->instr_addr, n2->instr_len);
sewardj5155dec2005-10-12 10:09:23 +0000333 cachesim_I1_doref(n->instr_addr, n->instr_len,
njn2d853a12010-10-06 22:46:31 +0000334 &n->parent->Ir.m1, &n->parent->Ir.mL);
sewardj5155dec2005-10-12 10:09:23 +0000335 n->parent->Ir.a++;
336 cachesim_I1_doref(n2->instr_addr, n2->instr_len,
njn2d853a12010-10-06 22:46:31 +0000337 &n2->parent->Ir.m1, &n2->parent->Ir.mL);
sewardj5155dec2005-10-12 10:09:23 +0000338 n2->parent->Ir.a++;
sewardj5155dec2005-10-12 10:09:23 +0000339}
340
341static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000342void log_3I_0D_cache_access(InstrInfo* n, InstrInfo* n2, InstrInfo* n3)
sewardj5155dec2005-10-12 10:09:23 +0000343{
344 //VG_(printf)("3I_0D : CC1addr=0x%010lx, i1addr=0x%010lx, i1size=%lu\n"
345 // " CC2addr=0x%010lx, i2addr=0x%010lx, i2size=%lu\n"
346 // " CC3addr=0x%010lx, i3addr=0x%010lx, i3size=%lu\n",
347 // n, n->instr_addr, n->instr_len,
348 // n2, n2->instr_addr, n2->instr_len,
349 // n3, n3->instr_addr, n3->instr_len);
sewardj5155dec2005-10-12 10:09:23 +0000350 cachesim_I1_doref(n->instr_addr, n->instr_len,
njn2d853a12010-10-06 22:46:31 +0000351 &n->parent->Ir.m1, &n->parent->Ir.mL);
sewardj5155dec2005-10-12 10:09:23 +0000352 n->parent->Ir.a++;
353 cachesim_I1_doref(n2->instr_addr, n2->instr_len,
njn2d853a12010-10-06 22:46:31 +0000354 &n2->parent->Ir.m1, &n2->parent->Ir.mL);
sewardj5155dec2005-10-12 10:09:23 +0000355 n2->parent->Ir.a++;
356 cachesim_I1_doref(n3->instr_addr, n3->instr_len,
njn2d853a12010-10-06 22:46:31 +0000357 &n3->parent->Ir.m1, &n3->parent->Ir.mL);
sewardj5155dec2005-10-12 10:09:23 +0000358 n3->parent->Ir.a++;
sewardj5155dec2005-10-12 10:09:23 +0000359}
360
361static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000362void log_1I_1Dr_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
sewardj5155dec2005-10-12 10:09:23 +0000363{
364 //VG_(printf)("1I_1Dr: CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n"
365 // " daddr=0x%010lx, dsize=%lu\n",
366 // n, n->instr_addr, n->instr_len, data_addr, data_size);
njn6a3009b2005-03-20 00:20:06 +0000367 cachesim_I1_doref(n->instr_addr, n->instr_len,
njn2d853a12010-10-06 22:46:31 +0000368 &n->parent->Ir.m1, &n->parent->Ir.mL);
nethercote9313ac42004-07-06 21:54:20 +0000369 n->parent->Ir.a++;
njn25e49d8e72002-09-23 09:36:25 +0000370
sewardj5155dec2005-10-12 10:09:23 +0000371 cachesim_D1_doref(data_addr, data_size,
njn2d853a12010-10-06 22:46:31 +0000372 &n->parent->Dr.m1, &n->parent->Dr.mL);
nethercote9313ac42004-07-06 21:54:20 +0000373 n->parent->Dr.a++;
njn25e49d8e72002-09-23 09:36:25 +0000374}
375
sewardj5155dec2005-10-12 10:09:23 +0000376static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000377void log_1I_1Dw_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
njn25e49d8e72002-09-23 09:36:25 +0000378{
sewardj5155dec2005-10-12 10:09:23 +0000379 //VG_(printf)("1I_1Dw: CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n"
380 // " daddr=0x%010lx, dsize=%lu\n",
381 // n, n->instr_addr, n->instr_len, data_addr, data_size);
njn6a3009b2005-03-20 00:20:06 +0000382 cachesim_I1_doref(n->instr_addr, n->instr_len,
njn2d853a12010-10-06 22:46:31 +0000383 &n->parent->Ir.m1, &n->parent->Ir.mL);
nethercote9313ac42004-07-06 21:54:20 +0000384 n->parent->Ir.a++;
385
sewardj5155dec2005-10-12 10:09:23 +0000386 cachesim_D1_doref(data_addr, data_size,
njn2d853a12010-10-06 22:46:31 +0000387 &n->parent->Dw.m1, &n->parent->Dw.mL);
nethercote9313ac42004-07-06 21:54:20 +0000388 n->parent->Dw.a++;
njn25e49d8e72002-09-23 09:36:25 +0000389}
390
njnaf839f52005-06-23 03:27:57 +0000391static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000392void log_0I_1Dr_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
njn25e49d8e72002-09-23 09:36:25 +0000393{
sewardj5155dec2005-10-12 10:09:23 +0000394 //VG_(printf)("0I_1Dr: CCaddr=0x%010lx, daddr=0x%010lx, dsize=%lu\n",
395 // n, data_addr, data_size);
sewardj5155dec2005-10-12 10:09:23 +0000396 cachesim_D1_doref(data_addr, data_size,
njn2d853a12010-10-06 22:46:31 +0000397 &n->parent->Dr.m1, &n->parent->Dr.mL);
nethercote9313ac42004-07-06 21:54:20 +0000398 n->parent->Dr.a++;
sewardj5155dec2005-10-12 10:09:23 +0000399}
400
401static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000402void log_0I_1Dw_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
sewardj5155dec2005-10-12 10:09:23 +0000403{
404 //VG_(printf)("0I_1Dw: CCaddr=0x%010lx, daddr=0x%010lx, dsize=%lu\n",
405 // n, data_addr, data_size);
sewardj5155dec2005-10-12 10:09:23 +0000406 cachesim_D1_doref(data_addr, data_size,
njn2d853a12010-10-06 22:46:31 +0000407 &n->parent->Dw.m1, &n->parent->Dw.mL);
nethercote9313ac42004-07-06 21:54:20 +0000408 n->parent->Dw.a++;
njn25e49d8e72002-09-23 09:36:25 +0000409}
410
sewardj8badbaa2007-05-08 09:20:25 +0000411/* For branches, we consult two different predictors, one which
412 predicts taken/untaken for conditional branches, and the other
413 which predicts the branch target address for indirect branches
414 (jump-to-register style ones). */
415
416static VG_REGPARM(2)
417void log_cond_branch(InstrInfo* n, Word taken)
418{
419 //VG_(printf)("cbrnch: CCaddr=0x%010lx, taken=0x%010lx\n",
420 // n, taken);
421 n->parent->Bc.b++;
422 n->parent->Bc.mp
423 += (1 & do_cond_branch_predict(n->instr_addr, taken));
424}
425
426static VG_REGPARM(2)
427void log_ind_branch(InstrInfo* n, UWord actual_dst)
428{
429 //VG_(printf)("ibrnch: CCaddr=0x%010lx, dst=0x%010lx\n",
430 // n, actual_dst);
431 n->parent->Bi.b++;
432 n->parent->Bi.mp
433 += (1 & do_ind_branch_predict(n->instr_addr, actual_dst));
434}
435
436
nethercote9313ac42004-07-06 21:54:20 +0000437/*------------------------------------------------------------*/
sewardj5155dec2005-10-12 10:09:23 +0000438/*--- Instrumentation types and structures ---*/
439/*------------------------------------------------------------*/
440
441/* Maintain an ordered list of memory events which are outstanding, in
442 the sense that no IR has yet been generated to do the relevant
443 helper calls. The BB is scanned top to bottom and memory events
444 are added to the end of the list, merging with the most recent
445 notified event where possible (Dw immediately following Dr and
446 having the same size and EA can be merged).
447
448 This merging is done so that for architectures which have
449 load-op-store instructions (x86, amd64), the insn is treated as if
450 it makes just one memory reference (a modify), rather than two (a
451 read followed by a write at the same address).
452
453 At various points the list will need to be flushed, that is, IR
454 generated from it. That must happen before any possible exit from
455 the block (the end, or an IRStmt_Exit). Flushing also takes place
456 when there is no space to add a new event.
457
458 If we require the simulation statistics to be up to date with
459 respect to possible memory exceptions, then the list would have to
460 be flushed before each memory reference. That would however lose
461 performance by inhibiting event-merging during flushing.
462
463 Flushing the list consists of walking it start to end and emitting
464 instrumentation IR for each event, in the order in which they
465 appear. It may be possible to emit a single call for two adjacent
466 events in order to reduce the number of helper function calls made.
467 For example, it could well be profitable to handle two adjacent Ir
468 events with a single helper call. */
469
470typedef
471 IRExpr
472 IRAtom;
473
474typedef
sewardj8badbaa2007-05-08 09:20:25 +0000475 enum {
476 Ev_Ir, // Instruction read
477 Ev_Dr, // Data read
478 Ev_Dw, // Data write
479 Ev_Dm, // Data modify (read then write)
480 Ev_Bc, // branch conditional
481 Ev_Bi // branch indirect (to unknown destination)
482 }
483 EventTag;
sewardj5155dec2005-10-12 10:09:23 +0000484
485typedef
486 struct {
sewardj8badbaa2007-05-08 09:20:25 +0000487 EventTag tag;
488 InstrInfo* inode;
489 union {
490 struct {
491 } Ir;
492 struct {
493 IRAtom* ea;
494 Int szB;
495 } Dr;
496 struct {
497 IRAtom* ea;
498 Int szB;
499 } Dw;
500 struct {
501 IRAtom* ea;
502 Int szB;
503 } Dm;
504 struct {
505 IRAtom* taken; /* :: Ity_I1 */
506 } Bc;
507 struct {
508 IRAtom* dst;
509 } Bi;
510 } Ev;
sewardj5155dec2005-10-12 10:09:23 +0000511 }
512 Event;
513
sewardj8badbaa2007-05-08 09:20:25 +0000514static void init_Event ( Event* ev ) {
515 VG_(memset)(ev, 0, sizeof(Event));
516}
517
518static IRAtom* get_Event_dea ( Event* ev ) {
519 switch (ev->tag) {
520 case Ev_Dr: return ev->Ev.Dr.ea;
521 case Ev_Dw: return ev->Ev.Dw.ea;
522 case Ev_Dm: return ev->Ev.Dm.ea;
523 default: tl_assert(0);
524 }
525}
526
527static Int get_Event_dszB ( Event* ev ) {
528 switch (ev->tag) {
529 case Ev_Dr: return ev->Ev.Dr.szB;
530 case Ev_Dw: return ev->Ev.Dw.szB;
531 case Ev_Dm: return ev->Ev.Dm.szB;
532 default: tl_assert(0);
533 }
534}
535
536
sewardj5155dec2005-10-12 10:09:23 +0000537/* Up to this many unnotified events are allowed. Number is
538 arbitrary. Larger numbers allow more event merging to occur, but
539 potentially induce more spilling due to extending live ranges of
540 address temporaries. */
541#define N_EVENTS 16
542
543
544/* A struct which holds all the running state during instrumentation.
545 Mostly to avoid passing loads of parameters everywhere. */
546typedef
547 struct {
548 /* The current outstanding-memory-event list. */
549 Event events[N_EVENTS];
550 Int events_used;
551
njnd3bef4f2005-10-15 17:46:18 +0000552 /* The array of InstrInfo bins for the BB. */
sewardj0b9d74a2006-12-24 02:24:11 +0000553 SB_info* sbInfo;
sewardj5155dec2005-10-12 10:09:23 +0000554
njnd3bef4f2005-10-15 17:46:18 +0000555 /* Number InstrInfo bins 'used' so far. */
sewardj0b9d74a2006-12-24 02:24:11 +0000556 Int sbInfo_i;
sewardj5155dec2005-10-12 10:09:23 +0000557
sewardj0b9d74a2006-12-24 02:24:11 +0000558 /* The output SB being constructed. */
559 IRSB* sbOut;
sewardj5155dec2005-10-12 10:09:23 +0000560 }
561 CgState;
562
563
sewardj5155dec2005-10-12 10:09:23 +0000564/*------------------------------------------------------------*/
565/*--- Instrumentation main ---*/
nethercote9313ac42004-07-06 21:54:20 +0000566/*------------------------------------------------------------*/
567
sewardj4ba057c2005-10-18 12:04:18 +0000568// Note that origAddr is the real origAddr, not the address of the first
569// instruction in the block (they can be different due to redirection).
nethercote564b2b02004-08-07 15:54:53 +0000570static
sewardj0b9d74a2006-12-24 02:24:11 +0000571SB_info* get_SB_info(IRSB* sbIn, Addr origAddr)
nethercote9313ac42004-07-06 21:54:20 +0000572{
njn4bd67b52005-08-11 00:47:10 +0000573 Int i, n_instrs;
574 IRStmt* st;
sewardj0b9d74a2006-12-24 02:24:11 +0000575 SB_info* sbInfo;
njnd3bef4f2005-10-15 17:46:18 +0000576
sewardj0b9d74a2006-12-24 02:24:11 +0000577 // Count number of original instrs in SB
njn6a3009b2005-03-20 00:20:06 +0000578 n_instrs = 0;
sewardj0b9d74a2006-12-24 02:24:11 +0000579 for (i = 0; i < sbIn->stmts_used; i++) {
580 st = sbIn->stmts[i];
njn6a3009b2005-03-20 00:20:06 +0000581 if (Ist_IMark == st->tag) n_instrs++;
nethercote9313ac42004-07-06 21:54:20 +0000582 }
583
njnf7d26092005-10-12 16:45:17 +0000584 // Check that we don't have an entry for this BB in the instr-info table.
585 // If this assertion fails, there has been some screwup: some
586 // translations must have been discarded but Cachegrind hasn't discarded
587 // the corresponding entries in the instr-info table.
njne2a9ad32007-09-17 05:30:48 +0000588 sbInfo = VG_(OSetGen_Lookup)(instrInfoTable, &origAddr);
sewardj0b9d74a2006-12-24 02:24:11 +0000589 tl_assert(NULL == sbInfo);
sewardja3a29a52005-10-12 16:16:03 +0000590
njnd3bef4f2005-10-15 17:46:18 +0000591 // BB never translated before (at this address, at least; could have
592 // been unloaded and then reloaded elsewhere in memory)
njne2a9ad32007-09-17 05:30:48 +0000593 sbInfo = VG_(OSetGen_AllocNode)(instrInfoTable,
sewardj0b9d74a2006-12-24 02:24:11 +0000594 sizeof(SB_info) + n_instrs*sizeof(InstrInfo));
595 sbInfo->SB_addr = origAddr;
596 sbInfo->n_instrs = n_instrs;
njne2a9ad32007-09-17 05:30:48 +0000597 VG_(OSetGen_Insert)( instrInfoTable, sbInfo );
sewardja3a29a52005-10-12 16:16:03 +0000598 distinct_instrs++;
599
sewardj0b9d74a2006-12-24 02:24:11 +0000600 return sbInfo;
nethercote9313ac42004-07-06 21:54:20 +0000601}
njn6a3009b2005-03-20 00:20:06 +0000602
nethercote9313ac42004-07-06 21:54:20 +0000603
sewardj5155dec2005-10-12 10:09:23 +0000604static void showEvent ( Event* ev )
nethercote9313ac42004-07-06 21:54:20 +0000605{
sewardj8badbaa2007-05-08 09:20:25 +0000606 switch (ev->tag) {
607 case Ev_Ir:
njnfd9f6222005-10-16 00:17:37 +0000608 VG_(printf)("Ir %p\n", ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000609 break;
sewardj8badbaa2007-05-08 09:20:25 +0000610 case Ev_Dr:
611 VG_(printf)("Dr %p %d EA=", ev->inode, ev->Ev.Dr.szB);
612 ppIRExpr(ev->Ev.Dr.ea);
sewardj5155dec2005-10-12 10:09:23 +0000613 VG_(printf)("\n");
614 break;
sewardj8badbaa2007-05-08 09:20:25 +0000615 case Ev_Dw:
616 VG_(printf)("Dw %p %d EA=", ev->inode, ev->Ev.Dw.szB);
617 ppIRExpr(ev->Ev.Dw.ea);
sewardj5155dec2005-10-12 10:09:23 +0000618 VG_(printf)("\n");
619 break;
sewardj8badbaa2007-05-08 09:20:25 +0000620 case Ev_Dm:
621 VG_(printf)("Dm %p %d EA=", ev->inode, ev->Ev.Dm.szB);
622 ppIRExpr(ev->Ev.Dm.ea);
623 VG_(printf)("\n");
624 break;
625 case Ev_Bc:
626 VG_(printf)("Bc %p GA=", ev->inode);
627 ppIRExpr(ev->Ev.Bc.taken);
628 VG_(printf)("\n");
629 break;
630 case Ev_Bi:
631 VG_(printf)("Bi %p DST=", ev->inode);
632 ppIRExpr(ev->Ev.Bi.dst);
sewardj5155dec2005-10-12 10:09:23 +0000633 VG_(printf)("\n");
634 break;
635 default:
636 tl_assert(0);
637 break;
638 }
njn6a3009b2005-03-20 00:20:06 +0000639}
640
njnfd9f6222005-10-16 00:17:37 +0000641// Reserve and initialise an InstrInfo for the first mention of a new insn.
642static
643InstrInfo* setup_InstrInfo ( CgState* cgs, Addr instr_addr, UInt instr_len )
njn6a3009b2005-03-20 00:20:06 +0000644{
njnd3bef4f2005-10-15 17:46:18 +0000645 InstrInfo* i_node;
sewardj0b9d74a2006-12-24 02:24:11 +0000646 tl_assert(cgs->sbInfo_i >= 0);
647 tl_assert(cgs->sbInfo_i < cgs->sbInfo->n_instrs);
648 i_node = &cgs->sbInfo->instrs[ cgs->sbInfo_i ];
njnfd9f6222005-10-16 00:17:37 +0000649 i_node->instr_addr = instr_addr;
650 i_node->instr_len = instr_len;
651 i_node->parent = get_lineCC(instr_addr);
sewardj0b9d74a2006-12-24 02:24:11 +0000652 cgs->sbInfo_i++;
sewardj5155dec2005-10-12 10:09:23 +0000653 return i_node;
654}
sewardj17a56bf2005-03-21 01:35:02 +0000655
sewardj17a56bf2005-03-21 01:35:02 +0000656
sewardj5155dec2005-10-12 10:09:23 +0000657/* Generate code for all outstanding memory events, and mark the queue
658 empty. Code is generated into cgs->bbOut, and this activity
sewardj0b9d74a2006-12-24 02:24:11 +0000659 'consumes' slots in cgs->sbInfo. */
njn6a3009b2005-03-20 00:20:06 +0000660
sewardj5155dec2005-10-12 10:09:23 +0000661static void flushEvents ( CgState* cgs )
662{
njnd3bef4f2005-10-15 17:46:18 +0000663 Int i, regparms;
664 Char* helperName;
665 void* helperAddr;
666 IRExpr** argv;
667 IRExpr* i_node_expr;
njnd3bef4f2005-10-15 17:46:18 +0000668 IRDirty* di;
njnc285dca2005-10-15 22:07:28 +0000669 Event* ev;
670 Event* ev2;
671 Event* ev3;
njn6a3009b2005-03-20 00:20:06 +0000672
sewardj5155dec2005-10-12 10:09:23 +0000673 i = 0;
674 while (i < cgs->events_used) {
njn6a3009b2005-03-20 00:20:06 +0000675
sewardj5155dec2005-10-12 10:09:23 +0000676 helperName = NULL;
677 helperAddr = NULL;
678 argv = NULL;
679 regparms = 0;
680
681 /* generate IR to notify event i and possibly the ones
682 immediately following it. */
683 tl_assert(i >= 0 && i < cgs->events_used);
njnc285dca2005-10-15 22:07:28 +0000684
685 ev = &cgs->events[i];
686 ev2 = ( i < cgs->events_used-1 ? &cgs->events[i+1] : NULL );
687 ev3 = ( i < cgs->events_used-2 ? &cgs->events[i+2] : NULL );
688
sewardj5155dec2005-10-12 10:09:23 +0000689 if (DEBUG_CG) {
690 VG_(printf)(" flush ");
njnc285dca2005-10-15 22:07:28 +0000691 showEvent( ev );
njn4f9c9342002-04-29 16:03:24 +0000692 }
sewardj5155dec2005-10-12 10:09:23 +0000693
njnfd9f6222005-10-16 00:17:37 +0000694 i_node_expr = mkIRExpr_HWord( (HWord)ev->inode );
sewardj5155dec2005-10-12 10:09:23 +0000695
696 /* Decide on helper fn to call and args to pass it, and advance
697 i appropriately. */
sewardj8badbaa2007-05-08 09:20:25 +0000698 switch (ev->tag) {
699 case Ev_Ir:
700 /* Merge an Ir with a following Dr/Dm. */
701 if (ev2 && (ev2->tag == Ev_Dr || ev2->tag == Ev_Dm)) {
702 /* Why is this true? It's because we're merging an Ir
703 with a following Dr or Dm. The Ir derives from the
704 instruction's IMark and the Dr/Dm from data
705 references which follow it. In short it holds
706 because each insn starts with an IMark, hence an
707 Ev_Ir, and so these Dr/Dm must pertain to the
708 immediately preceding Ir. Same applies to analogous
709 assertions in the subsequent cases. */
njnfd9f6222005-10-16 00:17:37 +0000710 tl_assert(ev2->inode == ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000711 helperName = "log_1I_1Dr_cache_access";
712 helperAddr = &log_1I_1Dr_cache_access;
713 argv = mkIRExprVec_3( i_node_expr,
sewardj8badbaa2007-05-08 09:20:25 +0000714 get_Event_dea(ev2),
715 mkIRExpr_HWord( get_Event_dszB(ev2) ) );
sewardj5155dec2005-10-12 10:09:23 +0000716 regparms = 3;
717 i += 2;
718 }
sewardj8badbaa2007-05-08 09:20:25 +0000719 /* Merge an Ir with a following Dw. */
sewardj5155dec2005-10-12 10:09:23 +0000720 else
sewardj8badbaa2007-05-08 09:20:25 +0000721 if (ev2 && ev2->tag == Ev_Dw) {
njnfd9f6222005-10-16 00:17:37 +0000722 tl_assert(ev2->inode == ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000723 helperName = "log_1I_1Dw_cache_access";
724 helperAddr = &log_1I_1Dw_cache_access;
725 argv = mkIRExprVec_3( i_node_expr,
sewardj8badbaa2007-05-08 09:20:25 +0000726 get_Event_dea(ev2),
727 mkIRExpr_HWord( get_Event_dszB(ev2) ) );
sewardj5155dec2005-10-12 10:09:23 +0000728 regparms = 3;
729 i += 2;
730 }
sewardj8badbaa2007-05-08 09:20:25 +0000731 /* Merge an Ir with two following Irs. */
sewardj5155dec2005-10-12 10:09:23 +0000732 else
sewardj8badbaa2007-05-08 09:20:25 +0000733 if (ev2 && ev3 && ev2->tag == Ev_Ir && ev3->tag == Ev_Ir)
njnc285dca2005-10-15 22:07:28 +0000734 {
njnc52b9322010-09-27 02:20:38 +0000735 if (clo_cache_sim) {
736 helperName = "log_3I_0D_cache_access";
737 helperAddr = &log_3I_0D_cache_access;
738 } else {
739 helperName = "log_3I";
740 helperAddr = &log_3I;
741 }
njnfd9f6222005-10-16 00:17:37 +0000742 argv = mkIRExprVec_3( i_node_expr,
743 mkIRExpr_HWord( (HWord)ev2->inode ),
744 mkIRExpr_HWord( (HWord)ev3->inode ) );
sewardj5155dec2005-10-12 10:09:23 +0000745 regparms = 3;
746 i += 3;
747 }
sewardj8badbaa2007-05-08 09:20:25 +0000748 /* Merge an Ir with one following Ir. */
sewardj5155dec2005-10-12 10:09:23 +0000749 else
sewardj8badbaa2007-05-08 09:20:25 +0000750 if (ev2 && ev2->tag == Ev_Ir) {
njnc52b9322010-09-27 02:20:38 +0000751 if (clo_cache_sim) {
752 helperName = "log_2I_0D_cache_access";
753 helperAddr = &log_2I_0D_cache_access;
754 } else {
755 helperName = "log_2I";
756 helperAddr = &log_2I;
757 }
njnfd9f6222005-10-16 00:17:37 +0000758 argv = mkIRExprVec_2( i_node_expr,
759 mkIRExpr_HWord( (HWord)ev2->inode ) );
sewardj5155dec2005-10-12 10:09:23 +0000760 regparms = 2;
761 i += 2;
762 }
763 /* No merging possible; emit as-is. */
764 else {
njnc52b9322010-09-27 02:20:38 +0000765 if (clo_cache_sim) {
766 helperName = "log_1I_0D_cache_access";
767 helperAddr = &log_1I_0D_cache_access;
768 } else {
769 helperName = "log_1I";
770 helperAddr = &log_1I;
771 }
sewardj5155dec2005-10-12 10:09:23 +0000772 argv = mkIRExprVec_1( i_node_expr );
773 regparms = 1;
774 i++;
775 }
776 break;
sewardj8badbaa2007-05-08 09:20:25 +0000777 case Ev_Dr:
778 case Ev_Dm:
779 /* Data read or modify */
sewardj5155dec2005-10-12 10:09:23 +0000780 helperName = "log_0I_1Dr_cache_access";
781 helperAddr = &log_0I_1Dr_cache_access;
782 argv = mkIRExprVec_3( i_node_expr,
sewardj8badbaa2007-05-08 09:20:25 +0000783 get_Event_dea(ev),
784 mkIRExpr_HWord( get_Event_dszB(ev) ) );
sewardj5155dec2005-10-12 10:09:23 +0000785 regparms = 3;
786 i++;
787 break;
sewardj8badbaa2007-05-08 09:20:25 +0000788 case Ev_Dw:
789 /* Data write */
sewardj5155dec2005-10-12 10:09:23 +0000790 helperName = "log_0I_1Dw_cache_access";
791 helperAddr = &log_0I_1Dw_cache_access;
792 argv = mkIRExprVec_3( i_node_expr,
sewardj8badbaa2007-05-08 09:20:25 +0000793 get_Event_dea(ev),
794 mkIRExpr_HWord( get_Event_dszB(ev) ) );
sewardj5155dec2005-10-12 10:09:23 +0000795 regparms = 3;
796 i++;
797 break;
sewardj8badbaa2007-05-08 09:20:25 +0000798 case Ev_Bc:
799 /* Conditional branch */
800 helperName = "log_cond_branch";
801 helperAddr = &log_cond_branch;
802 argv = mkIRExprVec_2( i_node_expr, ev->Ev.Bc.taken );
803 regparms = 2;
804 i++;
805 break;
806 case Ev_Bi:
807 /* Branch to an unknown destination */
808 helperName = "log_ind_branch";
809 helperAddr = &log_ind_branch;
810 argv = mkIRExprVec_2( i_node_expr, ev->Ev.Bi.dst );
811 regparms = 2;
812 i++;
813 break;
sewardj5155dec2005-10-12 10:09:23 +0000814 default:
815 tl_assert(0);
816 }
817
818 /* Add the helper. */
819 tl_assert(helperName);
820 tl_assert(helperAddr);
821 tl_assert(argv);
sewardj5bb86822005-12-23 12:47:42 +0000822 di = unsafeIRDirty_0_N( regparms,
823 helperName, VG_(fnptr_to_fnentry)( helperAddr ),
824 argv );
sewardj0b9d74a2006-12-24 02:24:11 +0000825 addStmtToIRSB( cgs->sbOut, IRStmt_Dirty(di) );
njn4f9c9342002-04-29 16:03:24 +0000826 }
827
sewardj5155dec2005-10-12 10:09:23 +0000828 cgs->events_used = 0;
njn4f9c9342002-04-29 16:03:24 +0000829}
njn14d01ce2004-11-26 11:30:14 +0000830
njnfd9f6222005-10-16 00:17:37 +0000831static void addEvent_Ir ( CgState* cgs, InstrInfo* inode )
sewardj5155dec2005-10-12 10:09:23 +0000832{
833 Event* evt;
sewardj5155dec2005-10-12 10:09:23 +0000834 if (cgs->events_used == N_EVENTS)
835 flushEvents(cgs);
836 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
837 evt = &cgs->events[cgs->events_used];
sewardj8badbaa2007-05-08 09:20:25 +0000838 init_Event(evt);
839 evt->tag = Ev_Ir;
njnfd9f6222005-10-16 00:17:37 +0000840 evt->inode = inode;
sewardj5155dec2005-10-12 10:09:23 +0000841 cgs->events_used++;
842}
843
njnfd9f6222005-10-16 00:17:37 +0000844static
845void addEvent_Dr ( CgState* cgs, InstrInfo* inode, Int datasize, IRAtom* ea )
sewardj5155dec2005-10-12 10:09:23 +0000846{
njnfd9f6222005-10-16 00:17:37 +0000847 Event* evt;
sewardj5155dec2005-10-12 10:09:23 +0000848 tl_assert(isIRAtom(ea));
njnfd9f6222005-10-16 00:17:37 +0000849 tl_assert(datasize >= 1 && datasize <= MIN_LINE_SIZE);
sewardj8badbaa2007-05-08 09:20:25 +0000850 if (!clo_cache_sim)
851 return;
njnfd9f6222005-10-16 00:17:37 +0000852 if (cgs->events_used == N_EVENTS)
853 flushEvents(cgs);
854 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
855 evt = &cgs->events[cgs->events_used];
sewardj8badbaa2007-05-08 09:20:25 +0000856 init_Event(evt);
857 evt->tag = Ev_Dr;
858 evt->inode = inode;
859 evt->Ev.Dr.szB = datasize;
860 evt->Ev.Dr.ea = ea;
njnfd9f6222005-10-16 00:17:37 +0000861 cgs->events_used++;
862}
sewardj5155dec2005-10-12 10:09:23 +0000863
njnfd9f6222005-10-16 00:17:37 +0000864static
865void addEvent_Dw ( CgState* cgs, InstrInfo* inode, Int datasize, IRAtom* ea )
866{
867 Event* lastEvt;
868 Event* evt;
869
870 tl_assert(isIRAtom(ea));
871 tl_assert(datasize >= 1 && datasize <= MIN_LINE_SIZE);
872
sewardj8badbaa2007-05-08 09:20:25 +0000873 if (!clo_cache_sim)
874 return;
875
njnfd9f6222005-10-16 00:17:37 +0000876 /* Is it possible to merge this write with the preceding read? */
877 lastEvt = &cgs->events[cgs->events_used-1];
sewardj5155dec2005-10-12 10:09:23 +0000878 if (cgs->events_used > 0
sewardj8badbaa2007-05-08 09:20:25 +0000879 && lastEvt->tag == Ev_Dr
880 && lastEvt->Ev.Dr.szB == datasize
881 && lastEvt->inode == inode
882 && eqIRAtom(lastEvt->Ev.Dr.ea, ea))
njnfd9f6222005-10-16 00:17:37 +0000883 {
sewardj8badbaa2007-05-08 09:20:25 +0000884 lastEvt->tag = Ev_Dm;
sewardj5155dec2005-10-12 10:09:23 +0000885 return;
886 }
887
888 /* No. Add as normal. */
889 if (cgs->events_used == N_EVENTS)
890 flushEvents(cgs);
891 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
njnfd9f6222005-10-16 00:17:37 +0000892 evt = &cgs->events[cgs->events_used];
sewardj8badbaa2007-05-08 09:20:25 +0000893 init_Event(evt);
894 evt->tag = Ev_Dw;
895 evt->inode = inode;
896 evt->Ev.Dw.szB = datasize;
897 evt->Ev.Dw.ea = ea;
898 cgs->events_used++;
899}
900
901static
902void addEvent_Bc ( CgState* cgs, InstrInfo* inode, IRAtom* guard )
903{
904 Event* evt;
905 tl_assert(isIRAtom(guard));
906 tl_assert(typeOfIRExpr(cgs->sbOut->tyenv, guard)
907 == (sizeof(HWord)==4 ? Ity_I32 : Ity_I64));
908 if (!clo_branch_sim)
909 return;
910 if (cgs->events_used == N_EVENTS)
911 flushEvents(cgs);
912 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
913 evt = &cgs->events[cgs->events_used];
914 init_Event(evt);
915 evt->tag = Ev_Bc;
916 evt->inode = inode;
917 evt->Ev.Bc.taken = guard;
918 cgs->events_used++;
919}
920
921static
922void addEvent_Bi ( CgState* cgs, InstrInfo* inode, IRAtom* whereTo )
923{
924 Event* evt;
925 tl_assert(isIRAtom(whereTo));
926 tl_assert(typeOfIRExpr(cgs->sbOut->tyenv, whereTo)
927 == (sizeof(HWord)==4 ? Ity_I32 : Ity_I64));
928 if (!clo_branch_sim)
929 return;
930 if (cgs->events_used == N_EVENTS)
931 flushEvents(cgs);
932 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
933 evt = &cgs->events[cgs->events_used];
934 init_Event(evt);
935 evt->tag = Ev_Bi;
936 evt->inode = inode;
937 evt->Ev.Bi.dst = whereTo;
sewardj5155dec2005-10-12 10:09:23 +0000938 cgs->events_used++;
939}
940
941////////////////////////////////////////////////////////////
942
943
sewardj4ba057c2005-10-18 12:04:18 +0000944static
sewardj0b9d74a2006-12-24 02:24:11 +0000945IRSB* cg_instrument ( VgCallbackClosure* closure,
946 IRSB* sbIn,
sewardj461df9c2006-01-17 02:06:39 +0000947 VexGuestLayout* layout,
948 VexGuestExtents* vge,
sewardj4ba057c2005-10-18 12:04:18 +0000949 IRType gWordTy, IRType hWordTy )
njn14d01ce2004-11-26 11:30:14 +0000950{
njnfd9f6222005-10-16 00:17:37 +0000951 Int i, isize;
sewardj5155dec2005-10-12 10:09:23 +0000952 IRStmt* st;
953 Addr64 cia; /* address of current insn */
954 CgState cgs;
sewardj0b9d74a2006-12-24 02:24:11 +0000955 IRTypeEnv* tyenv = sbIn->tyenv;
njnfd9f6222005-10-16 00:17:37 +0000956 InstrInfo* curr_inode = NULL;
sewardj5155dec2005-10-12 10:09:23 +0000957
sewardjd54babf2005-03-21 00:55:49 +0000958 if (gWordTy != hWordTy) {
959 /* We don't currently support this case. */
960 VG_(tool_panic)("host/guest word size mismatch");
961 }
962
sewardj0b9d74a2006-12-24 02:24:11 +0000963 // Set up new SB
964 cgs.sbOut = deepCopyIRSBExceptStmts(sbIn);
njn6a3009b2005-03-20 00:20:06 +0000965
sewardja9f538c2005-10-23 12:06:55 +0000966 // Copy verbatim any IR preamble preceding the first IMark
njn6a3009b2005-03-20 00:20:06 +0000967 i = 0;
sewardj0b9d74a2006-12-24 02:24:11 +0000968 while (i < sbIn->stmts_used && sbIn->stmts[i]->tag != Ist_IMark) {
969 addStmtToIRSB( cgs.sbOut, sbIn->stmts[i] );
sewardja9f538c2005-10-23 12:06:55 +0000970 i++;
971 }
972
973 // Get the first statement, and initial cia from it
sewardj0b9d74a2006-12-24 02:24:11 +0000974 tl_assert(sbIn->stmts_used > 0);
975 tl_assert(i < sbIn->stmts_used);
976 st = sbIn->stmts[i];
njn6a3009b2005-03-20 00:20:06 +0000977 tl_assert(Ist_IMark == st->tag);
sewardj8badbaa2007-05-08 09:20:25 +0000978
979 cia = st->Ist.IMark.addr;
980 isize = st->Ist.IMark.len;
981 // If Vex fails to decode an instruction, the size will be zero.
982 // Pretend otherwise.
983 if (isize == 0) isize = VG_MIN_INSTR_SZB;
njn6a3009b2005-03-20 00:20:06 +0000984
sewardj5155dec2005-10-12 10:09:23 +0000985 // Set up running state and get block info
sewardj3a384b32006-01-22 01:12:51 +0000986 tl_assert(closure->readdr == vge->base[0]);
sewardj5155dec2005-10-12 10:09:23 +0000987 cgs.events_used = 0;
sewardj0b9d74a2006-12-24 02:24:11 +0000988 cgs.sbInfo = get_SB_info(sbIn, (Addr)closure->readdr);
989 cgs.sbInfo_i = 0;
njn6a3009b2005-03-20 00:20:06 +0000990
sewardj5155dec2005-10-12 10:09:23 +0000991 if (DEBUG_CG)
992 VG_(printf)("\n\n---------- cg_instrument ----------\n");
njn6a3009b2005-03-20 00:20:06 +0000993
njnfd9f6222005-10-16 00:17:37 +0000994 // Traverse the block, initialising inodes, adding events and flushing as
995 // necessary.
sewardj0b9d74a2006-12-24 02:24:11 +0000996 for (/*use current i*/; i < sbIn->stmts_used; i++) {
njn6a3009b2005-03-20 00:20:06 +0000997
sewardj0b9d74a2006-12-24 02:24:11 +0000998 st = sbIn->stmts[i];
sewardj5155dec2005-10-12 10:09:23 +0000999 tl_assert(isFlatIRStmt(st));
njnb3507ea2005-08-02 23:07:02 +00001000
sewardj5155dec2005-10-12 10:09:23 +00001001 switch (st->tag) {
1002 case Ist_NoOp:
1003 case Ist_AbiHint:
1004 case Ist_Put:
1005 case Ist_PutI:
sewardj72d75132007-11-09 23:06:35 +00001006 case Ist_MBE:
sewardj5155dec2005-10-12 10:09:23 +00001007 break;
njn20677cc2005-08-12 23:47:51 +00001008
sewardj5155dec2005-10-12 10:09:23 +00001009 case Ist_IMark:
njnfd9f6222005-10-16 00:17:37 +00001010 cia = st->Ist.IMark.addr;
1011 isize = st->Ist.IMark.len;
1012
1013 // If Vex fails to decode an instruction, the size will be zero.
1014 // Pretend otherwise.
1015 if (isize == 0) isize = VG_MIN_INSTR_SZB;
1016
njna5ad9ba2005-11-10 15:20:37 +00001017 // Sanity-check size.
1018 tl_assert( (VG_MIN_INSTR_SZB <= isize && isize <= VG_MAX_INSTR_SZB)
1019 || VG_CLREQ_SZB == isize );
njnfd9f6222005-10-16 00:17:37 +00001020
1021 // Get space for and init the inode, record it as the current one.
1022 // Subsequent Dr/Dw/Dm events from the same instruction will
1023 // also use it.
1024 curr_inode = setup_InstrInfo(&cgs, cia, isize);
1025
1026 addEvent_Ir( &cgs, curr_inode );
sewardj5155dec2005-10-12 10:09:23 +00001027 break;
1028
sewardj0b9d74a2006-12-24 02:24:11 +00001029 case Ist_WrTmp: {
1030 IRExpr* data = st->Ist.WrTmp.data;
sewardj5155dec2005-10-12 10:09:23 +00001031 if (data->tag == Iex_Load) {
1032 IRExpr* aexpr = data->Iex.Load.addr;
sewardj5155dec2005-10-12 10:09:23 +00001033 // Note also, endianness info is ignored. I guess
1034 // that's not interesting.
njnfd9f6222005-10-16 00:17:37 +00001035 addEvent_Dr( &cgs, curr_inode, sizeofIRType(data->Iex.Load.ty),
1036 aexpr );
sewardj5155dec2005-10-12 10:09:23 +00001037 }
1038 break;
njnb3507ea2005-08-02 23:07:02 +00001039 }
1040
sewardj5155dec2005-10-12 10:09:23 +00001041 case Ist_Store: {
1042 IRExpr* data = st->Ist.Store.data;
1043 IRExpr* aexpr = st->Ist.Store.addr;
njnfd9f6222005-10-16 00:17:37 +00001044 addEvent_Dw( &cgs, curr_inode,
1045 sizeofIRType(typeOfIRExpr(tyenv, data)), aexpr );
sewardj5155dec2005-10-12 10:09:23 +00001046 break;
1047 }
njnb3507ea2005-08-02 23:07:02 +00001048
sewardj5155dec2005-10-12 10:09:23 +00001049 case Ist_Dirty: {
1050 Int dataSize;
1051 IRDirty* d = st->Ist.Dirty.details;
1052 if (d->mFx != Ifx_None) {
njnfd9f6222005-10-16 00:17:37 +00001053 /* This dirty helper accesses memory. Collect the details. */
sewardj5155dec2005-10-12 10:09:23 +00001054 tl_assert(d->mAddr != NULL);
1055 tl_assert(d->mSize != 0);
1056 dataSize = d->mSize;
1057 // Large (eg. 28B, 108B, 512B on x86) data-sized
1058 // instructions will be done inaccurately, but they're
1059 // very rare and this avoids errors from hitting more
1060 // than two cache lines in the simulation.
1061 if (dataSize > MIN_LINE_SIZE)
1062 dataSize = MIN_LINE_SIZE;
1063 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
njnfd9f6222005-10-16 00:17:37 +00001064 addEvent_Dr( &cgs, curr_inode, dataSize, d->mAddr );
sewardj5155dec2005-10-12 10:09:23 +00001065 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
njnfd9f6222005-10-16 00:17:37 +00001066 addEvent_Dw( &cgs, curr_inode, dataSize, d->mAddr );
sewardj5155dec2005-10-12 10:09:23 +00001067 } else {
1068 tl_assert(d->mAddr == NULL);
1069 tl_assert(d->mSize == 0);
1070 }
1071 break;
1072 }
njn6a3009b2005-03-20 00:20:06 +00001073
sewardj1c0ce7a2009-07-01 08:10:49 +00001074 case Ist_CAS: {
1075 /* We treat it as a read and a write of the location. I
1076 think that is the same behaviour as it was before IRCAS
1077 was introduced, since prior to that point, the Vex
1078 front ends would translate a lock-prefixed instruction
1079 into a (normal) read followed by a (normal) write. */
1080 Int dataSize;
1081 IRCAS* cas = st->Ist.CAS.details;
1082 tl_assert(cas->addr != NULL);
1083 tl_assert(cas->dataLo != NULL);
1084 dataSize = sizeofIRType(typeOfIRExpr(tyenv, cas->dataLo));
1085 if (cas->dataHi != NULL)
1086 dataSize *= 2; /* since it's a doubleword-CAS */
1087 /* I don't think this can ever happen, but play safe. */
1088 if (dataSize > MIN_LINE_SIZE)
1089 dataSize = MIN_LINE_SIZE;
1090 addEvent_Dr( &cgs, curr_inode, dataSize, cas->addr );
1091 addEvent_Dw( &cgs, curr_inode, dataSize, cas->addr );
1092 break;
1093 }
1094
sewardjdb5907d2009-11-26 17:20:21 +00001095 case Ist_LLSC: {
1096 IRType dataTy;
1097 if (st->Ist.LLSC.storedata == NULL) {
1098 /* LL */
1099 dataTy = typeOfIRTemp(tyenv, st->Ist.LLSC.result);
1100 addEvent_Dr( &cgs, curr_inode,
1101 sizeofIRType(dataTy), st->Ist.LLSC.addr );
1102 } else {
1103 /* SC */
1104 dataTy = typeOfIRExpr(tyenv, st->Ist.LLSC.storedata);
1105 addEvent_Dw( &cgs, curr_inode,
1106 sizeofIRType(dataTy), st->Ist.LLSC.addr );
1107 }
1108 break;
1109 }
1110
sewardj8badbaa2007-05-08 09:20:25 +00001111 case Ist_Exit: {
weidendo374a48f2010-09-02 17:06:49 +00001112 // call branch predictor only if this is a branch in guest code
1113 if ( (st->Ist.Exit.jk == Ijk_Boring) ||
1114 (st->Ist.Exit.jk == Ijk_Call) ||
1115 (st->Ist.Exit.jk == Ijk_Ret) )
1116 {
1117 /* Stuff to widen the guard expression to a host word, so
1118 we can pass it to the branch predictor simulation
1119 functions easily. */
1120 Bool inverted;
1121 Addr64 nia, sea;
1122 IRConst* dst;
1123 IRType tyW = hWordTy;
1124 IROp widen = tyW==Ity_I32 ? Iop_1Uto32 : Iop_1Uto64;
1125 IROp opXOR = tyW==Ity_I32 ? Iop_Xor32 : Iop_Xor64;
1126 IRTemp guard1 = newIRTemp(cgs.sbOut->tyenv, Ity_I1);
1127 IRTemp guardW = newIRTemp(cgs.sbOut->tyenv, tyW);
1128 IRTemp guard = newIRTemp(cgs.sbOut->tyenv, tyW);
1129 IRExpr* one = tyW==Ity_I32 ? IRExpr_Const(IRConst_U32(1))
1130 : IRExpr_Const(IRConst_U64(1));
sewardj8badbaa2007-05-08 09:20:25 +00001131
weidendo374a48f2010-09-02 17:06:49 +00001132 /* First we need to figure out whether the side exit got
1133 inverted by the ir optimiser. To do that, figure out
1134 the next (fallthrough) instruction's address and the
1135 side exit address and see if they are the same. */
1136 nia = cia + (Addr64)isize;
1137 if (tyW == Ity_I32)
1138 nia &= 0xFFFFFFFFULL;
sewardj8badbaa2007-05-08 09:20:25 +00001139
weidendo374a48f2010-09-02 17:06:49 +00001140 /* Side exit address */
1141 dst = st->Ist.Exit.dst;
1142 if (tyW == Ity_I32) {
1143 tl_assert(dst->tag == Ico_U32);
1144 sea = (Addr64)(UInt)dst->Ico.U32;
1145 } else {
1146 tl_assert(tyW == Ity_I64);
1147 tl_assert(dst->tag == Ico_U64);
1148 sea = dst->Ico.U64;
1149 }
1150
1151 inverted = nia == sea;
1152
1153 /* Widen the guard expression. */
1154 addStmtToIRSB( cgs.sbOut,
1155 IRStmt_WrTmp( guard1, st->Ist.Exit.guard ));
1156 addStmtToIRSB( cgs.sbOut,
1157 IRStmt_WrTmp( guardW,
1158 IRExpr_Unop(widen,
1159 IRExpr_RdTmp(guard1))) );
1160 /* If the exit is inverted, invert the sense of the guard. */
1161 addStmtToIRSB(
1162 cgs.sbOut,
1163 IRStmt_WrTmp(
1164 guard,
1165 inverted ? IRExpr_Binop(opXOR, IRExpr_RdTmp(guardW), one)
1166 : IRExpr_RdTmp(guardW)
1167 ));
1168 /* And post the event. */
1169 addEvent_Bc( &cgs, curr_inode, IRExpr_RdTmp(guard) );
sewardj8badbaa2007-05-08 09:20:25 +00001170 }
1171
sewardj5155dec2005-10-12 10:09:23 +00001172 /* We may never reach the next statement, so need to flush
1173 all outstanding transactions now. */
1174 flushEvents( &cgs );
1175 break;
sewardj8badbaa2007-05-08 09:20:25 +00001176 }
sewardj5155dec2005-10-12 10:09:23 +00001177
1178 default:
1179 tl_assert(0);
1180 break;
njnb3507ea2005-08-02 23:07:02 +00001181 }
njn6a3009b2005-03-20 00:20:06 +00001182
sewardj5155dec2005-10-12 10:09:23 +00001183 /* Copy the original statement */
sewardj0b9d74a2006-12-24 02:24:11 +00001184 addStmtToIRSB( cgs.sbOut, st );
njn6a3009b2005-03-20 00:20:06 +00001185
sewardj5155dec2005-10-12 10:09:23 +00001186 if (DEBUG_CG) {
1187 ppIRStmt(st);
1188 VG_(printf)("\n");
1189 }
1190 }
1191
sewardj8badbaa2007-05-08 09:20:25 +00001192 /* Deal with branches to unknown destinations. Except ignore ones
1193 which are function returns as we assume the return stack
1194 predictor never mispredicts. */
weidendo374a48f2010-09-02 17:06:49 +00001195 if ((sbIn->jumpkind == Ijk_Boring) || (sbIn->jumpkind == Ijk_Call)) {
sewardj8badbaa2007-05-08 09:20:25 +00001196 if (0) { ppIRExpr( sbIn->next ); VG_(printf)("\n"); }
1197 switch (sbIn->next->tag) {
1198 case Iex_Const:
1199 break; /* boring - branch to known address */
1200 case Iex_RdTmp:
1201 /* looks like an indirect branch (branch to unknown) */
1202 addEvent_Bi( &cgs, curr_inode, sbIn->next );
1203 break;
1204 default:
1205 /* shouldn't happen - if the incoming IR is properly
1206 flattened, should only have tmp and const cases to
1207 consider. */
1208 tl_assert(0);
1209 }
1210 }
1211
sewardj5155dec2005-10-12 10:09:23 +00001212 /* At the end of the bb. Flush outstandings. */
sewardj5155dec2005-10-12 10:09:23 +00001213 flushEvents( &cgs );
1214
sewardj5155dec2005-10-12 10:09:23 +00001215 /* done. stay sane ... */
sewardj0b9d74a2006-12-24 02:24:11 +00001216 tl_assert(cgs.sbInfo_i == cgs.sbInfo->n_instrs);
sewardj5155dec2005-10-12 10:09:23 +00001217
1218 if (DEBUG_CG) {
1219 VG_(printf)( "goto {");
sewardj0b9d74a2006-12-24 02:24:11 +00001220 ppIRJumpKind(sbIn->jumpkind);
sewardj5155dec2005-10-12 10:09:23 +00001221 VG_(printf)( "} ");
sewardj0b9d74a2006-12-24 02:24:11 +00001222 ppIRExpr( sbIn->next );
sewardj5155dec2005-10-12 10:09:23 +00001223 VG_(printf)( "}\n");
1224 }
1225
sewardj0b9d74a2006-12-24 02:24:11 +00001226 return cgs.sbOut;
njn14d01ce2004-11-26 11:30:14 +00001227}
njn4f9c9342002-04-29 16:03:24 +00001228
1229/*------------------------------------------------------------*/
nethercoteb35a8b92004-09-11 16:45:27 +00001230/*--- Cache configuration ---*/
njn4f9c9342002-04-29 16:03:24 +00001231/*------------------------------------------------------------*/
1232
sewardjb5f6f512005-03-10 23:59:00 +00001233#define UNDEFINED_CACHE { -1, -1, -1 }
njn25e49d8e72002-09-23 09:36:25 +00001234
1235static cache_t clo_I1_cache = UNDEFINED_CACHE;
1236static cache_t clo_D1_cache = UNDEFINED_CACHE;
njn2d853a12010-10-06 22:46:31 +00001237static cache_t clo_LL_cache = UNDEFINED_CACHE;
njn25e49d8e72002-09-23 09:36:25 +00001238
njn4f9c9342002-04-29 16:03:24 +00001239/*------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +00001240/*--- cg_fini() and related function ---*/
njn4f9c9342002-04-29 16:03:24 +00001241/*------------------------------------------------------------*/
1242
nethercote9313ac42004-07-06 21:54:20 +00001243// Total reads/writes/misses. Calculated during CC traversal at the end.
1244// All auto-zeroed.
sewardj8badbaa2007-05-08 09:20:25 +00001245static CacheCC Ir_total;
1246static CacheCC Dr_total;
1247static CacheCC Dw_total;
1248static BranchCC Bc_total;
1249static BranchCC Bi_total;
nethercote9313ac42004-07-06 21:54:20 +00001250
nethercote9313ac42004-07-06 21:54:20 +00001251static void fprint_CC_table_and_calc_totals(void)
1252{
njnd3bef4f2005-10-15 17:46:18 +00001253 Int i, fd;
sewardj92645592005-07-23 09:18:34 +00001254 SysRes sres;
njnd3bef4f2005-10-15 17:46:18 +00001255 Char buf[512], *currFile = NULL, *currFn = NULL;
1256 LineCC* lineCC;
njn4f9c9342002-04-29 16:03:24 +00001257
njn7064fb22008-05-29 23:09:52 +00001258 // Setup output filename. Nb: it's important to do this now, ie. as late
1259 // as possible. If we do it at start-up and the program forks and the
1260 // output file format string contains a %p (pid) specifier, both the
1261 // parent and child will incorrectly write to the same file; this
1262 // happened in 3.3.0.
1263 Char* cachegrind_out_file =
1264 VG_(expand_file_name)("--cachegrind-out-file", clo_cachegrind_out_file);
1265
sewardj92645592005-07-23 09:18:34 +00001266 sres = VG_(open)(cachegrind_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
1267 VKI_S_IRUSR|VKI_S_IWUSR);
njncda2f0f2009-05-18 02:12:08 +00001268 if (sr_isError(sres)) {
nethercote9313ac42004-07-06 21:54:20 +00001269 // If the file can't be opened for whatever reason (conflict
1270 // between multiple cachegrinded processes?), give up now.
sewardjb2c985b2009-07-15 14:51:17 +00001271 VG_(umsg)("error: can't open cache simulation output file '%s'\n",
1272 cachegrind_out_file );
1273 VG_(umsg)(" ... so simulation results will be missing.\n");
njn7064fb22008-05-29 23:09:52 +00001274 VG_(free)(cachegrind_out_file);
sewardj0744b6c2002-12-11 00:45:42 +00001275 return;
sewardj92645592005-07-23 09:18:34 +00001276 } else {
njncda2f0f2009-05-18 02:12:08 +00001277 fd = sr_Res(sres);
njn7064fb22008-05-29 23:09:52 +00001278 VG_(free)(cachegrind_out_file);
sewardj0744b6c2002-12-11 00:45:42 +00001279 }
njn4f9c9342002-04-29 16:03:24 +00001280
njn2d853a12010-10-06 22:46:31 +00001281 // "desc:" lines (giving I1/D1/LL cache configuration). The spaces after
nethercote9313ac42004-07-06 21:54:20 +00001282 // the 2nd colon makes cg_annotate's output look nicer.
1283 VG_(sprintf)(buf, "desc: I1 cache: %s\n"
1284 "desc: D1 cache: %s\n"
njn2d853a12010-10-06 22:46:31 +00001285 "desc: LL cache: %s\n",
1286 I1.desc_line, D1.desc_line, LL.desc_line);
njn7cf0bd32002-06-08 13:36:03 +00001287 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njn4f9c9342002-04-29 16:03:24 +00001288
nethercote9313ac42004-07-06 21:54:20 +00001289 // "cmd:" line
njn4f9c9342002-04-29 16:03:24 +00001290 VG_(strcpy)(buf, "cmd:");
1291 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
sewardj45f4e7c2005-09-27 19:20:21 +00001292 if (VG_(args_the_exename)) {
1293 VG_(write)(fd, " ", 1);
1294 VG_(write)(fd, VG_(args_the_exename),
1295 VG_(strlen)( VG_(args_the_exename) ));
1296 }
sewardj14c7cc52007-02-25 15:08:24 +00001297 for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
1298 HChar* arg = * (HChar**) VG_(indexXA)( VG_(args_for_client), i );
1299 if (arg) {
sewardj45f4e7c2005-09-27 19:20:21 +00001300 VG_(write)(fd, " ", 1);
sewardj14c7cc52007-02-25 15:08:24 +00001301 VG_(write)(fd, arg, VG_(strlen)( arg ));
sewardj45f4e7c2005-09-27 19:20:21 +00001302 }
njn4f9c9342002-04-29 16:03:24 +00001303 }
nethercote9313ac42004-07-06 21:54:20 +00001304 // "events:" line
sewardj8badbaa2007-05-08 09:20:25 +00001305 if (clo_cache_sim && clo_branch_sim) {
njn2d853a12010-10-06 22:46:31 +00001306 VG_(sprintf)(buf, "\nevents: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw "
sewardj8badbaa2007-05-08 09:20:25 +00001307 "Bc Bcm Bi Bim\n");
1308 }
1309 else if (clo_cache_sim && !clo_branch_sim) {
njn2d853a12010-10-06 22:46:31 +00001310 VG_(sprintf)(buf, "\nevents: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw "
sewardj8badbaa2007-05-08 09:20:25 +00001311 "\n");
1312 }
1313 else if (!clo_cache_sim && clo_branch_sim) {
1314 VG_(sprintf)(buf, "\nevents: Ir "
1315 "Bc Bcm Bi Bim\n");
1316 }
njne90711c2010-09-27 01:04:20 +00001317 else {
1318 VG_(sprintf)(buf, "\nevents: Ir\n");
1319 }
sewardj8badbaa2007-05-08 09:20:25 +00001320
njn4f9c9342002-04-29 16:03:24 +00001321 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1322
njnd3bef4f2005-10-15 17:46:18 +00001323 // Traverse every lineCC
njne2a9ad32007-09-17 05:30:48 +00001324 VG_(OSetGen_ResetIter)(CC_table);
1325 while ( (lineCC = VG_(OSetGen_Next)(CC_table)) ) {
njn4311fe62005-12-08 23:18:50 +00001326 Bool just_hit_a_new_file = False;
njnd3bef4f2005-10-15 17:46:18 +00001327 // If we've hit a new file, print a "fl=" line. Note that because
1328 // each string is stored exactly once in the string table, we can use
1329 // pointer comparison rather than strcmp() to test for equality, which
1330 // is good because most of the time the comparisons are equal and so
njn4311fe62005-12-08 23:18:50 +00001331 // the whole strings would have to be checked.
njnd3bef4f2005-10-15 17:46:18 +00001332 if ( lineCC->loc.file != currFile ) {
1333 currFile = lineCC->loc.file;
1334 VG_(sprintf)(buf, "fl=%s\n", currFile);
njn4f9c9342002-04-29 16:03:24 +00001335 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njnd3bef4f2005-10-15 17:46:18 +00001336 distinct_files++;
njn4311fe62005-12-08 23:18:50 +00001337 just_hit_a_new_file = True;
njn4f9c9342002-04-29 16:03:24 +00001338 }
njn4311fe62005-12-08 23:18:50 +00001339 // If we've hit a new function, print a "fn=" line. We know to do
1340 // this when the function name changes, and also every time we hit a
1341 // new file (in which case the new function name might be the same as
1342 // in the old file, hence the just_hit_a_new_file test).
1343 if ( just_hit_a_new_file || lineCC->loc.fn != currFn ) {
njnd3bef4f2005-10-15 17:46:18 +00001344 currFn = lineCC->loc.fn;
1345 VG_(sprintf)(buf, "fn=%s\n", currFn);
1346 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1347 distinct_fns++;
1348 }
1349
1350 // Print the LineCC
sewardj8badbaa2007-05-08 09:20:25 +00001351 if (clo_cache_sim && clo_branch_sim) {
1352 VG_(sprintf)(buf, "%u %llu %llu %llu"
1353 " %llu %llu %llu"
1354 " %llu %llu %llu"
1355 " %llu %llu %llu %llu\n",
1356 lineCC->loc.line,
njn2d853a12010-10-06 22:46:31 +00001357 lineCC->Ir.a, lineCC->Ir.m1, lineCC->Ir.mL,
1358 lineCC->Dr.a, lineCC->Dr.m1, lineCC->Dr.mL,
1359 lineCC->Dw.a, lineCC->Dw.m1, lineCC->Dw.mL,
sewardj8badbaa2007-05-08 09:20:25 +00001360 lineCC->Bc.b, lineCC->Bc.mp,
1361 lineCC->Bi.b, lineCC->Bi.mp);
1362 }
1363 else if (clo_cache_sim && !clo_branch_sim) {
1364 VG_(sprintf)(buf, "%u %llu %llu %llu"
1365 " %llu %llu %llu"
1366 " %llu %llu %llu\n",
1367 lineCC->loc.line,
njn2d853a12010-10-06 22:46:31 +00001368 lineCC->Ir.a, lineCC->Ir.m1, lineCC->Ir.mL,
1369 lineCC->Dr.a, lineCC->Dr.m1, lineCC->Dr.mL,
1370 lineCC->Dw.a, lineCC->Dw.m1, lineCC->Dw.mL);
sewardj8badbaa2007-05-08 09:20:25 +00001371 }
1372 else if (!clo_cache_sim && clo_branch_sim) {
1373 VG_(sprintf)(buf, "%u %llu"
1374 " %llu %llu %llu %llu\n",
1375 lineCC->loc.line,
1376 lineCC->Ir.a,
1377 lineCC->Bc.b, lineCC->Bc.mp,
1378 lineCC->Bi.b, lineCC->Bi.mp);
1379 }
njne90711c2010-09-27 01:04:20 +00001380 else {
1381 VG_(sprintf)(buf, "%u %llu\n",
1382 lineCC->loc.line,
1383 lineCC->Ir.a);
1384 }
sewardj8badbaa2007-05-08 09:20:25 +00001385
njnd3bef4f2005-10-15 17:46:18 +00001386 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1387
1388 // Update summary stats
1389 Ir_total.a += lineCC->Ir.a;
1390 Ir_total.m1 += lineCC->Ir.m1;
njn2d853a12010-10-06 22:46:31 +00001391 Ir_total.mL += lineCC->Ir.mL;
njnd3bef4f2005-10-15 17:46:18 +00001392 Dr_total.a += lineCC->Dr.a;
1393 Dr_total.m1 += lineCC->Dr.m1;
njn2d853a12010-10-06 22:46:31 +00001394 Dr_total.mL += lineCC->Dr.mL;
njnd3bef4f2005-10-15 17:46:18 +00001395 Dw_total.a += lineCC->Dw.a;
1396 Dw_total.m1 += lineCC->Dw.m1;
njn2d853a12010-10-06 22:46:31 +00001397 Dw_total.mL += lineCC->Dw.mL;
sewardj8badbaa2007-05-08 09:20:25 +00001398 Bc_total.b += lineCC->Bc.b;
1399 Bc_total.mp += lineCC->Bc.mp;
1400 Bi_total.b += lineCC->Bi.b;
1401 Bi_total.mp += lineCC->Bi.mp;
njnd3bef4f2005-10-15 17:46:18 +00001402
1403 distinct_lines++;
njn4f9c9342002-04-29 16:03:24 +00001404 }
1405
nethercote9313ac42004-07-06 21:54:20 +00001406 // Summary stats must come after rest of table, since we calculate them
sewardj8badbaa2007-05-08 09:20:25 +00001407 // during traversal. */
1408 if (clo_cache_sim && clo_branch_sim) {
1409 VG_(sprintf)(buf, "summary:"
1410 " %llu %llu %llu"
1411 " %llu %llu %llu"
1412 " %llu %llu %llu"
1413 " %llu %llu %llu %llu\n",
njn2d853a12010-10-06 22:46:31 +00001414 Ir_total.a, Ir_total.m1, Ir_total.mL,
1415 Dr_total.a, Dr_total.m1, Dr_total.mL,
1416 Dw_total.a, Dw_total.m1, Dw_total.mL,
sewardj8badbaa2007-05-08 09:20:25 +00001417 Bc_total.b, Bc_total.mp,
1418 Bi_total.b, Bi_total.mp);
1419 }
1420 else if (clo_cache_sim && !clo_branch_sim) {
1421 VG_(sprintf)(buf, "summary:"
1422 " %llu %llu %llu"
1423 " %llu %llu %llu"
1424 " %llu %llu %llu\n",
njn2d853a12010-10-06 22:46:31 +00001425 Ir_total.a, Ir_total.m1, Ir_total.mL,
1426 Dr_total.a, Dr_total.m1, Dr_total.mL,
1427 Dw_total.a, Dw_total.m1, Dw_total.mL);
sewardj8badbaa2007-05-08 09:20:25 +00001428 }
1429 else if (!clo_cache_sim && clo_branch_sim) {
1430 VG_(sprintf)(buf, "summary:"
1431 " %llu"
1432 " %llu %llu %llu %llu\n",
1433 Ir_total.a,
1434 Bc_total.b, Bc_total.mp,
1435 Bi_total.b, Bi_total.mp);
1436 }
njne90711c2010-09-27 01:04:20 +00001437 else {
1438 VG_(sprintf)(buf, "summary:"
1439 " %llu\n",
1440 Ir_total.a);
1441 }
sewardj8badbaa2007-05-08 09:20:25 +00001442
njn4f9c9342002-04-29 16:03:24 +00001443 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1444 VG_(close)(fd);
1445}
1446
njn607adfc2003-09-30 14:15:44 +00001447static UInt ULong_width(ULong n)
njn4f9c9342002-04-29 16:03:24 +00001448{
njn607adfc2003-09-30 14:15:44 +00001449 UInt w = 0;
1450 while (n > 0) {
1451 n = n / 10;
1452 w++;
njn4f9c9342002-04-29 16:03:24 +00001453 }
sewardj46c59b12005-11-01 02:20:19 +00001454 if (w == 0) w = 1;
njn607adfc2003-09-30 14:15:44 +00001455 return w + (w-1)/3; // add space for commas
njn4f9c9342002-04-29 16:03:24 +00001456}
1457
njn51d827b2005-05-09 01:02:08 +00001458static void cg_fini(Int exitcode)
njn4f9c9342002-04-29 16:03:24 +00001459{
njn1baf7db2006-04-18 22:34:48 +00001460 static Char buf1[128], buf2[128], buf3[128], buf4[123], fmt[128];
njn607adfc2003-09-30 14:15:44 +00001461
sewardj8badbaa2007-05-08 09:20:25 +00001462 CacheCC D_total;
1463 BranchCC B_total;
njn2d853a12010-10-06 22:46:31 +00001464 ULong LL_total_m, LL_total_mr, LL_total_mw,
1465 LL_total, LL_total_r, LL_total_w;
njn4c245e52009-03-15 23:25:38 +00001466 Int l1, l2, l3;
njn4f9c9342002-04-29 16:03:24 +00001467
nethercote9313ac42004-07-06 21:54:20 +00001468 fprint_CC_table_and_calc_totals();
njn4f9c9342002-04-29 16:03:24 +00001469
njn7cf0bd32002-06-08 13:36:03 +00001470 if (VG_(clo_verbosity) == 0)
1471 return;
1472
njnf76d27a2009-05-28 01:53:07 +00001473 // Nb: this isn't called "MAX" because that overshadows a global on Darwin.
1474 #define CG_MAX(a, b) ((a) >= (b) ? (a) : (b))
njn4c245e52009-03-15 23:25:38 +00001475
njn4f9c9342002-04-29 16:03:24 +00001476 /* I cache results. Use the I_refs value to determine the first column
1477 * width. */
njn607adfc2003-09-30 14:15:44 +00001478 l1 = ULong_width(Ir_total.a);
njnf76d27a2009-05-28 01:53:07 +00001479 l2 = ULong_width(CG_MAX(Dr_total.a, Bc_total.b));
1480 l3 = ULong_width(CG_MAX(Dw_total.a, Bi_total.b));
njn4f9c9342002-04-29 16:03:24 +00001481
njn607adfc2003-09-30 14:15:44 +00001482 /* Make format string, getting width right for numbers */
sewardjb2c985b2009-07-15 14:51:17 +00001483 VG_(sprintf)(fmt, "%%s %%,%dllu\n", l1);
njnd3bef4f2005-10-15 17:46:18 +00001484
sewardj8badbaa2007-05-08 09:20:25 +00001485 /* Always print this */
sewardjb2c985b2009-07-15 14:51:17 +00001486 VG_(umsg)(fmt, "I refs: ", Ir_total.a);
njn4f9c9342002-04-29 16:03:24 +00001487
sewardj8badbaa2007-05-08 09:20:25 +00001488 /* If cache profiling is enabled, show D access numbers and all
1489 miss numbers */
1490 if (clo_cache_sim) {
sewardjb2c985b2009-07-15 14:51:17 +00001491 VG_(umsg)(fmt, "I1 misses: ", Ir_total.m1);
njn2d853a12010-10-06 22:46:31 +00001492 VG_(umsg)(fmt, "LLi misses: ", Ir_total.mL);
njn4f9c9342002-04-29 16:03:24 +00001493
sewardj8badbaa2007-05-08 09:20:25 +00001494 if (0 == Ir_total.a) Ir_total.a = 1;
1495 VG_(percentify)(Ir_total.m1, Ir_total.a, 2, l1+1, buf1);
sewardjb2c985b2009-07-15 14:51:17 +00001496 VG_(umsg)("I1 miss rate: %s\n", buf1);
njn4f9c9342002-04-29 16:03:24 +00001497
njn2d853a12010-10-06 22:46:31 +00001498 VG_(percentify)(Ir_total.mL, Ir_total.a, 2, l1+1, buf1);
1499 VG_(umsg)("LLi miss rate: %s\n", buf1);
sewardjb2c985b2009-07-15 14:51:17 +00001500 VG_(umsg)("\n");
njnd3bef4f2005-10-15 17:46:18 +00001501
sewardj8badbaa2007-05-08 09:20:25 +00001502 /* D cache results. Use the D_refs.rd and D_refs.wr values to
1503 * determine the width of columns 2 & 3. */
1504 D_total.a = Dr_total.a + Dw_total.a;
1505 D_total.m1 = Dr_total.m1 + Dw_total.m1;
njn2d853a12010-10-06 22:46:31 +00001506 D_total.mL = Dr_total.mL + Dw_total.mL;
njn4f9c9342002-04-29 16:03:24 +00001507
sewardj8badbaa2007-05-08 09:20:25 +00001508 /* Make format string, getting width right for numbers */
sewardjb2c985b2009-07-15 14:51:17 +00001509 VG_(sprintf)(fmt, "%%s %%,%dllu (%%,%dllu rd + %%,%dllu wr)\n",
1510 l1, l2, l3);
njn4f9c9342002-04-29 16:03:24 +00001511
sewardjb2c985b2009-07-15 14:51:17 +00001512 VG_(umsg)(fmt, "D refs: ",
1513 D_total.a, Dr_total.a, Dw_total.a);
1514 VG_(umsg)(fmt, "D1 misses: ",
1515 D_total.m1, Dr_total.m1, Dw_total.m1);
njn2d853a12010-10-06 22:46:31 +00001516 VG_(umsg)(fmt, "LLd misses: ",
1517 D_total.mL, Dr_total.mL, Dw_total.mL);
njnd3bef4f2005-10-15 17:46:18 +00001518
sewardj8badbaa2007-05-08 09:20:25 +00001519 if (0 == D_total.a) D_total.a = 1;
1520 if (0 == Dr_total.a) Dr_total.a = 1;
1521 if (0 == Dw_total.a) Dw_total.a = 1;
1522 VG_(percentify)( D_total.m1, D_total.a, 1, l1+1, buf1);
1523 VG_(percentify)(Dr_total.m1, Dr_total.a, 1, l2+1, buf2);
1524 VG_(percentify)(Dw_total.m1, Dw_total.a, 1, l3+1, buf3);
sewardjb2c985b2009-07-15 14:51:17 +00001525 VG_(umsg)("D1 miss rate: %s (%s + %s )\n", buf1, buf2,buf3);
njn4f9c9342002-04-29 16:03:24 +00001526
njn2d853a12010-10-06 22:46:31 +00001527 VG_(percentify)( D_total.mL, D_total.a, 1, l1+1, buf1);
1528 VG_(percentify)(Dr_total.mL, Dr_total.a, 1, l2+1, buf2);
1529 VG_(percentify)(Dw_total.mL, Dw_total.a, 1, l3+1, buf3);
1530 VG_(umsg)("LLd miss rate: %s (%s + %s )\n", buf1, buf2,buf3);
sewardjb2c985b2009-07-15 14:51:17 +00001531 VG_(umsg)("\n");
njn1d021fa2002-05-02 13:56:34 +00001532
njn2d853a12010-10-06 22:46:31 +00001533 /* LL overall results */
njn1d021fa2002-05-02 13:56:34 +00001534
njn2d853a12010-10-06 22:46:31 +00001535 LL_total = Dr_total.m1 + Dw_total.m1 + Ir_total.m1;
1536 LL_total_r = Dr_total.m1 + Ir_total.m1;
1537 LL_total_w = Dw_total.m1;
1538 VG_(umsg)(fmt, "LL refs: ",
1539 LL_total, LL_total_r, LL_total_w);
njn4f9c9342002-04-29 16:03:24 +00001540
njn2d853a12010-10-06 22:46:31 +00001541 LL_total_m = Dr_total.mL + Dw_total.mL + Ir_total.mL;
1542 LL_total_mr = Dr_total.mL + Ir_total.mL;
1543 LL_total_mw = Dw_total.mL;
1544 VG_(umsg)(fmt, "LL misses: ",
1545 LL_total_m, LL_total_mr, LL_total_mw);
njnd3bef4f2005-10-15 17:46:18 +00001546
njn2d853a12010-10-06 22:46:31 +00001547 VG_(percentify)(LL_total_m, (Ir_total.a + D_total.a), 1, l1+1, buf1);
1548 VG_(percentify)(LL_total_mr, (Ir_total.a + Dr_total.a), 1, l2+1, buf2);
1549 VG_(percentify)(LL_total_mw, Dw_total.a, 1, l3+1, buf3);
1550 VG_(umsg)("LL miss rate: %s (%s + %s )\n", buf1, buf2,buf3);
sewardj8badbaa2007-05-08 09:20:25 +00001551 }
1552
1553 /* If branch profiling is enabled, show branch overall results. */
1554 if (clo_branch_sim) {
1555 /* Make format string, getting width right for numbers */
sewardjb2c985b2009-07-15 14:51:17 +00001556 VG_(sprintf)(fmt, "%%s %%,%dllu (%%,%dllu cond + %%,%dllu ind)\n",
1557 l1, l2, l3);
sewardj8badbaa2007-05-08 09:20:25 +00001558
1559 if (0 == Bc_total.b) Bc_total.b = 1;
1560 if (0 == Bi_total.b) Bi_total.b = 1;
1561 B_total.b = Bc_total.b + Bi_total.b;
1562 B_total.mp = Bc_total.mp + Bi_total.mp;
1563
sewardjb2c985b2009-07-15 14:51:17 +00001564 VG_(umsg)("\n");
1565 VG_(umsg)(fmt, "Branches: ",
1566 B_total.b, Bc_total.b, Bi_total.b);
sewardj8badbaa2007-05-08 09:20:25 +00001567
sewardjb2c985b2009-07-15 14:51:17 +00001568 VG_(umsg)(fmt, "Mispredicts: ",
1569 B_total.mp, Bc_total.mp, Bi_total.mp);
sewardj8badbaa2007-05-08 09:20:25 +00001570
1571 VG_(percentify)(B_total.mp, B_total.b, 1, l1+1, buf1);
1572 VG_(percentify)(Bc_total.mp, Bc_total.b, 1, l2+1, buf2);
1573 VG_(percentify)(Bi_total.mp, Bi_total.b, 1, l3+1, buf3);
1574
sewardjb2c985b2009-07-15 14:51:17 +00001575 VG_(umsg)("Mispred rate: %s (%s + %s )\n", buf1, buf2,buf3);
sewardj8badbaa2007-05-08 09:20:25 +00001576 }
njn4f9c9342002-04-29 16:03:24 +00001577
nethercote9313ac42004-07-06 21:54:20 +00001578 // Various stats
sewardj2d9e8742009-08-07 15:46:56 +00001579 if (VG_(clo_stats)) {
njn1baf7db2006-04-18 22:34:48 +00001580 Int debug_lookups = full_debugs + fn_debugs +
1581 file_line_debugs + no_debugs;
njnd3bef4f2005-10-15 17:46:18 +00001582
sewardjb2c985b2009-07-15 14:51:17 +00001583 VG_(dmsg)("\n");
1584 VG_(dmsg)("cachegrind: distinct files: %d\n", distinct_files);
1585 VG_(dmsg)("cachegrind: distinct fns: %d\n", distinct_fns);
1586 VG_(dmsg)("cachegrind: distinct lines: %d\n", distinct_lines);
1587 VG_(dmsg)("cachegrind: distinct instrs:%d\n", distinct_instrs);
1588 VG_(dmsg)("cachegrind: debug lookups : %d\n", debug_lookups);
njn1baf7db2006-04-18 22:34:48 +00001589
1590 VG_(percentify)(full_debugs, debug_lookups, 1, 6, buf1);
1591 VG_(percentify)(file_line_debugs, debug_lookups, 1, 6, buf2);
1592 VG_(percentify)(fn_debugs, debug_lookups, 1, 6, buf3);
1593 VG_(percentify)(no_debugs, debug_lookups, 1, 6, buf4);
sewardjb2c985b2009-07-15 14:51:17 +00001594 VG_(dmsg)("cachegrind: with full info:%s (%d)\n",
1595 buf1, full_debugs);
1596 VG_(dmsg)("cachegrind: with file/line info:%s (%d)\n",
1597 buf2, file_line_debugs);
1598 VG_(dmsg)("cachegrind: with fn name info:%s (%d)\n",
1599 buf3, fn_debugs);
1600 VG_(dmsg)("cachegrind: with zero info:%s (%d)\n",
1601 buf4, no_debugs);
njn1baf7db2006-04-18 22:34:48 +00001602
sewardjb2c985b2009-07-15 14:51:17 +00001603 VG_(dmsg)("cachegrind: string table size: %lu\n",
1604 VG_(OSetGen_Size)(stringTable));
1605 VG_(dmsg)("cachegrind: CC table size: %lu\n",
1606 VG_(OSetGen_Size)(CC_table));
1607 VG_(dmsg)("cachegrind: InstrInfo table size: %lu\n",
1608 VG_(OSetGen_Size)(instrInfoTable));
njn4f9c9342002-04-29 16:03:24 +00001609 }
njn4f9c9342002-04-29 16:03:24 +00001610}
1611
nethercote9313ac42004-07-06 21:54:20 +00001612/*--------------------------------------------------------------------*/
1613/*--- Discarding BB info ---*/
1614/*--------------------------------------------------------------------*/
sewardj18d75132002-05-16 11:06:21 +00001615
sewardja3a29a52005-10-12 16:16:03 +00001616// Called when a translation is removed from the translation cache for
1617// any reason at all: to free up space, because the guest code was
1618// unmapped or modified, or for any arbitrary reason.
sewardj4ba057c2005-10-18 12:04:18 +00001619static
sewardj0b9d74a2006-12-24 02:24:11 +00001620void cg_discard_superblock_info ( Addr64 orig_addr64, VexGuestExtents vge )
sewardj18d75132002-05-16 11:06:21 +00001621{
sewardj0b9d74a2006-12-24 02:24:11 +00001622 SB_info* sbInfo;
sewardj3a384b32006-01-22 01:12:51 +00001623 Addr orig_addr = (Addr)vge.base[0];
njn4294fd42002-06-05 14:41:10 +00001624
sewardj5155dec2005-10-12 10:09:23 +00001625 tl_assert(vge.n_used > 0);
1626
1627 if (DEBUG_CG)
sewardj4ba057c2005-10-18 12:04:18 +00001628 VG_(printf)( "discard_basic_block_info: %p, %p, %llu\n",
1629 (void*)(Addr)orig_addr,
sewardj5155dec2005-10-12 10:09:23 +00001630 (void*)(Addr)vge.base[0], (ULong)vge.len[0]);
njn4294fd42002-06-05 14:41:10 +00001631
sewardj4ba057c2005-10-18 12:04:18 +00001632 // Get BB info, remove from table, free BB info. Simple! Note that we
1633 // use orig_addr, not the first instruction address in vge.
njne2a9ad32007-09-17 05:30:48 +00001634 sbInfo = VG_(OSetGen_Remove)(instrInfoTable, &orig_addr);
sewardj0b9d74a2006-12-24 02:24:11 +00001635 tl_assert(NULL != sbInfo);
njne2a9ad32007-09-17 05:30:48 +00001636 VG_(OSetGen_FreeNode)(instrInfoTable, sbInfo);
sewardj18d75132002-05-16 11:06:21 +00001637}
1638
1639/*--------------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001640/*--- Command line processing ---*/
1641/*--------------------------------------------------------------------*/
1642
njn51d827b2005-05-09 01:02:08 +00001643static Bool cg_process_cmd_line_option(Char* arg)
njn25e49d8e72002-09-23 09:36:25 +00001644{
weidendo23642272011-09-06 19:08:31 +00001645 if (VG_(str_clo_cache_opt)(arg,
1646 &clo_I1_cache,
1647 &clo_D1_cache,
1648 &clo_LL_cache)) {}
njn83df0b62009-02-25 01:01:05 +00001649
1650 else if VG_STR_CLO( arg, "--cachegrind-out-file", clo_cachegrind_out_file) {}
1651 else if VG_BOOL_CLO(arg, "--cache-sim", clo_cache_sim) {}
1652 else if VG_BOOL_CLO(arg, "--branch-sim", clo_branch_sim) {}
njn25e49d8e72002-09-23 09:36:25 +00001653 else
1654 return False;
1655
1656 return True;
1657}
1658
njn51d827b2005-05-09 01:02:08 +00001659static void cg_print_usage(void)
njn25e49d8e72002-09-23 09:36:25 +00001660{
weidendo23642272011-09-06 19:08:31 +00001661 VG_(print_cache_clo_opts)();
njn3e884182003-04-15 13:03:23 +00001662 VG_(printf)(
sewardj8badbaa2007-05-08 09:20:25 +00001663" --cache-sim=yes|no [yes] collect cache stats?\n"
1664" --branch-sim=yes|no [no] collect branch prediction stats?\n"
njn374a36d2007-11-23 01:41:32 +00001665" --cachegrind-out-file=<file> output file name [cachegrind.out.%%p]\n"
njn3e884182003-04-15 13:03:23 +00001666 );
1667}
1668
njn51d827b2005-05-09 01:02:08 +00001669static void cg_print_debug_usage(void)
njn3e884182003-04-15 13:03:23 +00001670{
1671 VG_(printf)(
1672" (none)\n"
1673 );
njn25e49d8e72002-09-23 09:36:25 +00001674}
1675
1676/*--------------------------------------------------------------------*/
1677/*--- Setup ---*/
1678/*--------------------------------------------------------------------*/
1679
sewardje1216cb2007-02-07 19:55:30 +00001680static void cg_post_clo_init(void); /* just below */
1681
njn51d827b2005-05-09 01:02:08 +00001682static void cg_pre_clo_init(void)
1683{
njn51d827b2005-05-09 01:02:08 +00001684 VG_(details_name) ("Cachegrind");
1685 VG_(details_version) (NULL);
sewardj8badbaa2007-05-08 09:20:25 +00001686 VG_(details_description) ("a cache and branch-prediction profiler");
njn51d827b2005-05-09 01:02:08 +00001687 VG_(details_copyright_author)(
sewardj9eecbbb2010-05-03 21:37:12 +00001688 "Copyright (C) 2002-2010, and GNU GPL'd, by Nicholas Nethercote et al.");
njn51d827b2005-05-09 01:02:08 +00001689 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardje8089302006-10-17 02:15:17 +00001690 VG_(details_avg_translation_sizeB) ( 500 );
njn51d827b2005-05-09 01:02:08 +00001691
1692 VG_(basic_tool_funcs) (cg_post_clo_init,
1693 cg_instrument,
1694 cg_fini);
1695
sewardj0b9d74a2006-12-24 02:24:11 +00001696 VG_(needs_superblock_discards)(cg_discard_superblock_info);
njn51d827b2005-05-09 01:02:08 +00001697 VG_(needs_command_line_options)(cg_process_cmd_line_option,
1698 cg_print_usage,
1699 cg_print_debug_usage);
sewardje1216cb2007-02-07 19:55:30 +00001700}
1701
1702static void cg_post_clo_init(void)
1703{
njn2d853a12010-10-06 22:46:31 +00001704 cache_t I1c, D1c, LLc;
njn51d827b2005-05-09 01:02:08 +00001705
njne2a9ad32007-09-17 05:30:48 +00001706 CC_table =
1707 VG_(OSetGen_Create)(offsetof(LineCC, loc),
1708 cmp_CodeLoc_LineCC,
sewardj9c606bd2008-09-18 18:12:50 +00001709 VG_(malloc), "cg.main.cpci.1",
1710 VG_(free));
njne2a9ad32007-09-17 05:30:48 +00001711 instrInfoTable =
1712 VG_(OSetGen_Create)(/*keyOff*/0,
1713 NULL,
sewardj9c606bd2008-09-18 18:12:50 +00001714 VG_(malloc), "cg.main.cpci.2",
1715 VG_(free));
njne2a9ad32007-09-17 05:30:48 +00001716 stringTable =
1717 VG_(OSetGen_Create)(/*keyOff*/0,
1718 stringCmp,
sewardj9c606bd2008-09-18 18:12:50 +00001719 VG_(malloc), "cg.main.cpci.3",
1720 VG_(free));
sewardje1216cb2007-02-07 19:55:30 +00001721
weidendo23642272011-09-06 19:08:31 +00001722 VG_(post_clo_init_configure_caches)(&I1c, &D1c, &LLc,
1723 &clo_I1_cache,
1724 &clo_D1_cache,
1725 &clo_LL_cache);
sewardje1216cb2007-02-07 19:55:30 +00001726
1727 cachesim_I1_initcache(I1c);
1728 cachesim_D1_initcache(D1c);
njn2d853a12010-10-06 22:46:31 +00001729 cachesim_LL_initcache(LLc);
njn51d827b2005-05-09 01:02:08 +00001730}
1731
sewardj45f4e7c2005-09-27 19:20:21 +00001732VG_DETERMINE_INTERFACE_VERSION(cg_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00001733
njn25e49d8e72002-09-23 09:36:25 +00001734/*--------------------------------------------------------------------*/
njnf69f9452005-07-03 17:53:11 +00001735/*--- end ---*/
sewardj18d75132002-05-16 11:06:21 +00001736/*--------------------------------------------------------------------*/
njnd3bef4f2005-10-15 17:46:18 +00001737