blob: d8627fb860e97edb19e5a155bc183bc460ff3f6c [file] [log] [blame]
sewardj07133bf2002-06-13 10:25:56 +00001
njn4f9c9342002-04-29 16:03:24 +00002/*--------------------------------------------------------------------*/
njn101e5722005-04-21 02:37:54 +00003/*--- Cachegrind: everything but the simulation itself. ---*/
njn25cac76cb2002-09-23 11:21:57 +00004/*--- cg_main.c ---*/
njn4f9c9342002-04-29 16:03:24 +00005/*--------------------------------------------------------------------*/
6
7/*
nethercote137bc552003-11-14 17:47:54 +00008 This file is part of Cachegrind, a Valgrind tool for cache
njnc9539842002-10-02 13:26:35 +00009 profiling programs.
njn4f9c9342002-04-29 16:03:24 +000010
sewardj9ebd6e02007-01-08 06:01:59 +000011 Copyright (C) 2002-2007 Nicholas Nethercote
njn2bc10122005-05-08 02:10:27 +000012 njn@valgrind.org
njn4f9c9342002-04-29 16:03:24 +000013
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
njn25e49d8e72002-09-23 09:36:25 +000029 The GNU General Public License is contained in the file COPYING.
njn4f9c9342002-04-29 16:03:24 +000030*/
31
njnc7561b92005-06-19 01:24:32 +000032#include "pub_tool_basics.h"
sewardj4cfea4f2006-10-14 19:26:10 +000033#include "pub_tool_vki.h"
njnea27e462005-05-31 02:38:09 +000034#include "pub_tool_debuginfo.h"
njn97405b22005-06-02 03:39:33 +000035#include "pub_tool_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000036#include "pub_tool_libcassert.h"
njneb8896b2005-06-04 20:03:55 +000037#include "pub_tool_libcfile.h"
njn36a20fa2005-06-03 03:08:39 +000038#include "pub_tool_libcprint.h"
njnf39e9a32005-06-12 02:43:17 +000039#include "pub_tool_libcproc.h"
njnf536bbb2005-06-13 04:21:38 +000040#include "pub_tool_machine.h"
njn717cde52005-05-10 02:47:21 +000041#include "pub_tool_mallocfree.h"
njn20242342005-05-16 23:31:24 +000042#include "pub_tool_options.h"
njnd3bef4f2005-10-15 17:46:18 +000043#include "pub_tool_oset.h"
njn43b9a8a2005-05-10 04:37:01 +000044#include "pub_tool_tooliface.h"
sewardj14c7cc52007-02-25 15:08:24 +000045#include "pub_tool_xarray.h"
sewardj45f4e7c2005-09-27 19:20:21 +000046#include "pub_tool_clientstate.h"
sewardj5bb86822005-12-23 12:47:42 +000047#include "pub_tool_machine.h" // VG_(fnptr_to_fnentry)
njn25e49d8e72002-09-23 09:36:25 +000048
nethercoteb35a8b92004-09-11 16:45:27 +000049#include "cg_arch.h"
nethercote27fc1da2004-01-04 16:56:57 +000050#include "cg_sim.c"
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
68static Bool clo_cache_sim = True; /* do cache simulation? */
69static Bool clo_branch_sim = False; /* do branch simulation? */
70
71/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +000072/*--- Types and Data Structures ---*/
njn4f9c9342002-04-29 16:03:24 +000073/*------------------------------------------------------------*/
74
sewardj8badbaa2007-05-08 09:20:25 +000075typedef
76 struct {
77 ULong a; /* total # memory accesses of this kind */
78 ULong m1; /* misses in the first level cache */
79 ULong m2; /* misses in the second level cache */
80 }
81 CacheCC;
82
83typedef
84 struct {
85 ULong b; /* total # branches of this kind */
86 ULong mp; /* number of branches mispredicted */
87 }
88 BranchCC;
njn4f9c9342002-04-29 16:03:24 +000089
nethercote9313ac42004-07-06 21:54:20 +000090//------------------------------------------------------------
91// Primary data structure #1: CC table
92// - Holds the per-source-line hit/miss stats, grouped by file/function/line.
njnd3bef4f2005-10-15 17:46:18 +000093// - an ordered set of CCs. CC indexing done by file/function/line (as
94// determined from the instrAddr).
nethercote9313ac42004-07-06 21:54:20 +000095// - Traversed for dumping stats at end in file/func/line hierarchy.
njn4f9c9342002-04-29 16:03:24 +000096
njnd3bef4f2005-10-15 17:46:18 +000097typedef struct {
98 Char* file;
99 Char* fn;
100 Int line;
101}
102CodeLoc;
njn4f9c9342002-04-29 16:03:24 +0000103
sewardj8badbaa2007-05-08 09:20:25 +0000104typedef struct {
105 CodeLoc loc; /* Source location that these counts pertain to */
106 CacheCC Ir; /* Insn read counts */
107 CacheCC Dr; /* Data read counts */
108 CacheCC Dw; /* Data write/modify counts */
109 BranchCC Bc; /* Conditional branch counts */
110 BranchCC Bi; /* Indirect branch counts */
111} LineCC;
njn4f9c9342002-04-29 16:03:24 +0000112
njnd3bef4f2005-10-15 17:46:18 +0000113// First compare file, then fn, then line.
njnafa12262005-12-24 03:10:56 +0000114static Word cmp_CodeLoc_LineCC(void *vloc, void *vcc)
njnd3bef4f2005-10-15 17:46:18 +0000115{
njnafa12262005-12-24 03:10:56 +0000116 Word res;
njnd3bef4f2005-10-15 17:46:18 +0000117 CodeLoc* a = (CodeLoc*)vloc;
118 CodeLoc* b = &(((LineCC*)vcc)->loc);
njn4f9c9342002-04-29 16:03:24 +0000119
njnd3bef4f2005-10-15 17:46:18 +0000120 res = VG_(strcmp)(a->file, b->file);
121 if (0 != res)
122 return res;
njn4f9c9342002-04-29 16:03:24 +0000123
njnd3bef4f2005-10-15 17:46:18 +0000124 res = VG_(strcmp)(a->fn, b->fn);
125 if (0 != res)
126 return res;
127
128 return a->line - b->line;
129}
130
131static OSet* CC_table;
njn4f9c9342002-04-29 16:03:24 +0000132
nethercote9313ac42004-07-06 21:54:20 +0000133//------------------------------------------------------------
njnd3bef4f2005-10-15 17:46:18 +0000134// Primary data structure #2: InstrInfo table
nethercote9313ac42004-07-06 21:54:20 +0000135// - Holds the cached info about each instr that is used for simulation.
sewardj0b9d74a2006-12-24 02:24:11 +0000136// - table(SB_start_addr, list(InstrInfo))
137// - For each SB, each InstrInfo in the list holds info about the
njnd3bef4f2005-10-15 17:46:18 +0000138// instruction (instrLen, instrAddr, etc), plus a pointer to its line
nethercote9313ac42004-07-06 21:54:20 +0000139// CC. This node is what's passed to the simulation function.
sewardj0b9d74a2006-12-24 02:24:11 +0000140// - When SBs are discarded the relevant list(instr_details) is freed.
nethercote9313ac42004-07-06 21:54:20 +0000141
njnd3bef4f2005-10-15 17:46:18 +0000142typedef struct _InstrInfo InstrInfo;
143struct _InstrInfo {
nethercoteca1f2dc2004-07-21 08:49:02 +0000144 Addr instr_addr;
njn6a3009b2005-03-20 00:20:06 +0000145 UChar instr_len;
njnd3bef4f2005-10-15 17:46:18 +0000146 LineCC* parent; // parent line-CC
nethercote9313ac42004-07-06 21:54:20 +0000147};
148
sewardj0b9d74a2006-12-24 02:24:11 +0000149typedef struct _SB_info SB_info;
150struct _SB_info {
151 Addr SB_addr; // key; MUST BE FIRST
njnd3bef4f2005-10-15 17:46:18 +0000152 Int n_instrs;
153 InstrInfo instrs[0];
nethercote9313ac42004-07-06 21:54:20 +0000154};
155
njnd3bef4f2005-10-15 17:46:18 +0000156static OSet* instrInfoTable;
157
158//------------------------------------------------------------
159// Secondary data structure: string table
160// - holds strings, avoiding dups
161// - used for filenames and function names, each of which will be
162// pointed to by one or more CCs.
163// - it also allows equality checks just by pointer comparison, which
164// is good when printing the output file at the end.
165
166static OSet* stringTable;
nethercote9313ac42004-07-06 21:54:20 +0000167
168//------------------------------------------------------------
169// Stats
sewardj4f29ddf2002-05-03 22:29:04 +0000170static Int distinct_files = 0;
171static Int distinct_fns = 0;
nethercote9313ac42004-07-06 21:54:20 +0000172static Int distinct_lines = 0;
sewardj4f29ddf2002-05-03 22:29:04 +0000173static Int distinct_instrs = 0;
nethercote9313ac42004-07-06 21:54:20 +0000174
njnd3bef4f2005-10-15 17:46:18 +0000175static Int full_debugs = 0;
176static Int file_line_debugs = 0;
177static Int fn_debugs = 0;
178static Int no_debugs = 0;
njn4f9c9342002-04-29 16:03:24 +0000179
nethercote9313ac42004-07-06 21:54:20 +0000180/*------------------------------------------------------------*/
njnd3bef4f2005-10-15 17:46:18 +0000181/*--- String table operations ---*/
182/*------------------------------------------------------------*/
183
njnafa12262005-12-24 03:10:56 +0000184static Word stringCmp( void* key, void* elem )
njnd3bef4f2005-10-15 17:46:18 +0000185{
186 return VG_(strcmp)(*(Char**)key, *(Char**)elem);
187}
188
189// Get a permanent string; either pull it out of the string table if it's
190// been encountered before, or dup it and put it into the string table.
191static Char* get_perm_string(Char* s)
192{
njne2a9ad32007-09-17 05:30:48 +0000193 Char** s_ptr = VG_(OSetGen_Lookup)(stringTable, &s);
njnd3bef4f2005-10-15 17:46:18 +0000194 if (s_ptr) {
195 return *s_ptr;
196 } else {
njne2a9ad32007-09-17 05:30:48 +0000197 Char** s_node = VG_(OSetGen_AllocNode)(stringTable, sizeof(Char*));
njnd3bef4f2005-10-15 17:46:18 +0000198 *s_node = VG_(strdup)(s);
njne2a9ad32007-09-17 05:30:48 +0000199 VG_(OSetGen_Insert)(stringTable, s_node);
njnd3bef4f2005-10-15 17:46:18 +0000200 return *s_node;
201 }
202}
203
204/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +0000205/*--- CC table operations ---*/
206/*------------------------------------------------------------*/
njn4294fd42002-06-05 14:41:10 +0000207
nethercote9313ac42004-07-06 21:54:20 +0000208static void get_debug_info(Addr instr_addr, Char file[FILE_LEN],
209 Char fn[FN_LEN], Int* line)
njn4f9c9342002-04-29 16:03:24 +0000210{
njnf3b61d62007-09-17 00:41:07 +0000211 Char dir[FILE_LEN];
212 Bool found_dirname;
sewardj7cee6f92005-06-13 17:39:06 +0000213 Bool found_file_line = VG_(get_filename_linenum)(
214 instr_addr,
215 file, FILE_LEN,
njnf3b61d62007-09-17 00:41:07 +0000216 dir, FILE_LEN, &found_dirname,
sewardj7cee6f92005-06-13 17:39:06 +0000217 line
218 );
nethercote9313ac42004-07-06 21:54:20 +0000219 Bool found_fn = VG_(get_fnname)(instr_addr, fn, FN_LEN);
njn4f9c9342002-04-29 16:03:24 +0000220
nethercote9313ac42004-07-06 21:54:20 +0000221 if (!found_file_line) {
222 VG_(strcpy)(file, "???");
223 *line = 0;
224 }
225 if (!found_fn) {
226 VG_(strcpy)(fn, "???");
227 }
njnf3b61d62007-09-17 00:41:07 +0000228
229 if (found_dirname) {
230 // +1 for the '/'.
231 tl_assert(VG_(strlen)(dir) + VG_(strlen)(file) + 1 < FILE_LEN);
232 VG_(strcat)(dir, "/"); // Append '/'
233 VG_(strcat)(dir, file); // Append file to dir
234 VG_(strcpy)(file, dir); // Move dir+file to file
235 }
236
nethercote9313ac42004-07-06 21:54:20 +0000237 if (found_file_line) {
njnd3bef4f2005-10-15 17:46:18 +0000238 if (found_fn) full_debugs++;
239 else file_line_debugs++;
nethercote9313ac42004-07-06 21:54:20 +0000240 } else {
njnd3bef4f2005-10-15 17:46:18 +0000241 if (found_fn) fn_debugs++;
242 else no_debugs++;
njn4f9c9342002-04-29 16:03:24 +0000243 }
244}
245
nethercote9313ac42004-07-06 21:54:20 +0000246// Do a three step traversal: by file, then fn, then line.
njnd3bef4f2005-10-15 17:46:18 +0000247// Returns a pointer to the line CC, creates a new one if necessary.
248static LineCC* get_lineCC(Addr origAddr)
nethercote9313ac42004-07-06 21:54:20 +0000249{
nethercote9313ac42004-07-06 21:54:20 +0000250 Char file[FILE_LEN], fn[FN_LEN];
251 Int line;
njnd3bef4f2005-10-15 17:46:18 +0000252 CodeLoc loc;
253 LineCC* lineCC;
nethercote9313ac42004-07-06 21:54:20 +0000254
njn6a3009b2005-03-20 00:20:06 +0000255 get_debug_info(origAddr, file, fn, &line);
nethercote9313ac42004-07-06 21:54:20 +0000256
njnd3bef4f2005-10-15 17:46:18 +0000257 loc.file = file;
258 loc.fn = fn;
259 loc.line = line;
njn4f9c9342002-04-29 16:03:24 +0000260
njne2a9ad32007-09-17 05:30:48 +0000261 lineCC = VG_(OSetGen_Lookup)(CC_table, &loc);
njnd3bef4f2005-10-15 17:46:18 +0000262 if (!lineCC) {
263 // Allocate and zero a new node.
njne2a9ad32007-09-17 05:30:48 +0000264 lineCC = VG_(OSetGen_AllocNode)(CC_table, sizeof(LineCC));
njnd3bef4f2005-10-15 17:46:18 +0000265 lineCC->loc.file = get_perm_string(loc.file);
266 lineCC->loc.fn = get_perm_string(loc.fn);
267 lineCC->loc.line = loc.line;
njn0a8db5c2007-04-02 03:11:41 +0000268 lineCC->Ir.a = 0;
269 lineCC->Ir.m1 = 0;
270 lineCC->Ir.m2 = 0;
271 lineCC->Dr.a = 0;
272 lineCC->Dr.m1 = 0;
273 lineCC->Dr.m2 = 0;
274 lineCC->Dw.a = 0;
275 lineCC->Dw.m1 = 0;
276 lineCC->Dw.m2 = 0;
sewardj8badbaa2007-05-08 09:20:25 +0000277 lineCC->Bc.b = 0;
278 lineCC->Bc.mp = 0;
279 lineCC->Bi.b = 0;
280 lineCC->Bi.mp = 0;
njne2a9ad32007-09-17 05:30:48 +0000281 VG_(OSetGen_Insert)(CC_table, lineCC);
njn4f9c9342002-04-29 16:03:24 +0000282 }
nethercote9313ac42004-07-06 21:54:20 +0000283
njnd3bef4f2005-10-15 17:46:18 +0000284 return lineCC;
njn4f9c9342002-04-29 16:03:24 +0000285}
286
287/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +0000288/*--- Cache simulation functions ---*/
njn4f9c9342002-04-29 16:03:24 +0000289/*------------------------------------------------------------*/
290
njnaf839f52005-06-23 03:27:57 +0000291static VG_REGPARM(1)
njnd3bef4f2005-10-15 17:46:18 +0000292void log_1I_0D_cache_access(InstrInfo* n)
njn25e49d8e72002-09-23 09:36:25 +0000293{
sewardj5155dec2005-10-12 10:09:23 +0000294 //VG_(printf)("1I_0D : CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n",
295 // n, n->instr_addr, n->instr_len);
njn6a3009b2005-03-20 00:20:06 +0000296 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000297 &n->parent->Ir.m1, &n->parent->Ir.m2);
298 n->parent->Ir.a++;
njn25e49d8e72002-09-23 09:36:25 +0000299}
300
njnaf839f52005-06-23 03:27:57 +0000301static VG_REGPARM(2)
njnd3bef4f2005-10-15 17:46:18 +0000302void log_2I_0D_cache_access(InstrInfo* n, InstrInfo* n2)
njn25e49d8e72002-09-23 09:36:25 +0000303{
sewardj5155dec2005-10-12 10:09:23 +0000304 //VG_(printf)("2I_0D : CC1addr=0x%010lx, i1addr=0x%010lx, i1size=%lu\n"
305 // " CC2addr=0x%010lx, i2addr=0x%010lx, i2size=%lu\n",
306 // n, n->instr_addr, n->instr_len,
307 // n2, n2->instr_addr, n2->instr_len);
sewardj5155dec2005-10-12 10:09:23 +0000308 cachesim_I1_doref(n->instr_addr, n->instr_len,
309 &n->parent->Ir.m1, &n->parent->Ir.m2);
310 n->parent->Ir.a++;
311 cachesim_I1_doref(n2->instr_addr, n2->instr_len,
312 &n2->parent->Ir.m1, &n2->parent->Ir.m2);
313 n2->parent->Ir.a++;
sewardj5155dec2005-10-12 10:09:23 +0000314}
315
316static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000317void log_3I_0D_cache_access(InstrInfo* n, InstrInfo* n2, InstrInfo* n3)
sewardj5155dec2005-10-12 10:09:23 +0000318{
319 //VG_(printf)("3I_0D : CC1addr=0x%010lx, i1addr=0x%010lx, i1size=%lu\n"
320 // " CC2addr=0x%010lx, i2addr=0x%010lx, i2size=%lu\n"
321 // " CC3addr=0x%010lx, i3addr=0x%010lx, i3size=%lu\n",
322 // n, n->instr_addr, n->instr_len,
323 // n2, n2->instr_addr, n2->instr_len,
324 // n3, n3->instr_addr, n3->instr_len);
sewardj5155dec2005-10-12 10:09:23 +0000325 cachesim_I1_doref(n->instr_addr, n->instr_len,
326 &n->parent->Ir.m1, &n->parent->Ir.m2);
327 n->parent->Ir.a++;
328 cachesim_I1_doref(n2->instr_addr, n2->instr_len,
329 &n2->parent->Ir.m1, &n2->parent->Ir.m2);
330 n2->parent->Ir.a++;
331 cachesim_I1_doref(n3->instr_addr, n3->instr_len,
332 &n3->parent->Ir.m1, &n3->parent->Ir.m2);
333 n3->parent->Ir.a++;
sewardj5155dec2005-10-12 10:09:23 +0000334}
335
336static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000337void log_1I_1Dr_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
sewardj5155dec2005-10-12 10:09:23 +0000338{
339 //VG_(printf)("1I_1Dr: CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n"
340 // " daddr=0x%010lx, dsize=%lu\n",
341 // n, n->instr_addr, n->instr_len, data_addr, data_size);
njn6a3009b2005-03-20 00:20:06 +0000342 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000343 &n->parent->Ir.m1, &n->parent->Ir.m2);
344 n->parent->Ir.a++;
njn25e49d8e72002-09-23 09:36:25 +0000345
sewardj5155dec2005-10-12 10:09:23 +0000346 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000347 &n->parent->Dr.m1, &n->parent->Dr.m2);
348 n->parent->Dr.a++;
njn25e49d8e72002-09-23 09:36:25 +0000349}
350
sewardj5155dec2005-10-12 10:09:23 +0000351static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000352void log_1I_1Dw_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
njn25e49d8e72002-09-23 09:36:25 +0000353{
sewardj5155dec2005-10-12 10:09:23 +0000354 //VG_(printf)("1I_1Dw: CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n"
355 // " daddr=0x%010lx, dsize=%lu\n",
356 // n, n->instr_addr, n->instr_len, data_addr, data_size);
njn6a3009b2005-03-20 00:20:06 +0000357 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000358 &n->parent->Ir.m1, &n->parent->Ir.m2);
359 n->parent->Ir.a++;
360
sewardj5155dec2005-10-12 10:09:23 +0000361 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000362 &n->parent->Dw.m1, &n->parent->Dw.m2);
363 n->parent->Dw.a++;
njn25e49d8e72002-09-23 09:36:25 +0000364}
365
njnaf839f52005-06-23 03:27:57 +0000366static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000367void log_0I_1Dr_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
njn25e49d8e72002-09-23 09:36:25 +0000368{
sewardj5155dec2005-10-12 10:09:23 +0000369 //VG_(printf)("0I_1Dr: CCaddr=0x%010lx, daddr=0x%010lx, dsize=%lu\n",
370 // n, data_addr, data_size);
sewardj5155dec2005-10-12 10:09:23 +0000371 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000372 &n->parent->Dr.m1, &n->parent->Dr.m2);
373 n->parent->Dr.a++;
sewardj5155dec2005-10-12 10:09:23 +0000374}
375
376static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000377void log_0I_1Dw_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
sewardj5155dec2005-10-12 10:09:23 +0000378{
379 //VG_(printf)("0I_1Dw: CCaddr=0x%010lx, daddr=0x%010lx, dsize=%lu\n",
380 // n, data_addr, data_size);
sewardj5155dec2005-10-12 10:09:23 +0000381 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000382 &n->parent->Dw.m1, &n->parent->Dw.m2);
383 n->parent->Dw.a++;
njn25e49d8e72002-09-23 09:36:25 +0000384}
385
sewardj8badbaa2007-05-08 09:20:25 +0000386/* For branches, we consult two different predictors, one which
387 predicts taken/untaken for conditional branches, and the other
388 which predicts the branch target address for indirect branches
389 (jump-to-register style ones). */
390
391static VG_REGPARM(2)
392void log_cond_branch(InstrInfo* n, Word taken)
393{
394 //VG_(printf)("cbrnch: CCaddr=0x%010lx, taken=0x%010lx\n",
395 // n, taken);
396 n->parent->Bc.b++;
397 n->parent->Bc.mp
398 += (1 & do_cond_branch_predict(n->instr_addr, taken));
399}
400
401static VG_REGPARM(2)
402void log_ind_branch(InstrInfo* n, UWord actual_dst)
403{
404 //VG_(printf)("ibrnch: CCaddr=0x%010lx, dst=0x%010lx\n",
405 // n, actual_dst);
406 n->parent->Bi.b++;
407 n->parent->Bi.mp
408 += (1 & do_ind_branch_predict(n->instr_addr, actual_dst));
409}
410
411
nethercote9313ac42004-07-06 21:54:20 +0000412/*------------------------------------------------------------*/
sewardj5155dec2005-10-12 10:09:23 +0000413/*--- Instrumentation types and structures ---*/
414/*------------------------------------------------------------*/
415
416/* Maintain an ordered list of memory events which are outstanding, in
417 the sense that no IR has yet been generated to do the relevant
418 helper calls. The BB is scanned top to bottom and memory events
419 are added to the end of the list, merging with the most recent
420 notified event where possible (Dw immediately following Dr and
421 having the same size and EA can be merged).
422
423 This merging is done so that for architectures which have
424 load-op-store instructions (x86, amd64), the insn is treated as if
425 it makes just one memory reference (a modify), rather than two (a
426 read followed by a write at the same address).
427
428 At various points the list will need to be flushed, that is, IR
429 generated from it. That must happen before any possible exit from
430 the block (the end, or an IRStmt_Exit). Flushing also takes place
431 when there is no space to add a new event.
432
433 If we require the simulation statistics to be up to date with
434 respect to possible memory exceptions, then the list would have to
435 be flushed before each memory reference. That would however lose
436 performance by inhibiting event-merging during flushing.
437
438 Flushing the list consists of walking it start to end and emitting
439 instrumentation IR for each event, in the order in which they
440 appear. It may be possible to emit a single call for two adjacent
441 events in order to reduce the number of helper function calls made.
442 For example, it could well be profitable to handle two adjacent Ir
443 events with a single helper call. */
444
445typedef
446 IRExpr
447 IRAtom;
448
449typedef
sewardj8badbaa2007-05-08 09:20:25 +0000450 enum {
451 Ev_Ir, // Instruction read
452 Ev_Dr, // Data read
453 Ev_Dw, // Data write
454 Ev_Dm, // Data modify (read then write)
455 Ev_Bc, // branch conditional
456 Ev_Bi // branch indirect (to unknown destination)
457 }
458 EventTag;
sewardj5155dec2005-10-12 10:09:23 +0000459
460typedef
461 struct {
sewardj8badbaa2007-05-08 09:20:25 +0000462 EventTag tag;
463 InstrInfo* inode;
464 union {
465 struct {
466 } Ir;
467 struct {
468 IRAtom* ea;
469 Int szB;
470 } Dr;
471 struct {
472 IRAtom* ea;
473 Int szB;
474 } Dw;
475 struct {
476 IRAtom* ea;
477 Int szB;
478 } Dm;
479 struct {
480 IRAtom* taken; /* :: Ity_I1 */
481 } Bc;
482 struct {
483 IRAtom* dst;
484 } Bi;
485 } Ev;
sewardj5155dec2005-10-12 10:09:23 +0000486 }
487 Event;
488
sewardj8badbaa2007-05-08 09:20:25 +0000489static void init_Event ( Event* ev ) {
490 VG_(memset)(ev, 0, sizeof(Event));
491}
492
493static IRAtom* get_Event_dea ( Event* ev ) {
494 switch (ev->tag) {
495 case Ev_Dr: return ev->Ev.Dr.ea;
496 case Ev_Dw: return ev->Ev.Dw.ea;
497 case Ev_Dm: return ev->Ev.Dm.ea;
498 default: tl_assert(0);
499 }
500}
501
502static Int get_Event_dszB ( Event* ev ) {
503 switch (ev->tag) {
504 case Ev_Dr: return ev->Ev.Dr.szB;
505 case Ev_Dw: return ev->Ev.Dw.szB;
506 case Ev_Dm: return ev->Ev.Dm.szB;
507 default: tl_assert(0);
508 }
509}
510
511
sewardj5155dec2005-10-12 10:09:23 +0000512/* Up to this many unnotified events are allowed. Number is
513 arbitrary. Larger numbers allow more event merging to occur, but
514 potentially induce more spilling due to extending live ranges of
515 address temporaries. */
516#define N_EVENTS 16
517
518
519/* A struct which holds all the running state during instrumentation.
520 Mostly to avoid passing loads of parameters everywhere. */
521typedef
522 struct {
523 /* The current outstanding-memory-event list. */
524 Event events[N_EVENTS];
525 Int events_used;
526
njnd3bef4f2005-10-15 17:46:18 +0000527 /* The array of InstrInfo bins for the BB. */
sewardj0b9d74a2006-12-24 02:24:11 +0000528 SB_info* sbInfo;
sewardj5155dec2005-10-12 10:09:23 +0000529
njnd3bef4f2005-10-15 17:46:18 +0000530 /* Number InstrInfo bins 'used' so far. */
sewardj0b9d74a2006-12-24 02:24:11 +0000531 Int sbInfo_i;
sewardj5155dec2005-10-12 10:09:23 +0000532
sewardj0b9d74a2006-12-24 02:24:11 +0000533 /* The output SB being constructed. */
534 IRSB* sbOut;
sewardj5155dec2005-10-12 10:09:23 +0000535 }
536 CgState;
537
538
sewardj5155dec2005-10-12 10:09:23 +0000539/*------------------------------------------------------------*/
540/*--- Instrumentation main ---*/
nethercote9313ac42004-07-06 21:54:20 +0000541/*------------------------------------------------------------*/
542
sewardj4ba057c2005-10-18 12:04:18 +0000543// Note that origAddr is the real origAddr, not the address of the first
544// instruction in the block (they can be different due to redirection).
nethercote564b2b02004-08-07 15:54:53 +0000545static
sewardj0b9d74a2006-12-24 02:24:11 +0000546SB_info* get_SB_info(IRSB* sbIn, Addr origAddr)
nethercote9313ac42004-07-06 21:54:20 +0000547{
njn4bd67b52005-08-11 00:47:10 +0000548 Int i, n_instrs;
549 IRStmt* st;
sewardj0b9d74a2006-12-24 02:24:11 +0000550 SB_info* sbInfo;
njnd3bef4f2005-10-15 17:46:18 +0000551
sewardj0b9d74a2006-12-24 02:24:11 +0000552 // Count number of original instrs in SB
njn6a3009b2005-03-20 00:20:06 +0000553 n_instrs = 0;
sewardj0b9d74a2006-12-24 02:24:11 +0000554 for (i = 0; i < sbIn->stmts_used; i++) {
555 st = sbIn->stmts[i];
njn6a3009b2005-03-20 00:20:06 +0000556 if (Ist_IMark == st->tag) n_instrs++;
nethercote9313ac42004-07-06 21:54:20 +0000557 }
558
njnf7d26092005-10-12 16:45:17 +0000559 // Check that we don't have an entry for this BB in the instr-info table.
560 // If this assertion fails, there has been some screwup: some
561 // translations must have been discarded but Cachegrind hasn't discarded
562 // the corresponding entries in the instr-info table.
njne2a9ad32007-09-17 05:30:48 +0000563 sbInfo = VG_(OSetGen_Lookup)(instrInfoTable, &origAddr);
sewardj0b9d74a2006-12-24 02:24:11 +0000564 tl_assert(NULL == sbInfo);
sewardja3a29a52005-10-12 16:16:03 +0000565
njnd3bef4f2005-10-15 17:46:18 +0000566 // BB never translated before (at this address, at least; could have
567 // been unloaded and then reloaded elsewhere in memory)
njne2a9ad32007-09-17 05:30:48 +0000568 sbInfo = VG_(OSetGen_AllocNode)(instrInfoTable,
sewardj0b9d74a2006-12-24 02:24:11 +0000569 sizeof(SB_info) + n_instrs*sizeof(InstrInfo));
570 sbInfo->SB_addr = origAddr;
571 sbInfo->n_instrs = n_instrs;
njne2a9ad32007-09-17 05:30:48 +0000572 VG_(OSetGen_Insert)( instrInfoTable, sbInfo );
sewardja3a29a52005-10-12 16:16:03 +0000573 distinct_instrs++;
574
sewardj0b9d74a2006-12-24 02:24:11 +0000575 return sbInfo;
nethercote9313ac42004-07-06 21:54:20 +0000576}
njn6a3009b2005-03-20 00:20:06 +0000577
nethercote9313ac42004-07-06 21:54:20 +0000578
sewardj5155dec2005-10-12 10:09:23 +0000579static void showEvent ( Event* ev )
nethercote9313ac42004-07-06 21:54:20 +0000580{
sewardj8badbaa2007-05-08 09:20:25 +0000581 switch (ev->tag) {
582 case Ev_Ir:
njnfd9f6222005-10-16 00:17:37 +0000583 VG_(printf)("Ir %p\n", ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000584 break;
sewardj8badbaa2007-05-08 09:20:25 +0000585 case Ev_Dr:
586 VG_(printf)("Dr %p %d EA=", ev->inode, ev->Ev.Dr.szB);
587 ppIRExpr(ev->Ev.Dr.ea);
sewardj5155dec2005-10-12 10:09:23 +0000588 VG_(printf)("\n");
589 break;
sewardj8badbaa2007-05-08 09:20:25 +0000590 case Ev_Dw:
591 VG_(printf)("Dw %p %d EA=", ev->inode, ev->Ev.Dw.szB);
592 ppIRExpr(ev->Ev.Dw.ea);
sewardj5155dec2005-10-12 10:09:23 +0000593 VG_(printf)("\n");
594 break;
sewardj8badbaa2007-05-08 09:20:25 +0000595 case Ev_Dm:
596 VG_(printf)("Dm %p %d EA=", ev->inode, ev->Ev.Dm.szB);
597 ppIRExpr(ev->Ev.Dm.ea);
598 VG_(printf)("\n");
599 break;
600 case Ev_Bc:
601 VG_(printf)("Bc %p GA=", ev->inode);
602 ppIRExpr(ev->Ev.Bc.taken);
603 VG_(printf)("\n");
604 break;
605 case Ev_Bi:
606 VG_(printf)("Bi %p DST=", ev->inode);
607 ppIRExpr(ev->Ev.Bi.dst);
sewardj5155dec2005-10-12 10:09:23 +0000608 VG_(printf)("\n");
609 break;
610 default:
611 tl_assert(0);
612 break;
613 }
njn6a3009b2005-03-20 00:20:06 +0000614}
615
njnfd9f6222005-10-16 00:17:37 +0000616// Reserve and initialise an InstrInfo for the first mention of a new insn.
617static
618InstrInfo* setup_InstrInfo ( CgState* cgs, Addr instr_addr, UInt instr_len )
njn6a3009b2005-03-20 00:20:06 +0000619{
njnd3bef4f2005-10-15 17:46:18 +0000620 InstrInfo* i_node;
sewardj0b9d74a2006-12-24 02:24:11 +0000621 tl_assert(cgs->sbInfo_i >= 0);
622 tl_assert(cgs->sbInfo_i < cgs->sbInfo->n_instrs);
623 i_node = &cgs->sbInfo->instrs[ cgs->sbInfo_i ];
njnfd9f6222005-10-16 00:17:37 +0000624 i_node->instr_addr = instr_addr;
625 i_node->instr_len = instr_len;
626 i_node->parent = get_lineCC(instr_addr);
sewardj0b9d74a2006-12-24 02:24:11 +0000627 cgs->sbInfo_i++;
sewardj5155dec2005-10-12 10:09:23 +0000628 return i_node;
629}
sewardj17a56bf2005-03-21 01:35:02 +0000630
sewardj17a56bf2005-03-21 01:35:02 +0000631
sewardj5155dec2005-10-12 10:09:23 +0000632/* Generate code for all outstanding memory events, and mark the queue
633 empty. Code is generated into cgs->bbOut, and this activity
sewardj0b9d74a2006-12-24 02:24:11 +0000634 'consumes' slots in cgs->sbInfo. */
njn6a3009b2005-03-20 00:20:06 +0000635
sewardj5155dec2005-10-12 10:09:23 +0000636static void flushEvents ( CgState* cgs )
637{
njnd3bef4f2005-10-15 17:46:18 +0000638 Int i, regparms;
639 Char* helperName;
640 void* helperAddr;
641 IRExpr** argv;
642 IRExpr* i_node_expr;
njnd3bef4f2005-10-15 17:46:18 +0000643 IRDirty* di;
njnc285dca2005-10-15 22:07:28 +0000644 Event* ev;
645 Event* ev2;
646 Event* ev3;
njn6a3009b2005-03-20 00:20:06 +0000647
sewardj5155dec2005-10-12 10:09:23 +0000648 i = 0;
649 while (i < cgs->events_used) {
njn6a3009b2005-03-20 00:20:06 +0000650
sewardj5155dec2005-10-12 10:09:23 +0000651 helperName = NULL;
652 helperAddr = NULL;
653 argv = NULL;
654 regparms = 0;
655
656 /* generate IR to notify event i and possibly the ones
657 immediately following it. */
658 tl_assert(i >= 0 && i < cgs->events_used);
njnc285dca2005-10-15 22:07:28 +0000659
660 ev = &cgs->events[i];
661 ev2 = ( i < cgs->events_used-1 ? &cgs->events[i+1] : NULL );
662 ev3 = ( i < cgs->events_used-2 ? &cgs->events[i+2] : NULL );
663
sewardj5155dec2005-10-12 10:09:23 +0000664 if (DEBUG_CG) {
665 VG_(printf)(" flush ");
njnc285dca2005-10-15 22:07:28 +0000666 showEvent( ev );
njn4f9c9342002-04-29 16:03:24 +0000667 }
sewardj5155dec2005-10-12 10:09:23 +0000668
njnfd9f6222005-10-16 00:17:37 +0000669 i_node_expr = mkIRExpr_HWord( (HWord)ev->inode );
sewardj5155dec2005-10-12 10:09:23 +0000670
671 /* Decide on helper fn to call and args to pass it, and advance
672 i appropriately. */
sewardj8badbaa2007-05-08 09:20:25 +0000673 switch (ev->tag) {
674 case Ev_Ir:
675 /* Merge an Ir with a following Dr/Dm. */
676 if (ev2 && (ev2->tag == Ev_Dr || ev2->tag == Ev_Dm)) {
677 /* Why is this true? It's because we're merging an Ir
678 with a following Dr or Dm. The Ir derives from the
679 instruction's IMark and the Dr/Dm from data
680 references which follow it. In short it holds
681 because each insn starts with an IMark, hence an
682 Ev_Ir, and so these Dr/Dm must pertain to the
683 immediately preceding Ir. Same applies to analogous
684 assertions in the subsequent cases. */
njnfd9f6222005-10-16 00:17:37 +0000685 tl_assert(ev2->inode == ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000686 helperName = "log_1I_1Dr_cache_access";
687 helperAddr = &log_1I_1Dr_cache_access;
688 argv = mkIRExprVec_3( i_node_expr,
sewardj8badbaa2007-05-08 09:20:25 +0000689 get_Event_dea(ev2),
690 mkIRExpr_HWord( get_Event_dszB(ev2) ) );
sewardj5155dec2005-10-12 10:09:23 +0000691 regparms = 3;
692 i += 2;
693 }
sewardj8badbaa2007-05-08 09:20:25 +0000694 /* Merge an Ir with a following Dw. */
sewardj5155dec2005-10-12 10:09:23 +0000695 else
sewardj8badbaa2007-05-08 09:20:25 +0000696 if (ev2 && ev2->tag == Ev_Dw) {
njnfd9f6222005-10-16 00:17:37 +0000697 tl_assert(ev2->inode == ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000698 helperName = "log_1I_1Dw_cache_access";
699 helperAddr = &log_1I_1Dw_cache_access;
700 argv = mkIRExprVec_3( i_node_expr,
sewardj8badbaa2007-05-08 09:20:25 +0000701 get_Event_dea(ev2),
702 mkIRExpr_HWord( get_Event_dszB(ev2) ) );
sewardj5155dec2005-10-12 10:09:23 +0000703 regparms = 3;
704 i += 2;
705 }
sewardj8badbaa2007-05-08 09:20:25 +0000706 /* Merge an Ir with two following Irs. */
sewardj5155dec2005-10-12 10:09:23 +0000707 else
sewardj8badbaa2007-05-08 09:20:25 +0000708 if (ev2 && ev3 && ev2->tag == Ev_Ir && ev3->tag == Ev_Ir)
njnc285dca2005-10-15 22:07:28 +0000709 {
sewardj5155dec2005-10-12 10:09:23 +0000710 helperName = "log_3I_0D_cache_access";
711 helperAddr = &log_3I_0D_cache_access;
njnfd9f6222005-10-16 00:17:37 +0000712 argv = mkIRExprVec_3( i_node_expr,
713 mkIRExpr_HWord( (HWord)ev2->inode ),
714 mkIRExpr_HWord( (HWord)ev3->inode ) );
sewardj5155dec2005-10-12 10:09:23 +0000715 regparms = 3;
716 i += 3;
717 }
sewardj8badbaa2007-05-08 09:20:25 +0000718 /* Merge an Ir with one following Ir. */
sewardj5155dec2005-10-12 10:09:23 +0000719 else
sewardj8badbaa2007-05-08 09:20:25 +0000720 if (ev2 && ev2->tag == Ev_Ir) {
sewardj5155dec2005-10-12 10:09:23 +0000721 helperName = "log_2I_0D_cache_access";
722 helperAddr = &log_2I_0D_cache_access;
njnfd9f6222005-10-16 00:17:37 +0000723 argv = mkIRExprVec_2( i_node_expr,
724 mkIRExpr_HWord( (HWord)ev2->inode ) );
sewardj5155dec2005-10-12 10:09:23 +0000725 regparms = 2;
726 i += 2;
727 }
728 /* No merging possible; emit as-is. */
729 else {
730 helperName = "log_1I_0D_cache_access";
731 helperAddr = &log_1I_0D_cache_access;
732 argv = mkIRExprVec_1( i_node_expr );
733 regparms = 1;
734 i++;
735 }
736 break;
sewardj8badbaa2007-05-08 09:20:25 +0000737 case Ev_Dr:
738 case Ev_Dm:
739 /* Data read or modify */
sewardj5155dec2005-10-12 10:09:23 +0000740 helperName = "log_0I_1Dr_cache_access";
741 helperAddr = &log_0I_1Dr_cache_access;
742 argv = mkIRExprVec_3( i_node_expr,
sewardj8badbaa2007-05-08 09:20:25 +0000743 get_Event_dea(ev),
744 mkIRExpr_HWord( get_Event_dszB(ev) ) );
sewardj5155dec2005-10-12 10:09:23 +0000745 regparms = 3;
746 i++;
747 break;
sewardj8badbaa2007-05-08 09:20:25 +0000748 case Ev_Dw:
749 /* Data write */
sewardj5155dec2005-10-12 10:09:23 +0000750 helperName = "log_0I_1Dw_cache_access";
751 helperAddr = &log_0I_1Dw_cache_access;
752 argv = mkIRExprVec_3( i_node_expr,
sewardj8badbaa2007-05-08 09:20:25 +0000753 get_Event_dea(ev),
754 mkIRExpr_HWord( get_Event_dszB(ev) ) );
sewardj5155dec2005-10-12 10:09:23 +0000755 regparms = 3;
756 i++;
757 break;
sewardj8badbaa2007-05-08 09:20:25 +0000758 case Ev_Bc:
759 /* Conditional branch */
760 helperName = "log_cond_branch";
761 helperAddr = &log_cond_branch;
762 argv = mkIRExprVec_2( i_node_expr, ev->Ev.Bc.taken );
763 regparms = 2;
764 i++;
765 break;
766 case Ev_Bi:
767 /* Branch to an unknown destination */
768 helperName = "log_ind_branch";
769 helperAddr = &log_ind_branch;
770 argv = mkIRExprVec_2( i_node_expr, ev->Ev.Bi.dst );
771 regparms = 2;
772 i++;
773 break;
sewardj5155dec2005-10-12 10:09:23 +0000774 default:
775 tl_assert(0);
776 }
777
778 /* Add the helper. */
779 tl_assert(helperName);
780 tl_assert(helperAddr);
781 tl_assert(argv);
sewardj5bb86822005-12-23 12:47:42 +0000782 di = unsafeIRDirty_0_N( regparms,
783 helperName, VG_(fnptr_to_fnentry)( helperAddr ),
784 argv );
sewardj0b9d74a2006-12-24 02:24:11 +0000785 addStmtToIRSB( cgs->sbOut, IRStmt_Dirty(di) );
njn4f9c9342002-04-29 16:03:24 +0000786 }
787
sewardj5155dec2005-10-12 10:09:23 +0000788 cgs->events_used = 0;
njn4f9c9342002-04-29 16:03:24 +0000789}
njn14d01ce2004-11-26 11:30:14 +0000790
njnfd9f6222005-10-16 00:17:37 +0000791static void addEvent_Ir ( CgState* cgs, InstrInfo* inode )
sewardj5155dec2005-10-12 10:09:23 +0000792{
793 Event* evt;
sewardj5155dec2005-10-12 10:09:23 +0000794 if (cgs->events_used == N_EVENTS)
795 flushEvents(cgs);
796 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
797 evt = &cgs->events[cgs->events_used];
sewardj8badbaa2007-05-08 09:20:25 +0000798 init_Event(evt);
799 evt->tag = Ev_Ir;
njnfd9f6222005-10-16 00:17:37 +0000800 evt->inode = inode;
sewardj5155dec2005-10-12 10:09:23 +0000801 cgs->events_used++;
802}
803
njnfd9f6222005-10-16 00:17:37 +0000804static
805void addEvent_Dr ( CgState* cgs, InstrInfo* inode, Int datasize, IRAtom* ea )
sewardj5155dec2005-10-12 10:09:23 +0000806{
njnfd9f6222005-10-16 00:17:37 +0000807 Event* evt;
sewardj5155dec2005-10-12 10:09:23 +0000808 tl_assert(isIRAtom(ea));
njnfd9f6222005-10-16 00:17:37 +0000809 tl_assert(datasize >= 1 && datasize <= MIN_LINE_SIZE);
sewardj8badbaa2007-05-08 09:20:25 +0000810 if (!clo_cache_sim)
811 return;
njnfd9f6222005-10-16 00:17:37 +0000812 if (cgs->events_used == N_EVENTS)
813 flushEvents(cgs);
814 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
815 evt = &cgs->events[cgs->events_used];
sewardj8badbaa2007-05-08 09:20:25 +0000816 init_Event(evt);
817 evt->tag = Ev_Dr;
818 evt->inode = inode;
819 evt->Ev.Dr.szB = datasize;
820 evt->Ev.Dr.ea = ea;
njnfd9f6222005-10-16 00:17:37 +0000821 cgs->events_used++;
822}
sewardj5155dec2005-10-12 10:09:23 +0000823
njnfd9f6222005-10-16 00:17:37 +0000824static
825void addEvent_Dw ( CgState* cgs, InstrInfo* inode, Int datasize, IRAtom* ea )
826{
827 Event* lastEvt;
828 Event* evt;
829
830 tl_assert(isIRAtom(ea));
831 tl_assert(datasize >= 1 && datasize <= MIN_LINE_SIZE);
832
sewardj8badbaa2007-05-08 09:20:25 +0000833 if (!clo_cache_sim)
834 return;
835
njnfd9f6222005-10-16 00:17:37 +0000836 /* Is it possible to merge this write with the preceding read? */
837 lastEvt = &cgs->events[cgs->events_used-1];
sewardj5155dec2005-10-12 10:09:23 +0000838 if (cgs->events_used > 0
sewardj8badbaa2007-05-08 09:20:25 +0000839 && lastEvt->tag == Ev_Dr
840 && lastEvt->Ev.Dr.szB == datasize
841 && lastEvt->inode == inode
842 && eqIRAtom(lastEvt->Ev.Dr.ea, ea))
njnfd9f6222005-10-16 00:17:37 +0000843 {
sewardj8badbaa2007-05-08 09:20:25 +0000844 lastEvt->tag = Ev_Dm;
sewardj5155dec2005-10-12 10:09:23 +0000845 return;
846 }
847
848 /* No. Add as normal. */
849 if (cgs->events_used == N_EVENTS)
850 flushEvents(cgs);
851 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
njnfd9f6222005-10-16 00:17:37 +0000852 evt = &cgs->events[cgs->events_used];
sewardj8badbaa2007-05-08 09:20:25 +0000853 init_Event(evt);
854 evt->tag = Ev_Dw;
855 evt->inode = inode;
856 evt->Ev.Dw.szB = datasize;
857 evt->Ev.Dw.ea = ea;
858 cgs->events_used++;
859}
860
861static
862void addEvent_Bc ( CgState* cgs, InstrInfo* inode, IRAtom* guard )
863{
864 Event* evt;
865 tl_assert(isIRAtom(guard));
866 tl_assert(typeOfIRExpr(cgs->sbOut->tyenv, guard)
867 == (sizeof(HWord)==4 ? Ity_I32 : Ity_I64));
868 if (!clo_branch_sim)
869 return;
870 if (cgs->events_used == N_EVENTS)
871 flushEvents(cgs);
872 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
873 evt = &cgs->events[cgs->events_used];
874 init_Event(evt);
875 evt->tag = Ev_Bc;
876 evt->inode = inode;
877 evt->Ev.Bc.taken = guard;
878 cgs->events_used++;
879}
880
881static
882void addEvent_Bi ( CgState* cgs, InstrInfo* inode, IRAtom* whereTo )
883{
884 Event* evt;
885 tl_assert(isIRAtom(whereTo));
886 tl_assert(typeOfIRExpr(cgs->sbOut->tyenv, whereTo)
887 == (sizeof(HWord)==4 ? Ity_I32 : Ity_I64));
888 if (!clo_branch_sim)
889 return;
890 if (cgs->events_used == N_EVENTS)
891 flushEvents(cgs);
892 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
893 evt = &cgs->events[cgs->events_used];
894 init_Event(evt);
895 evt->tag = Ev_Bi;
896 evt->inode = inode;
897 evt->Ev.Bi.dst = whereTo;
sewardj5155dec2005-10-12 10:09:23 +0000898 cgs->events_used++;
899}
900
901////////////////////////////////////////////////////////////
902
903
sewardj4ba057c2005-10-18 12:04:18 +0000904static
sewardj0b9d74a2006-12-24 02:24:11 +0000905IRSB* cg_instrument ( VgCallbackClosure* closure,
906 IRSB* sbIn,
sewardj461df9c2006-01-17 02:06:39 +0000907 VexGuestLayout* layout,
908 VexGuestExtents* vge,
sewardj4ba057c2005-10-18 12:04:18 +0000909 IRType gWordTy, IRType hWordTy )
njn14d01ce2004-11-26 11:30:14 +0000910{
njnfd9f6222005-10-16 00:17:37 +0000911 Int i, isize;
sewardj5155dec2005-10-12 10:09:23 +0000912 IRStmt* st;
913 Addr64 cia; /* address of current insn */
914 CgState cgs;
sewardj0b9d74a2006-12-24 02:24:11 +0000915 IRTypeEnv* tyenv = sbIn->tyenv;
njnfd9f6222005-10-16 00:17:37 +0000916 InstrInfo* curr_inode = NULL;
sewardj5155dec2005-10-12 10:09:23 +0000917
sewardjd54babf2005-03-21 00:55:49 +0000918 if (gWordTy != hWordTy) {
919 /* We don't currently support this case. */
920 VG_(tool_panic)("host/guest word size mismatch");
921 }
922
sewardj0b9d74a2006-12-24 02:24:11 +0000923 // Set up new SB
924 cgs.sbOut = deepCopyIRSBExceptStmts(sbIn);
njn6a3009b2005-03-20 00:20:06 +0000925
sewardja9f538c2005-10-23 12:06:55 +0000926 // Copy verbatim any IR preamble preceding the first IMark
njn6a3009b2005-03-20 00:20:06 +0000927 i = 0;
sewardj0b9d74a2006-12-24 02:24:11 +0000928 while (i < sbIn->stmts_used && sbIn->stmts[i]->tag != Ist_IMark) {
929 addStmtToIRSB( cgs.sbOut, sbIn->stmts[i] );
sewardja9f538c2005-10-23 12:06:55 +0000930 i++;
931 }
932
933 // Get the first statement, and initial cia from it
sewardj0b9d74a2006-12-24 02:24:11 +0000934 tl_assert(sbIn->stmts_used > 0);
935 tl_assert(i < sbIn->stmts_used);
936 st = sbIn->stmts[i];
njn6a3009b2005-03-20 00:20:06 +0000937 tl_assert(Ist_IMark == st->tag);
sewardj8badbaa2007-05-08 09:20:25 +0000938
939 cia = st->Ist.IMark.addr;
940 isize = st->Ist.IMark.len;
941 // If Vex fails to decode an instruction, the size will be zero.
942 // Pretend otherwise.
943 if (isize == 0) isize = VG_MIN_INSTR_SZB;
njn6a3009b2005-03-20 00:20:06 +0000944
sewardj5155dec2005-10-12 10:09:23 +0000945 // Set up running state and get block info
sewardj3a384b32006-01-22 01:12:51 +0000946 tl_assert(closure->readdr == vge->base[0]);
sewardj5155dec2005-10-12 10:09:23 +0000947 cgs.events_used = 0;
sewardj0b9d74a2006-12-24 02:24:11 +0000948 cgs.sbInfo = get_SB_info(sbIn, (Addr)closure->readdr);
949 cgs.sbInfo_i = 0;
njn6a3009b2005-03-20 00:20:06 +0000950
sewardj5155dec2005-10-12 10:09:23 +0000951 if (DEBUG_CG)
952 VG_(printf)("\n\n---------- cg_instrument ----------\n");
njn6a3009b2005-03-20 00:20:06 +0000953
njnfd9f6222005-10-16 00:17:37 +0000954 // Traverse the block, initialising inodes, adding events and flushing as
955 // necessary.
sewardj0b9d74a2006-12-24 02:24:11 +0000956 for (/*use current i*/; i < sbIn->stmts_used; i++) {
njn6a3009b2005-03-20 00:20:06 +0000957
sewardj0b9d74a2006-12-24 02:24:11 +0000958 st = sbIn->stmts[i];
sewardj5155dec2005-10-12 10:09:23 +0000959 tl_assert(isFlatIRStmt(st));
njnb3507ea2005-08-02 23:07:02 +0000960
sewardj5155dec2005-10-12 10:09:23 +0000961 switch (st->tag) {
962 case Ist_NoOp:
963 case Ist_AbiHint:
964 case Ist_Put:
965 case Ist_PutI:
sewardj72d75132007-11-09 23:06:35 +0000966 case Ist_MBE:
sewardj5155dec2005-10-12 10:09:23 +0000967 break;
njn20677cc2005-08-12 23:47:51 +0000968
sewardj5155dec2005-10-12 10:09:23 +0000969 case Ist_IMark:
njnfd9f6222005-10-16 00:17:37 +0000970 cia = st->Ist.IMark.addr;
971 isize = st->Ist.IMark.len;
972
973 // If Vex fails to decode an instruction, the size will be zero.
974 // Pretend otherwise.
975 if (isize == 0) isize = VG_MIN_INSTR_SZB;
976
njna5ad9ba2005-11-10 15:20:37 +0000977 // Sanity-check size.
978 tl_assert( (VG_MIN_INSTR_SZB <= isize && isize <= VG_MAX_INSTR_SZB)
979 || VG_CLREQ_SZB == isize );
njnfd9f6222005-10-16 00:17:37 +0000980
981 // Get space for and init the inode, record it as the current one.
982 // Subsequent Dr/Dw/Dm events from the same instruction will
983 // also use it.
984 curr_inode = setup_InstrInfo(&cgs, cia, isize);
985
986 addEvent_Ir( &cgs, curr_inode );
sewardj5155dec2005-10-12 10:09:23 +0000987 break;
988
sewardj0b9d74a2006-12-24 02:24:11 +0000989 case Ist_WrTmp: {
990 IRExpr* data = st->Ist.WrTmp.data;
sewardj5155dec2005-10-12 10:09:23 +0000991 if (data->tag == Iex_Load) {
992 IRExpr* aexpr = data->Iex.Load.addr;
sewardj5155dec2005-10-12 10:09:23 +0000993 // Note also, endianness info is ignored. I guess
994 // that's not interesting.
njnfd9f6222005-10-16 00:17:37 +0000995 addEvent_Dr( &cgs, curr_inode, sizeofIRType(data->Iex.Load.ty),
996 aexpr );
sewardj5155dec2005-10-12 10:09:23 +0000997 }
998 break;
njnb3507ea2005-08-02 23:07:02 +0000999 }
1000
sewardj5155dec2005-10-12 10:09:23 +00001001 case Ist_Store: {
1002 IRExpr* data = st->Ist.Store.data;
1003 IRExpr* aexpr = st->Ist.Store.addr;
njnfd9f6222005-10-16 00:17:37 +00001004 addEvent_Dw( &cgs, curr_inode,
1005 sizeofIRType(typeOfIRExpr(tyenv, data)), aexpr );
sewardj5155dec2005-10-12 10:09:23 +00001006 break;
1007 }
njnb3507ea2005-08-02 23:07:02 +00001008
sewardj5155dec2005-10-12 10:09:23 +00001009 case Ist_Dirty: {
1010 Int dataSize;
1011 IRDirty* d = st->Ist.Dirty.details;
1012 if (d->mFx != Ifx_None) {
njnfd9f6222005-10-16 00:17:37 +00001013 /* This dirty helper accesses memory. Collect the details. */
sewardj5155dec2005-10-12 10:09:23 +00001014 tl_assert(d->mAddr != NULL);
1015 tl_assert(d->mSize != 0);
1016 dataSize = d->mSize;
1017 // Large (eg. 28B, 108B, 512B on x86) data-sized
1018 // instructions will be done inaccurately, but they're
1019 // very rare and this avoids errors from hitting more
1020 // than two cache lines in the simulation.
1021 if (dataSize > MIN_LINE_SIZE)
1022 dataSize = MIN_LINE_SIZE;
1023 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
njnfd9f6222005-10-16 00:17:37 +00001024 addEvent_Dr( &cgs, curr_inode, dataSize, d->mAddr );
sewardj5155dec2005-10-12 10:09:23 +00001025 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
njnfd9f6222005-10-16 00:17:37 +00001026 addEvent_Dw( &cgs, curr_inode, dataSize, d->mAddr );
sewardj5155dec2005-10-12 10:09:23 +00001027 } else {
1028 tl_assert(d->mAddr == NULL);
1029 tl_assert(d->mSize == 0);
1030 }
1031 break;
1032 }
njn6a3009b2005-03-20 00:20:06 +00001033
sewardj8badbaa2007-05-08 09:20:25 +00001034 case Ist_Exit: {
1035 /* Stuff to widen the guard expression to a host word, so
1036 we can pass it to the branch predictor simulation
1037 functions easily. */
1038 Bool inverted;
1039 Addr64 nia, sea;
1040 IRConst* dst;
1041 IROp tyW = hWordTy;
1042 IROp widen = tyW==Ity_I32 ? Iop_1Uto32 : Iop_1Uto64;
1043 IROp opXOR = tyW==Ity_I32 ? Iop_Xor32 : Iop_Xor64;
1044 IRTemp guard1 = newIRTemp(cgs.sbOut->tyenv, Ity_I1);
1045 IRTemp guardW = newIRTemp(cgs.sbOut->tyenv, tyW);
1046 IRTemp guard = newIRTemp(cgs.sbOut->tyenv, tyW);
1047 IRExpr* one = tyW==Ity_I32 ? IRExpr_Const(IRConst_U32(1))
1048 : IRExpr_Const(IRConst_U64(1));
1049
1050 /* First we need to figure out whether the side exit got
1051 inverted by the ir optimiser. To do that, figure out
1052 the next (fallthrough) instruction's address and the
1053 side exit address and see if they are the same. */
1054 nia = cia + (Addr64)isize;
1055 if (tyW == Ity_I32)
1056 nia &= 0xFFFFFFFFULL;
1057
1058 /* Side exit address */
1059 dst = st->Ist.Exit.dst;
1060 if (tyW == Ity_I32) {
1061 tl_assert(dst->tag == Ico_U32);
1062 sea = (Addr64)(UInt)dst->Ico.U32;
1063 } else {
1064 tl_assert(tyW == Ity_I64);
1065 tl_assert(dst->tag == Ico_U64);
1066 sea = dst->Ico.U64;
1067 }
1068
1069 inverted = nia == sea;
1070
1071 /* Widen the guard expression. */
1072 addStmtToIRSB( cgs.sbOut,
1073 IRStmt_WrTmp( guard1, st->Ist.Exit.guard ));
1074 addStmtToIRSB( cgs.sbOut,
1075 IRStmt_WrTmp( guardW,
1076 IRExpr_Unop(widen,
1077 IRExpr_RdTmp(guard1))) );
1078 /* If the exit is inverted, invert the sense of the guard. */
1079 addStmtToIRSB(
1080 cgs.sbOut,
1081 IRStmt_WrTmp(
1082 guard,
1083 inverted ? IRExpr_Binop(opXOR, IRExpr_RdTmp(guardW), one)
1084 : IRExpr_RdTmp(guardW)
1085 ));
1086 /* And post the event. */
1087 addEvent_Bc( &cgs, curr_inode, IRExpr_RdTmp(guard) );
1088
sewardj5155dec2005-10-12 10:09:23 +00001089 /* We may never reach the next statement, so need to flush
1090 all outstanding transactions now. */
1091 flushEvents( &cgs );
1092 break;
sewardj8badbaa2007-05-08 09:20:25 +00001093 }
sewardj5155dec2005-10-12 10:09:23 +00001094
1095 default:
1096 tl_assert(0);
1097 break;
njnb3507ea2005-08-02 23:07:02 +00001098 }
njn6a3009b2005-03-20 00:20:06 +00001099
sewardj5155dec2005-10-12 10:09:23 +00001100 /* Copy the original statement */
sewardj0b9d74a2006-12-24 02:24:11 +00001101 addStmtToIRSB( cgs.sbOut, st );
njn6a3009b2005-03-20 00:20:06 +00001102
sewardj5155dec2005-10-12 10:09:23 +00001103 if (DEBUG_CG) {
1104 ppIRStmt(st);
1105 VG_(printf)("\n");
1106 }
1107 }
1108
sewardj8badbaa2007-05-08 09:20:25 +00001109 /* Deal with branches to unknown destinations. Except ignore ones
1110 which are function returns as we assume the return stack
1111 predictor never mispredicts. */
1112 if (sbIn->jumpkind == Ijk_Boring) {
1113 if (0) { ppIRExpr( sbIn->next ); VG_(printf)("\n"); }
1114 switch (sbIn->next->tag) {
1115 case Iex_Const:
1116 break; /* boring - branch to known address */
1117 case Iex_RdTmp:
1118 /* looks like an indirect branch (branch to unknown) */
1119 addEvent_Bi( &cgs, curr_inode, sbIn->next );
1120 break;
1121 default:
1122 /* shouldn't happen - if the incoming IR is properly
1123 flattened, should only have tmp and const cases to
1124 consider. */
1125 tl_assert(0);
1126 }
1127 }
1128
sewardj5155dec2005-10-12 10:09:23 +00001129 /* At the end of the bb. Flush outstandings. */
sewardj5155dec2005-10-12 10:09:23 +00001130 flushEvents( &cgs );
1131
sewardj5155dec2005-10-12 10:09:23 +00001132 /* done. stay sane ... */
sewardj0b9d74a2006-12-24 02:24:11 +00001133 tl_assert(cgs.sbInfo_i == cgs.sbInfo->n_instrs);
sewardj5155dec2005-10-12 10:09:23 +00001134
1135 if (DEBUG_CG) {
1136 VG_(printf)( "goto {");
sewardj0b9d74a2006-12-24 02:24:11 +00001137 ppIRJumpKind(sbIn->jumpkind);
sewardj5155dec2005-10-12 10:09:23 +00001138 VG_(printf)( "} ");
sewardj0b9d74a2006-12-24 02:24:11 +00001139 ppIRExpr( sbIn->next );
sewardj5155dec2005-10-12 10:09:23 +00001140 VG_(printf)( "}\n");
1141 }
1142
sewardj0b9d74a2006-12-24 02:24:11 +00001143 return cgs.sbOut;
njn14d01ce2004-11-26 11:30:14 +00001144}
njn4f9c9342002-04-29 16:03:24 +00001145
1146/*------------------------------------------------------------*/
nethercoteb35a8b92004-09-11 16:45:27 +00001147/*--- Cache configuration ---*/
njn4f9c9342002-04-29 16:03:24 +00001148/*------------------------------------------------------------*/
1149
sewardjb5f6f512005-03-10 23:59:00 +00001150#define UNDEFINED_CACHE { -1, -1, -1 }
njn25e49d8e72002-09-23 09:36:25 +00001151
1152static cache_t clo_I1_cache = UNDEFINED_CACHE;
1153static cache_t clo_D1_cache = UNDEFINED_CACHE;
1154static cache_t clo_L2_cache = UNDEFINED_CACHE;
1155
njn7cf0bd32002-06-08 13:36:03 +00001156/* Checks cache config is ok; makes it so if not. */
sewardj07133bf2002-06-13 10:25:56 +00001157static
njna1d1a642004-11-26 18:36:02 +00001158void check_cache(cache_t* cache, Char *name)
njn7cf0bd32002-06-08 13:36:03 +00001159{
1160 /* First check they're all powers of two */
sewardj07133bf2002-06-13 10:25:56 +00001161 if (-1 == VG_(log2)(cache->size)) {
njn7cf0bd32002-06-08 13:36:03 +00001162 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +00001163 "error: %s size of %dB not a power of two; aborting.",
1164 name, cache->size);
1165 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +00001166 }
1167
sewardj07133bf2002-06-13 10:25:56 +00001168 if (-1 == VG_(log2)(cache->assoc)) {
njn7cf0bd32002-06-08 13:36:03 +00001169 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +00001170 "error: %s associativity of %d not a power of two; aborting.",
1171 name, cache->assoc);
1172 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +00001173 }
1174
sewardj07133bf2002-06-13 10:25:56 +00001175 if (-1 == VG_(log2)(cache->line_size)) {
njn7cf0bd32002-06-08 13:36:03 +00001176 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +00001177 "error: %s line size of %dB not a power of two; aborting.",
1178 name, cache->line_size);
1179 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +00001180 }
1181
njn6a3009b2005-03-20 00:20:06 +00001182 // Then check line size >= 16 -- any smaller and a single instruction could
1183 // straddle three cache lines, which breaks a simulation assertion and is
1184 // stupid anyway.
njn7cf0bd32002-06-08 13:36:03 +00001185 if (cache->line_size < MIN_LINE_SIZE) {
1186 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +00001187 "error: %s line size of %dB too small; aborting.",
1188 name, cache->line_size);
1189 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +00001190 }
1191
1192 /* Then check cache size > line size (causes seg faults if not). */
1193 if (cache->size <= cache->line_size) {
1194 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +00001195 "error: %s cache size of %dB <= line size of %dB; aborting.",
1196 name, cache->size, cache->line_size);
1197 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +00001198 }
1199
1200 /* Then check assoc <= (size / line size) (seg faults otherwise). */
1201 if (cache->assoc > (cache->size / cache->line_size)) {
1202 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +00001203 "warning: %s associativity > (size / line size); aborting.", name);
1204 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +00001205 }
1206}
1207
sewardj07133bf2002-06-13 10:25:56 +00001208static
nethercoteb35a8b92004-09-11 16:45:27 +00001209void configure_caches(cache_t* I1c, cache_t* D1c, cache_t* L2c)
njn7cf0bd32002-06-08 13:36:03 +00001210{
nethercote9313ac42004-07-06 21:54:20 +00001211#define DEFINED(L) (-1 != L.size || -1 != L.assoc || -1 != L.line_size)
1212
nethercoteb35a8b92004-09-11 16:45:27 +00001213 Int n_clos = 0;
nethercote9313ac42004-07-06 21:54:20 +00001214
nethercoteb35a8b92004-09-11 16:45:27 +00001215 // Count how many were defined on the command line.
1216 if (DEFINED(clo_I1_cache)) { n_clos++; }
1217 if (DEFINED(clo_D1_cache)) { n_clos++; }
1218 if (DEFINED(clo_L2_cache)) { n_clos++; }
njn7cf0bd32002-06-08 13:36:03 +00001219
njna1d1a642004-11-26 18:36:02 +00001220 // Set the cache config (using auto-detection, if supported by the
1221 // architecture)
njnaf839f52005-06-23 03:27:57 +00001222 VG_(configure_caches)( I1c, D1c, L2c, (3 == n_clos) );
sewardjb1a77a42002-07-13 13:31:20 +00001223
nethercote9313ac42004-07-06 21:54:20 +00001224 // Then replace with any defined on the command line.
nethercoteb35a8b92004-09-11 16:45:27 +00001225 if (DEFINED(clo_I1_cache)) { *I1c = clo_I1_cache; }
1226 if (DEFINED(clo_D1_cache)) { *D1c = clo_D1_cache; }
1227 if (DEFINED(clo_L2_cache)) { *L2c = clo_L2_cache; }
njn7cf0bd32002-06-08 13:36:03 +00001228
nethercote9313ac42004-07-06 21:54:20 +00001229 // Then check values and fix if not acceptable.
njna1d1a642004-11-26 18:36:02 +00001230 check_cache(I1c, "I1");
1231 check_cache(D1c, "D1");
1232 check_cache(L2c, "L2");
njn7cf0bd32002-06-08 13:36:03 +00001233
1234 if (VG_(clo_verbosity) > 1) {
1235 VG_(message)(Vg_UserMsg, "Cache configuration used:");
1236 VG_(message)(Vg_UserMsg, " I1: %dB, %d-way, %dB lines",
1237 I1c->size, I1c->assoc, I1c->line_size);
1238 VG_(message)(Vg_UserMsg, " D1: %dB, %d-way, %dB lines",
1239 D1c->size, D1c->assoc, D1c->line_size);
1240 VG_(message)(Vg_UserMsg, " L2: %dB, %d-way, %dB lines",
1241 L2c->size, L2c->assoc, L2c->line_size);
1242 }
nethercote9313ac42004-07-06 21:54:20 +00001243#undef CMD_LINE_DEFINED
njn7cf0bd32002-06-08 13:36:03 +00001244}
1245
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
sewardje1216cb2007-02-07 19:55:30 +00001258// The output file base name specified by the user using the
1259// --cachegrind-out-file switch. This is combined with the
1260// process ID and optional user-supplied qualifier (from
1261// --log-file-qualifier) to produce the name stored in
1262// cachegrind_out_file.
1263static Char* cachegrind_out_file_basename = "cachegrind.out";
1264
1265// The final, completed name for the output file.
1266static Char* cachegrind_out_file = NULL;
1267
nethercote9313ac42004-07-06 21:54:20 +00001268
nethercote9313ac42004-07-06 21:54:20 +00001269static void fprint_CC_table_and_calc_totals(void)
1270{
njnd3bef4f2005-10-15 17:46:18 +00001271 Int i, fd;
sewardj92645592005-07-23 09:18:34 +00001272 SysRes sres;
njnd3bef4f2005-10-15 17:46:18 +00001273 Char buf[512], *currFile = NULL, *currFn = NULL;
1274 LineCC* lineCC;
njn4f9c9342002-04-29 16:03:24 +00001275
sewardj92645592005-07-23 09:18:34 +00001276 sres = VG_(open)(cachegrind_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
1277 VKI_S_IRUSR|VKI_S_IWUSR);
1278 if (sres.isError) {
nethercote9313ac42004-07-06 21:54:20 +00001279 // If the file can't be opened for whatever reason (conflict
1280 // between multiple cachegrinded processes?), give up now.
njnee0e6a32005-04-24 00:21:01 +00001281 VG_(message)(Vg_UserMsg,
njn02bc4b82005-05-15 17:28:26 +00001282 "error: can't open cache simulation output file '%s'",
njnee0e6a32005-04-24 00:21:01 +00001283 cachegrind_out_file );
1284 VG_(message)(Vg_UserMsg,
1285 " ... so simulation results will be missing.");
sewardj0744b6c2002-12-11 00:45:42 +00001286 return;
sewardj92645592005-07-23 09:18:34 +00001287 } else {
sewardje8089302006-10-17 02:15:17 +00001288 fd = sres.res;
sewardj0744b6c2002-12-11 00:45:42 +00001289 }
njn4f9c9342002-04-29 16:03:24 +00001290
nethercote9313ac42004-07-06 21:54:20 +00001291 // "desc:" lines (giving I1/D1/L2 cache configuration). The spaces after
1292 // the 2nd colon makes cg_annotate's output look nicer.
1293 VG_(sprintf)(buf, "desc: I1 cache: %s\n"
1294 "desc: D1 cache: %s\n"
1295 "desc: L2 cache: %s\n",
1296 I1.desc_line, D1.desc_line, L2.desc_line);
njn7cf0bd32002-06-08 13:36:03 +00001297 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njn4f9c9342002-04-29 16:03:24 +00001298
nethercote9313ac42004-07-06 21:54:20 +00001299 // "cmd:" line
njn4f9c9342002-04-29 16:03:24 +00001300 VG_(strcpy)(buf, "cmd:");
1301 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
sewardj45f4e7c2005-09-27 19:20:21 +00001302 if (VG_(args_the_exename)) {
1303 VG_(write)(fd, " ", 1);
1304 VG_(write)(fd, VG_(args_the_exename),
1305 VG_(strlen)( VG_(args_the_exename) ));
1306 }
sewardj14c7cc52007-02-25 15:08:24 +00001307 for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
1308 HChar* arg = * (HChar**) VG_(indexXA)( VG_(args_for_client), i );
1309 if (arg) {
sewardj45f4e7c2005-09-27 19:20:21 +00001310 VG_(write)(fd, " ", 1);
sewardj14c7cc52007-02-25 15:08:24 +00001311 VG_(write)(fd, arg, VG_(strlen)( arg ));
sewardj45f4e7c2005-09-27 19:20:21 +00001312 }
njn4f9c9342002-04-29 16:03:24 +00001313 }
nethercote9313ac42004-07-06 21:54:20 +00001314 // "events:" line
sewardj8badbaa2007-05-08 09:20:25 +00001315 if (clo_cache_sim && clo_branch_sim) {
1316 VG_(sprintf)(buf, "\nevents: Ir I1mr I2mr Dr D1mr D2mr Dw D1mw D2mw "
1317 "Bc Bcm Bi Bim\n");
1318 }
1319 else if (clo_cache_sim && !clo_branch_sim) {
1320 VG_(sprintf)(buf, "\nevents: Ir I1mr I2mr Dr D1mr D2mr Dw D1mw D2mw "
1321 "\n");
1322 }
1323 else if (!clo_cache_sim && clo_branch_sim) {
1324 VG_(sprintf)(buf, "\nevents: Ir "
1325 "Bc Bcm Bi Bim\n");
1326 }
1327 else
1328 tl_assert(0); /* can't happen */
1329
njn4f9c9342002-04-29 16:03:24 +00001330 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1331
njnd3bef4f2005-10-15 17:46:18 +00001332 // Traverse every lineCC
njne2a9ad32007-09-17 05:30:48 +00001333 VG_(OSetGen_ResetIter)(CC_table);
1334 while ( (lineCC = VG_(OSetGen_Next)(CC_table)) ) {
njn4311fe62005-12-08 23:18:50 +00001335 Bool just_hit_a_new_file = False;
njnd3bef4f2005-10-15 17:46:18 +00001336 // If we've hit a new file, print a "fl=" line. Note that because
1337 // each string is stored exactly once in the string table, we can use
1338 // pointer comparison rather than strcmp() to test for equality, which
1339 // is good because most of the time the comparisons are equal and so
njn4311fe62005-12-08 23:18:50 +00001340 // the whole strings would have to be checked.
njnd3bef4f2005-10-15 17:46:18 +00001341 if ( lineCC->loc.file != currFile ) {
1342 currFile = lineCC->loc.file;
1343 VG_(sprintf)(buf, "fl=%s\n", currFile);
njn4f9c9342002-04-29 16:03:24 +00001344 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njnd3bef4f2005-10-15 17:46:18 +00001345 distinct_files++;
njn4311fe62005-12-08 23:18:50 +00001346 just_hit_a_new_file = True;
njn4f9c9342002-04-29 16:03:24 +00001347 }
njn4311fe62005-12-08 23:18:50 +00001348 // If we've hit a new function, print a "fn=" line. We know to do
1349 // this when the function name changes, and also every time we hit a
1350 // new file (in which case the new function name might be the same as
1351 // in the old file, hence the just_hit_a_new_file test).
1352 if ( just_hit_a_new_file || lineCC->loc.fn != currFn ) {
njnd3bef4f2005-10-15 17:46:18 +00001353 currFn = lineCC->loc.fn;
1354 VG_(sprintf)(buf, "fn=%s\n", currFn);
1355 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1356 distinct_fns++;
njn4311fe62005-12-08 23:18:50 +00001357 just_hit_a_new_file = False;
njnd3bef4f2005-10-15 17:46:18 +00001358 }
1359
1360 // Print the LineCC
sewardj8badbaa2007-05-08 09:20:25 +00001361 if (clo_cache_sim && clo_branch_sim) {
1362 VG_(sprintf)(buf, "%u %llu %llu %llu"
1363 " %llu %llu %llu"
1364 " %llu %llu %llu"
1365 " %llu %llu %llu %llu\n",
1366 lineCC->loc.line,
1367 lineCC->Ir.a, lineCC->Ir.m1, lineCC->Ir.m2,
1368 lineCC->Dr.a, lineCC->Dr.m1, lineCC->Dr.m2,
1369 lineCC->Dw.a, lineCC->Dw.m1, lineCC->Dw.m2,
1370 lineCC->Bc.b, lineCC->Bc.mp,
1371 lineCC->Bi.b, lineCC->Bi.mp);
1372 }
1373 else if (clo_cache_sim && !clo_branch_sim) {
1374 VG_(sprintf)(buf, "%u %llu %llu %llu"
1375 " %llu %llu %llu"
1376 " %llu %llu %llu\n",
1377 lineCC->loc.line,
1378 lineCC->Ir.a, lineCC->Ir.m1, lineCC->Ir.m2,
1379 lineCC->Dr.a, lineCC->Dr.m1, lineCC->Dr.m2,
1380 lineCC->Dw.a, lineCC->Dw.m1, lineCC->Dw.m2);
1381 }
1382 else if (!clo_cache_sim && clo_branch_sim) {
1383 VG_(sprintf)(buf, "%u %llu"
1384 " %llu %llu %llu %llu\n",
1385 lineCC->loc.line,
1386 lineCC->Ir.a,
1387 lineCC->Bc.b, lineCC->Bc.mp,
1388 lineCC->Bi.b, lineCC->Bi.mp);
1389 }
1390 else
1391 tl_assert(0);
1392
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;
1398 Ir_total.m2 += lineCC->Ir.m2;
1399 Dr_total.a += lineCC->Dr.a;
1400 Dr_total.m1 += lineCC->Dr.m1;
1401 Dr_total.m2 += lineCC->Dr.m2;
1402 Dw_total.a += lineCC->Dw.a;
1403 Dw_total.m1 += lineCC->Dw.m1;
1404 Dw_total.m2 += lineCC->Dw.m2;
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",
1421 Ir_total.a, Ir_total.m1, Ir_total.m2,
1422 Dr_total.a, Dr_total.m1, Dr_total.m2,
1423 Dw_total.a, Dw_total.m1, Dw_total.m2,
1424 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",
1432 Ir_total.a, Ir_total.m1, Ir_total.m2,
1433 Dr_total.a, Dr_total.m1, Dr_total.m2,
1434 Dw_total.a, Dw_total.m1, Dw_total.m2);
1435 }
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 }
1444 else
1445 tl_assert(0);
1446
njn4f9c9342002-04-29 16:03:24 +00001447 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1448 VG_(close)(fd);
1449}
1450
njn607adfc2003-09-30 14:15:44 +00001451static UInt ULong_width(ULong n)
njn4f9c9342002-04-29 16:03:24 +00001452{
njn607adfc2003-09-30 14:15:44 +00001453 UInt w = 0;
1454 while (n > 0) {
1455 n = n / 10;
1456 w++;
njn4f9c9342002-04-29 16:03:24 +00001457 }
sewardj46c59b12005-11-01 02:20:19 +00001458 if (w == 0) w = 1;
njn607adfc2003-09-30 14:15:44 +00001459 return w + (w-1)/3; // add space for commas
njn4f9c9342002-04-29 16:03:24 +00001460}
1461
njn51d827b2005-05-09 01:02:08 +00001462static void cg_fini(Int exitcode)
njn4f9c9342002-04-29 16:03:24 +00001463{
njn1baf7db2006-04-18 22:34:48 +00001464 static Char buf1[128], buf2[128], buf3[128], buf4[123], fmt[128];
njn607adfc2003-09-30 14:15:44 +00001465
sewardj8badbaa2007-05-08 09:20:25 +00001466 CacheCC D_total;
1467 BranchCC B_total;
njn1d021fa2002-05-02 13:56:34 +00001468 ULong L2_total_m, L2_total_mr, L2_total_mw,
1469 L2_total, L2_total_r, L2_total_w;
sewardj8badbaa2007-05-08 09:20:25 +00001470 Int l1, l2, l3, l4;
njn4f9c9342002-04-29 16:03:24 +00001471 Int p;
1472
sewardj8badbaa2007-05-08 09:20:25 +00001473 /* Running with both cache and branch simulation disabled is not
1474 allowed (checked during command line option processing). */
1475 tl_assert(clo_cache_sim || clo_branch_sim);
1476
nethercote9313ac42004-07-06 21:54:20 +00001477 fprint_CC_table_and_calc_totals();
njn4f9c9342002-04-29 16:03:24 +00001478
njn7cf0bd32002-06-08 13:36:03 +00001479 if (VG_(clo_verbosity) == 0)
1480 return;
1481
njn4f9c9342002-04-29 16:03:24 +00001482 /* I cache results. Use the I_refs value to determine the first column
1483 * width. */
njn607adfc2003-09-30 14:15:44 +00001484 l1 = ULong_width(Ir_total.a);
1485 l2 = ULong_width(Dr_total.a);
1486 l3 = ULong_width(Dw_total.a);
sewardj8badbaa2007-05-08 09:20:25 +00001487 l4 = ULong_width(Bc_total.b + Bi_total.b);
njn4f9c9342002-04-29 16:03:24 +00001488
njn607adfc2003-09-30 14:15:44 +00001489 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001490 VG_(sprintf)(fmt, "%%s %%,%dllu", l1);
njnd3bef4f2005-10-15 17:46:18 +00001491
sewardj8badbaa2007-05-08 09:20:25 +00001492 /* Always print this */
njn607adfc2003-09-30 14:15:44 +00001493 VG_(message)(Vg_UserMsg, fmt, "I refs: ", Ir_total.a);
njn4f9c9342002-04-29 16:03:24 +00001494
sewardj8badbaa2007-05-08 09:20:25 +00001495 /* If cache profiling is enabled, show D access numbers and all
1496 miss numbers */
1497 if (clo_cache_sim) {
1498 VG_(message)(Vg_UserMsg, fmt, "I1 misses: ", Ir_total.m1);
1499 VG_(message)(Vg_UserMsg, fmt, "L2i misses: ", Ir_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001500
sewardj8badbaa2007-05-08 09:20:25 +00001501 p = 100;
njnd3bef4f2005-10-15 17:46:18 +00001502
sewardj8badbaa2007-05-08 09:20:25 +00001503 if (0 == Ir_total.a) Ir_total.a = 1;
1504 VG_(percentify)(Ir_total.m1, Ir_total.a, 2, l1+1, buf1);
1505 VG_(message)(Vg_UserMsg, "I1 miss rate: %s", buf1);
njn4f9c9342002-04-29 16:03:24 +00001506
sewardj8badbaa2007-05-08 09:20:25 +00001507 VG_(percentify)(Ir_total.m2, Ir_total.a, 2, l1+1, buf1);
1508 VG_(message)(Vg_UserMsg, "L2i miss rate: %s", buf1);
1509 VG_(message)(Vg_UserMsg, "");
njnd3bef4f2005-10-15 17:46:18 +00001510
sewardj8badbaa2007-05-08 09:20:25 +00001511 /* D cache results. Use the D_refs.rd and D_refs.wr values to
1512 * determine the width of columns 2 & 3. */
1513 D_total.a = Dr_total.a + Dw_total.a;
1514 D_total.m1 = Dr_total.m1 + Dw_total.m1;
1515 D_total.m2 = Dr_total.m2 + Dw_total.m2;
njn4f9c9342002-04-29 16:03:24 +00001516
sewardj8badbaa2007-05-08 09:20:25 +00001517 /* Make format string, getting width right for numbers */
1518 VG_(sprintf)(fmt, "%%s %%,%dllu (%%,%dllu rd + %%,%dllu wr)", l1, l2, l3);
njn4f9c9342002-04-29 16:03:24 +00001519
sewardj8badbaa2007-05-08 09:20:25 +00001520 VG_(message)(Vg_UserMsg, fmt, "D refs: ",
1521 D_total.a, Dr_total.a, Dw_total.a);
1522 VG_(message)(Vg_UserMsg, fmt, "D1 misses: ",
1523 D_total.m1, Dr_total.m1, Dw_total.m1);
1524 VG_(message)(Vg_UserMsg, fmt, "L2d misses: ",
1525 D_total.m2, Dr_total.m2, Dw_total.m2);
njnd3bef4f2005-10-15 17:46:18 +00001526
sewardj8badbaa2007-05-08 09:20:25 +00001527 p = 10;
njn4f9c9342002-04-29 16:03:24 +00001528
sewardj8badbaa2007-05-08 09:20:25 +00001529 if (0 == D_total.a) D_total.a = 1;
1530 if (0 == Dr_total.a) Dr_total.a = 1;
1531 if (0 == Dw_total.a) Dw_total.a = 1;
1532 VG_(percentify)( D_total.m1, D_total.a, 1, l1+1, buf1);
1533 VG_(percentify)(Dr_total.m1, Dr_total.a, 1, l2+1, buf2);
1534 VG_(percentify)(Dw_total.m1, Dw_total.a, 1, l3+1, buf3);
1535 VG_(message)(Vg_UserMsg, "D1 miss rate: %s (%s + %s )", buf1, buf2,buf3);
njn4f9c9342002-04-29 16:03:24 +00001536
sewardj8badbaa2007-05-08 09:20:25 +00001537 VG_(percentify)( D_total.m2, D_total.a, 1, l1+1, buf1);
1538 VG_(percentify)(Dr_total.m2, Dr_total.a, 1, l2+1, buf2);
1539 VG_(percentify)(Dw_total.m2, Dw_total.a, 1, l3+1, buf3);
1540 VG_(message)(Vg_UserMsg, "L2d miss rate: %s (%s + %s )", buf1, buf2,buf3);
1541 VG_(message)(Vg_UserMsg, "");
njn1d021fa2002-05-02 13:56:34 +00001542
sewardj8badbaa2007-05-08 09:20:25 +00001543 /* L2 overall results */
njn1d021fa2002-05-02 13:56:34 +00001544
sewardj8badbaa2007-05-08 09:20:25 +00001545 L2_total = Dr_total.m1 + Dw_total.m1 + Ir_total.m1;
1546 L2_total_r = Dr_total.m1 + Ir_total.m1;
1547 L2_total_w = Dw_total.m1;
1548 VG_(message)(Vg_UserMsg, fmt, "L2 refs: ",
1549 L2_total, L2_total_r, L2_total_w);
njn4f9c9342002-04-29 16:03:24 +00001550
sewardj8badbaa2007-05-08 09:20:25 +00001551 L2_total_m = Dr_total.m2 + Dw_total.m2 + Ir_total.m2;
1552 L2_total_mr = Dr_total.m2 + Ir_total.m2;
1553 L2_total_mw = Dw_total.m2;
1554 VG_(message)(Vg_UserMsg, fmt, "L2 misses: ",
1555 L2_total_m, L2_total_mr, L2_total_mw);
njnd3bef4f2005-10-15 17:46:18 +00001556
sewardj8badbaa2007-05-08 09:20:25 +00001557 VG_(percentify)(L2_total_m, (Ir_total.a + D_total.a), 1, l1+1, buf1);
1558 VG_(percentify)(L2_total_mr, (Ir_total.a + Dr_total.a), 1, l2+1, buf2);
1559 VG_(percentify)(L2_total_mw, Dw_total.a, 1, l3+1, buf3);
1560 VG_(message)(Vg_UserMsg, "L2 miss rate: %s (%s + %s )", buf1, buf2,buf3);
1561 }
1562
1563 /* If branch profiling is enabled, show branch overall results. */
1564 if (clo_branch_sim) {
1565 /* Make format string, getting width right for numbers */
1566 VG_(sprintf)(fmt, "%%s %%,%dllu (%%,%dllu cond + %%,%dllu ind)", l1, l2, l3);
1567
1568 if (0 == Bc_total.b) Bc_total.b = 1;
1569 if (0 == Bi_total.b) Bi_total.b = 1;
1570 B_total.b = Bc_total.b + Bi_total.b;
1571 B_total.mp = Bc_total.mp + Bi_total.mp;
1572
1573 VG_(message)(Vg_UserMsg, "");
1574 VG_(message)(Vg_UserMsg, fmt, "Branches: ",
1575 B_total.b, Bc_total.b, Bi_total.b);
1576
1577 VG_(message)(Vg_UserMsg, fmt, "Mispredicts: ",
1578 B_total.mp, Bc_total.mp, Bi_total.mp);
1579
1580 VG_(percentify)(B_total.mp, B_total.b, 1, l1+1, buf1);
1581 VG_(percentify)(Bc_total.mp, Bc_total.b, 1, l2+1, buf2);
1582 VG_(percentify)(Bi_total.mp, Bi_total.b, 1, l3+1, buf3);
1583
1584 VG_(message)(Vg_UserMsg, "Mispred rate: %s (%s + %s )", buf1, buf2,buf3);
1585 }
njn4f9c9342002-04-29 16:03:24 +00001586
nethercote9313ac42004-07-06 21:54:20 +00001587 // Various stats
njn4f9c9342002-04-29 16:03:24 +00001588 if (VG_(clo_verbosity) > 1) {
njn1baf7db2006-04-18 22:34:48 +00001589 Int debug_lookups = full_debugs + fn_debugs +
1590 file_line_debugs + no_debugs;
njnd3bef4f2005-10-15 17:46:18 +00001591
njn1baf7db2006-04-18 22:34:48 +00001592 VG_(message)(Vg_DebugMsg, "");
1593 VG_(message)(Vg_DebugMsg, "cachegrind: distinct files: %d", distinct_files);
1594 VG_(message)(Vg_DebugMsg, "cachegrind: distinct fns: %d", distinct_fns);
1595 VG_(message)(Vg_DebugMsg, "cachegrind: distinct lines: %d", distinct_lines);
1596 VG_(message)(Vg_DebugMsg, "cachegrind: distinct instrs:%d", distinct_instrs);
1597 VG_(message)(Vg_DebugMsg, "cachegrind: debug lookups : %d", debug_lookups);
1598
1599 VG_(percentify)(full_debugs, debug_lookups, 1, 6, buf1);
1600 VG_(percentify)(file_line_debugs, debug_lookups, 1, 6, buf2);
1601 VG_(percentify)(fn_debugs, debug_lookups, 1, 6, buf3);
1602 VG_(percentify)(no_debugs, debug_lookups, 1, 6, buf4);
1603 VG_(message)(Vg_DebugMsg, "cachegrind: with full info:%s (%d)",
1604 buf1, full_debugs);
1605 VG_(message)(Vg_DebugMsg, "cachegrind: with file/line info:%s (%d)",
1606 buf2, file_line_debugs);
1607 VG_(message)(Vg_DebugMsg, "cachegrind: with fn name info:%s (%d)",
1608 buf3, fn_debugs);
1609 VG_(message)(Vg_DebugMsg, "cachegrind: with zero info:%s (%d)",
1610 buf4, no_debugs);
1611
1612 VG_(message)(Vg_DebugMsg, "cachegrind: string table size: %u",
njne2a9ad32007-09-17 05:30:48 +00001613 VG_(OSetGen_Size)(stringTable));
njn1baf7db2006-04-18 22:34:48 +00001614 VG_(message)(Vg_DebugMsg, "cachegrind: CC table size: %u",
njne2a9ad32007-09-17 05:30:48 +00001615 VG_(OSetGen_Size)(CC_table));
njn1baf7db2006-04-18 22:34:48 +00001616 VG_(message)(Vg_DebugMsg, "cachegrind: InstrInfo table size: %u",
njne2a9ad32007-09-17 05:30:48 +00001617 VG_(OSetGen_Size)(instrInfoTable));
njn4f9c9342002-04-29 16:03:24 +00001618 }
njn4f9c9342002-04-29 16:03:24 +00001619}
1620
nethercote9313ac42004-07-06 21:54:20 +00001621/*--------------------------------------------------------------------*/
1622/*--- Discarding BB info ---*/
1623/*--------------------------------------------------------------------*/
sewardj18d75132002-05-16 11:06:21 +00001624
sewardja3a29a52005-10-12 16:16:03 +00001625// Called when a translation is removed from the translation cache for
1626// any reason at all: to free up space, because the guest code was
1627// unmapped or modified, or for any arbitrary reason.
sewardj4ba057c2005-10-18 12:04:18 +00001628static
sewardj0b9d74a2006-12-24 02:24:11 +00001629void cg_discard_superblock_info ( Addr64 orig_addr64, VexGuestExtents vge )
sewardj18d75132002-05-16 11:06:21 +00001630{
sewardj0b9d74a2006-12-24 02:24:11 +00001631 SB_info* sbInfo;
sewardj3a384b32006-01-22 01:12:51 +00001632 Addr orig_addr = (Addr)vge.base[0];
njn4294fd42002-06-05 14:41:10 +00001633
sewardj5155dec2005-10-12 10:09:23 +00001634 tl_assert(vge.n_used > 0);
1635
1636 if (DEBUG_CG)
sewardj4ba057c2005-10-18 12:04:18 +00001637 VG_(printf)( "discard_basic_block_info: %p, %p, %llu\n",
1638 (void*)(Addr)orig_addr,
sewardj5155dec2005-10-12 10:09:23 +00001639 (void*)(Addr)vge.base[0], (ULong)vge.len[0]);
njn4294fd42002-06-05 14:41:10 +00001640
sewardj4ba057c2005-10-18 12:04:18 +00001641 // Get BB info, remove from table, free BB info. Simple! Note that we
1642 // use orig_addr, not the first instruction address in vge.
njne2a9ad32007-09-17 05:30:48 +00001643 sbInfo = VG_(OSetGen_Remove)(instrInfoTable, &orig_addr);
sewardj0b9d74a2006-12-24 02:24:11 +00001644 tl_assert(NULL != sbInfo);
njne2a9ad32007-09-17 05:30:48 +00001645 VG_(OSetGen_FreeNode)(instrInfoTable, sbInfo);
sewardj18d75132002-05-16 11:06:21 +00001646}
1647
1648/*--------------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001649/*--- Command line processing ---*/
1650/*--------------------------------------------------------------------*/
1651
njn0103de52005-10-10 16:49:01 +00001652static void parse_cache_opt ( cache_t* cache, Char* opt )
njn25e49d8e72002-09-23 09:36:25 +00001653{
njn0103de52005-10-10 16:49:01 +00001654 Int i = 0, i2, i3;
njn25e49d8e72002-09-23 09:36:25 +00001655
nethercote9313ac42004-07-06 21:54:20 +00001656 // Option argument looks like "65536,2,64".
1657 // Find commas, replace with NULs to make three independent
1658 // strings, then extract numbers, put NULs back. Yuck.
njn25e49d8e72002-09-23 09:36:25 +00001659 while (VG_(isdigit)(opt[i])) i++;
1660 if (',' == opt[i]) {
1661 opt[i++] = '\0';
1662 i2 = i;
1663 } else goto bad;
1664 while (VG_(isdigit)(opt[i])) i++;
1665 if (',' == opt[i]) {
1666 opt[i++] = '\0';
1667 i3 = i;
1668 } else goto bad;
1669 while (VG_(isdigit)(opt[i])) i++;
1670 if ('\0' != opt[i]) goto bad;
1671
nethercote9313ac42004-07-06 21:54:20 +00001672 cache->size = (Int)VG_(atoll)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001673 cache->assoc = (Int)VG_(atoll)(opt + i2);
1674 cache->line_size = (Int)VG_(atoll)(opt + i3);
1675
nethercote9313ac42004-07-06 21:54:20 +00001676 opt[i2-1] = ',';
1677 opt[i3-1] = ',';
njn25e49d8e72002-09-23 09:36:25 +00001678 return;
1679
1680 bad:
sewardj6893d652006-10-15 01:25:13 +00001681 VG_(err_bad_option)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001682}
1683
njn51d827b2005-05-09 01:02:08 +00001684static Bool cg_process_cmd_line_option(Char* arg)
njn25e49d8e72002-09-23 09:36:25 +00001685{
nethercote9313ac42004-07-06 21:54:20 +00001686 // 5 is length of "--I1="
njn39c86652003-05-21 10:13:39 +00001687 if (VG_CLO_STREQN(5, arg, "--I1="))
nethercote9313ac42004-07-06 21:54:20 +00001688 parse_cache_opt(&clo_I1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001689 else if (VG_CLO_STREQN(5, arg, "--D1="))
nethercote9313ac42004-07-06 21:54:20 +00001690 parse_cache_opt(&clo_D1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001691 else if (VG_CLO_STREQN(5, arg, "--L2="))
nethercote9313ac42004-07-06 21:54:20 +00001692 parse_cache_opt(&clo_L2_cache, &arg[5]);
sewardje1216cb2007-02-07 19:55:30 +00001693 else if (VG_CLO_STREQN(22, arg, "--cachegrind-out-file=")) {
1694 cachegrind_out_file_basename = &arg[22];
1695 }
sewardj8badbaa2007-05-08 09:20:25 +00001696 else VG_BOOL_CLO(arg, "--cache-sim", clo_cache_sim)
1697 else VG_BOOL_CLO(arg, "--branch-sim", clo_branch_sim)
njn25e49d8e72002-09-23 09:36:25 +00001698 else
1699 return False;
1700
1701 return True;
1702}
1703
njn51d827b2005-05-09 01:02:08 +00001704static void cg_print_usage(void)
njn25e49d8e72002-09-23 09:36:25 +00001705{
njn3e884182003-04-15 13:03:23 +00001706 VG_(printf)(
njn25e49d8e72002-09-23 09:36:25 +00001707" --I1=<size>,<assoc>,<line_size> set I1 cache manually\n"
1708" --D1=<size>,<assoc>,<line_size> set D1 cache manually\n"
njn3e884182003-04-15 13:03:23 +00001709" --L2=<size>,<assoc>,<line_size> set L2 cache manually\n"
sewardj8badbaa2007-05-08 09:20:25 +00001710" --cache-sim=yes|no [yes] collect cache stats?\n"
1711" --branch-sim=yes|no [no] collect branch prediction stats?\n"
sewardje1216cb2007-02-07 19:55:30 +00001712" --cachegrind-out-file=<file> write profile data to <file>.<pid>\n"
1713" [cachegrind.out.<pid>]\n"
njn3e884182003-04-15 13:03:23 +00001714 );
1715}
1716
njn51d827b2005-05-09 01:02:08 +00001717static void cg_print_debug_usage(void)
njn3e884182003-04-15 13:03:23 +00001718{
1719 VG_(printf)(
1720" (none)\n"
1721 );
njn25e49d8e72002-09-23 09:36:25 +00001722}
1723
1724/*--------------------------------------------------------------------*/
1725/*--- Setup ---*/
1726/*--------------------------------------------------------------------*/
1727
njn57ca7ab2005-06-21 23:44:58 +00001728static Char base_dir[VKI_PATH_MAX];
1729
sewardje1216cb2007-02-07 19:55:30 +00001730static void cg_post_clo_init(void); /* just below */
1731
njn51d827b2005-05-09 01:02:08 +00001732static void cg_pre_clo_init(void)
1733{
njn51d827b2005-05-09 01:02:08 +00001734 VG_(details_name) ("Cachegrind");
1735 VG_(details_version) (NULL);
sewardj8badbaa2007-05-08 09:20:25 +00001736 VG_(details_description) ("a cache and branch-prediction profiler");
njn51d827b2005-05-09 01:02:08 +00001737 VG_(details_copyright_author)(
sewardj9ebd6e02007-01-08 06:01:59 +00001738 "Copyright (C) 2002-2007, and GNU GPL'd, by Nicholas Nethercote et al.");
njn51d827b2005-05-09 01:02:08 +00001739 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardje8089302006-10-17 02:15:17 +00001740 VG_(details_avg_translation_sizeB) ( 500 );
njn51d827b2005-05-09 01:02:08 +00001741
1742 VG_(basic_tool_funcs) (cg_post_clo_init,
1743 cg_instrument,
1744 cg_fini);
1745
sewardj0b9d74a2006-12-24 02:24:11 +00001746 VG_(needs_superblock_discards)(cg_discard_superblock_info);
njn51d827b2005-05-09 01:02:08 +00001747 VG_(needs_command_line_options)(cg_process_cmd_line_option,
1748 cg_print_usage,
1749 cg_print_debug_usage);
sewardje1216cb2007-02-07 19:55:30 +00001750}
1751
1752static void cg_post_clo_init(void)
1753{
1754 HChar* qual = NULL;
1755 cache_t I1c, D1c, L2c;
1756 Int filename_szB;
njn51d827b2005-05-09 01:02:08 +00001757
sewardj8badbaa2007-05-08 09:20:25 +00001758 /* Can't disable both cache and branch profiling */
1759 if ((!clo_cache_sim) && (!clo_branch_sim)) {
1760 VG_(message)(Vg_DebugMsg,
1761 "ERROR: --cache-sim=no --branch-sim=no is not allowed.");
1762 VG_(message)(Vg_DebugMsg,
1763 "You must select cache profiling, or branch profiling, or both.");
1764 VG_(exit)(2);
1765 }
1766
njn51d827b2005-05-09 01:02:08 +00001767 /* Get working directory */
sewardj198f34f2007-07-09 23:13:07 +00001768 tl_assert( VG_(get_startup_wd)(base_dir, VKI_PATH_MAX) );
njn51d827b2005-05-09 01:02:08 +00001769
sewardje1216cb2007-02-07 19:55:30 +00001770 /* Do we have a --log-file-qualifier= to consider? */
1771 if (VG_(clo_log_file_qualifier)) {
1772 qual = VG_(getenv)(VG_(clo_log_file_qualifier));
1773 }
1774
1775 /* Block is big enough for
1776 dir name ++ cachegrind_out_file_basename
1777 ++ ".<pid>"
1778 ++ the log file qualifier, if in use */
1779 filename_szB
1780 = VG_(strlen)(base_dir)
1781 + 1 /* "/" */
1782 + VG_(strlen)(cachegrind_out_file_basename)
1783 + 11 /* "." <pid>, assuming sizeof(pid) <= 4 */
1784 + (qual ? (10 + VG_(strlen)(qual)) : 0)
1785 + 1; /* to guarantee checkable zero at the end */
1786
1787 tl_assert(filename_szB > 0);
1788 cachegrind_out_file
1789 = VG_(calloc)( sizeof(Char), filename_szB );
1790
1791 if (qual) {
1792 VG_(sprintf)(cachegrind_out_file, "%s/%s.%d.lfq.%s",
1793 base_dir, cachegrind_out_file_basename,
1794 VG_(getpid)(), qual);
1795 } else {
1796 VG_(sprintf)(cachegrind_out_file, "%s/%s.%d",
1797 base_dir, cachegrind_out_file_basename,
1798 VG_(getpid)());
1799 }
1800
1801 tl_assert( cachegrind_out_file[filename_szB-1] == 0 );
njn51d827b2005-05-09 01:02:08 +00001802
njne2a9ad32007-09-17 05:30:48 +00001803 CC_table =
1804 VG_(OSetGen_Create)(offsetof(LineCC, loc),
1805 cmp_CodeLoc_LineCC,
1806 VG_(malloc), VG_(free));
1807 instrInfoTable =
1808 VG_(OSetGen_Create)(/*keyOff*/0,
1809 NULL,
1810 VG_(malloc), VG_(free));
1811 stringTable =
1812 VG_(OSetGen_Create)(/*keyOff*/0,
1813 stringCmp,
1814 VG_(malloc), VG_(free));
sewardje1216cb2007-02-07 19:55:30 +00001815
1816 configure_caches(&I1c, &D1c, &L2c);
1817
1818 cachesim_I1_initcache(I1c);
1819 cachesim_D1_initcache(D1c);
1820 cachesim_L2_initcache(L2c);
njn51d827b2005-05-09 01:02:08 +00001821}
1822
sewardj45f4e7c2005-09-27 19:20:21 +00001823VG_DETERMINE_INTERFACE_VERSION(cg_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00001824
njn25e49d8e72002-09-23 09:36:25 +00001825/*--------------------------------------------------------------------*/
njnf69f9452005-07-03 17:53:11 +00001826/*--- end ---*/
sewardj18d75132002-05-16 11:06:21 +00001827/*--------------------------------------------------------------------*/
njnd3bef4f2005-10-15 17:46:18 +00001828