blob: 345a6cb45f4f4aa542d29af63c99cca4db9d6a5d [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{
193 Char** s_ptr = VG_(OSet_Lookup)(stringTable, &s);
194 if (s_ptr) {
195 return *s_ptr;
196 } else {
197 Char** s_node = VG_(OSet_AllocNode)(stringTable, sizeof(Char*));
198 *s_node = VG_(strdup)(s);
199 VG_(OSet_Insert)(stringTable, s_node);
200 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{
sewardj7cee6f92005-06-13 17:39:06 +0000211 Bool found_file_line = VG_(get_filename_linenum)(
212 instr_addr,
213 file, FILE_LEN,
214 NULL, 0, NULL,
215 line
216 );
nethercote9313ac42004-07-06 21:54:20 +0000217 Bool found_fn = VG_(get_fnname)(instr_addr, fn, FN_LEN);
njn4f9c9342002-04-29 16:03:24 +0000218
nethercote9313ac42004-07-06 21:54:20 +0000219 if (!found_file_line) {
220 VG_(strcpy)(file, "???");
221 *line = 0;
222 }
223 if (!found_fn) {
224 VG_(strcpy)(fn, "???");
225 }
226 if (found_file_line) {
njnd3bef4f2005-10-15 17:46:18 +0000227 if (found_fn) full_debugs++;
228 else file_line_debugs++;
nethercote9313ac42004-07-06 21:54:20 +0000229 } else {
njnd3bef4f2005-10-15 17:46:18 +0000230 if (found_fn) fn_debugs++;
231 else no_debugs++;
njn4f9c9342002-04-29 16:03:24 +0000232 }
233}
234
nethercote9313ac42004-07-06 21:54:20 +0000235// Do a three step traversal: by file, then fn, then line.
njnd3bef4f2005-10-15 17:46:18 +0000236// Returns a pointer to the line CC, creates a new one if necessary.
237static LineCC* get_lineCC(Addr origAddr)
nethercote9313ac42004-07-06 21:54:20 +0000238{
nethercote9313ac42004-07-06 21:54:20 +0000239 Char file[FILE_LEN], fn[FN_LEN];
240 Int line;
njnd3bef4f2005-10-15 17:46:18 +0000241 CodeLoc loc;
242 LineCC* lineCC;
nethercote9313ac42004-07-06 21:54:20 +0000243
njn6a3009b2005-03-20 00:20:06 +0000244 get_debug_info(origAddr, file, fn, &line);
nethercote9313ac42004-07-06 21:54:20 +0000245
njnd3bef4f2005-10-15 17:46:18 +0000246 loc.file = file;
247 loc.fn = fn;
248 loc.line = line;
njn4f9c9342002-04-29 16:03:24 +0000249
njnd3bef4f2005-10-15 17:46:18 +0000250 lineCC = VG_(OSet_Lookup)(CC_table, &loc);
251 if (!lineCC) {
252 // Allocate and zero a new node.
253 lineCC = VG_(OSet_AllocNode)(CC_table, sizeof(LineCC));
254 lineCC->loc.file = get_perm_string(loc.file);
255 lineCC->loc.fn = get_perm_string(loc.fn);
256 lineCC->loc.line = loc.line;
njn0a8db5c2007-04-02 03:11:41 +0000257 lineCC->Ir.a = 0;
258 lineCC->Ir.m1 = 0;
259 lineCC->Ir.m2 = 0;
260 lineCC->Dr.a = 0;
261 lineCC->Dr.m1 = 0;
262 lineCC->Dr.m2 = 0;
263 lineCC->Dw.a = 0;
264 lineCC->Dw.m1 = 0;
265 lineCC->Dw.m2 = 0;
sewardj8badbaa2007-05-08 09:20:25 +0000266 lineCC->Bc.b = 0;
267 lineCC->Bc.mp = 0;
268 lineCC->Bi.b = 0;
269 lineCC->Bi.mp = 0;
njnd3bef4f2005-10-15 17:46:18 +0000270 VG_(OSet_Insert)(CC_table, lineCC);
njn4f9c9342002-04-29 16:03:24 +0000271 }
nethercote9313ac42004-07-06 21:54:20 +0000272
njnd3bef4f2005-10-15 17:46:18 +0000273 return lineCC;
njn4f9c9342002-04-29 16:03:24 +0000274}
275
276/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +0000277/*--- Cache simulation functions ---*/
njn4f9c9342002-04-29 16:03:24 +0000278/*------------------------------------------------------------*/
279
njnaf839f52005-06-23 03:27:57 +0000280static VG_REGPARM(1)
njnd3bef4f2005-10-15 17:46:18 +0000281void log_1I_0D_cache_access(InstrInfo* n)
njn25e49d8e72002-09-23 09:36:25 +0000282{
sewardj5155dec2005-10-12 10:09:23 +0000283 //VG_(printf)("1I_0D : CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n",
284 // n, n->instr_addr, n->instr_len);
njn6a3009b2005-03-20 00:20:06 +0000285 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000286 &n->parent->Ir.m1, &n->parent->Ir.m2);
287 n->parent->Ir.a++;
njn25e49d8e72002-09-23 09:36:25 +0000288}
289
njnaf839f52005-06-23 03:27:57 +0000290static VG_REGPARM(2)
njnd3bef4f2005-10-15 17:46:18 +0000291void log_2I_0D_cache_access(InstrInfo* n, InstrInfo* n2)
njn25e49d8e72002-09-23 09:36:25 +0000292{
sewardj5155dec2005-10-12 10:09:23 +0000293 //VG_(printf)("2I_0D : CC1addr=0x%010lx, i1addr=0x%010lx, i1size=%lu\n"
294 // " CC2addr=0x%010lx, i2addr=0x%010lx, i2size=%lu\n",
295 // n, n->instr_addr, n->instr_len,
296 // n2, n2->instr_addr, n2->instr_len);
sewardj5155dec2005-10-12 10:09:23 +0000297 cachesim_I1_doref(n->instr_addr, n->instr_len,
298 &n->parent->Ir.m1, &n->parent->Ir.m2);
299 n->parent->Ir.a++;
300 cachesim_I1_doref(n2->instr_addr, n2->instr_len,
301 &n2->parent->Ir.m1, &n2->parent->Ir.m2);
302 n2->parent->Ir.a++;
sewardj5155dec2005-10-12 10:09:23 +0000303}
304
305static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000306void log_3I_0D_cache_access(InstrInfo* n, InstrInfo* n2, InstrInfo* n3)
sewardj5155dec2005-10-12 10:09:23 +0000307{
308 //VG_(printf)("3I_0D : CC1addr=0x%010lx, i1addr=0x%010lx, i1size=%lu\n"
309 // " CC2addr=0x%010lx, i2addr=0x%010lx, i2size=%lu\n"
310 // " CC3addr=0x%010lx, i3addr=0x%010lx, i3size=%lu\n",
311 // n, n->instr_addr, n->instr_len,
312 // n2, n2->instr_addr, n2->instr_len,
313 // n3, n3->instr_addr, n3->instr_len);
sewardj5155dec2005-10-12 10:09:23 +0000314 cachesim_I1_doref(n->instr_addr, n->instr_len,
315 &n->parent->Ir.m1, &n->parent->Ir.m2);
316 n->parent->Ir.a++;
317 cachesim_I1_doref(n2->instr_addr, n2->instr_len,
318 &n2->parent->Ir.m1, &n2->parent->Ir.m2);
319 n2->parent->Ir.a++;
320 cachesim_I1_doref(n3->instr_addr, n3->instr_len,
321 &n3->parent->Ir.m1, &n3->parent->Ir.m2);
322 n3->parent->Ir.a++;
sewardj5155dec2005-10-12 10:09:23 +0000323}
324
325static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000326void log_1I_1Dr_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
sewardj5155dec2005-10-12 10:09:23 +0000327{
328 //VG_(printf)("1I_1Dr: CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n"
329 // " daddr=0x%010lx, dsize=%lu\n",
330 // n, n->instr_addr, n->instr_len, data_addr, data_size);
njn6a3009b2005-03-20 00:20:06 +0000331 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000332 &n->parent->Ir.m1, &n->parent->Ir.m2);
333 n->parent->Ir.a++;
njn25e49d8e72002-09-23 09:36:25 +0000334
sewardj5155dec2005-10-12 10:09:23 +0000335 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000336 &n->parent->Dr.m1, &n->parent->Dr.m2);
337 n->parent->Dr.a++;
njn25e49d8e72002-09-23 09:36:25 +0000338}
339
sewardj5155dec2005-10-12 10:09:23 +0000340static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000341void log_1I_1Dw_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
njn25e49d8e72002-09-23 09:36:25 +0000342{
sewardj5155dec2005-10-12 10:09:23 +0000343 //VG_(printf)("1I_1Dw: CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n"
344 // " daddr=0x%010lx, dsize=%lu\n",
345 // n, n->instr_addr, n->instr_len, data_addr, data_size);
njn6a3009b2005-03-20 00:20:06 +0000346 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000347 &n->parent->Ir.m1, &n->parent->Ir.m2);
348 n->parent->Ir.a++;
349
sewardj5155dec2005-10-12 10:09:23 +0000350 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000351 &n->parent->Dw.m1, &n->parent->Dw.m2);
352 n->parent->Dw.a++;
njn25e49d8e72002-09-23 09:36:25 +0000353}
354
njnaf839f52005-06-23 03:27:57 +0000355static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000356void log_0I_1Dr_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
njn25e49d8e72002-09-23 09:36:25 +0000357{
sewardj5155dec2005-10-12 10:09:23 +0000358 //VG_(printf)("0I_1Dr: CCaddr=0x%010lx, daddr=0x%010lx, dsize=%lu\n",
359 // n, data_addr, data_size);
sewardj5155dec2005-10-12 10:09:23 +0000360 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000361 &n->parent->Dr.m1, &n->parent->Dr.m2);
362 n->parent->Dr.a++;
sewardj5155dec2005-10-12 10:09:23 +0000363}
364
365static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000366void log_0I_1Dw_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
sewardj5155dec2005-10-12 10:09:23 +0000367{
368 //VG_(printf)("0I_1Dw: CCaddr=0x%010lx, daddr=0x%010lx, dsize=%lu\n",
369 // n, data_addr, data_size);
sewardj5155dec2005-10-12 10:09:23 +0000370 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000371 &n->parent->Dw.m1, &n->parent->Dw.m2);
372 n->parent->Dw.a++;
njn25e49d8e72002-09-23 09:36:25 +0000373}
374
sewardj8badbaa2007-05-08 09:20:25 +0000375/* For branches, we consult two different predictors, one which
376 predicts taken/untaken for conditional branches, and the other
377 which predicts the branch target address for indirect branches
378 (jump-to-register style ones). */
379
380static VG_REGPARM(2)
381void log_cond_branch(InstrInfo* n, Word taken)
382{
383 //VG_(printf)("cbrnch: CCaddr=0x%010lx, taken=0x%010lx\n",
384 // n, taken);
385 n->parent->Bc.b++;
386 n->parent->Bc.mp
387 += (1 & do_cond_branch_predict(n->instr_addr, taken));
388}
389
390static VG_REGPARM(2)
391void log_ind_branch(InstrInfo* n, UWord actual_dst)
392{
393 //VG_(printf)("ibrnch: CCaddr=0x%010lx, dst=0x%010lx\n",
394 // n, actual_dst);
395 n->parent->Bi.b++;
396 n->parent->Bi.mp
397 += (1 & do_ind_branch_predict(n->instr_addr, actual_dst));
398}
399
400
nethercote9313ac42004-07-06 21:54:20 +0000401/*------------------------------------------------------------*/
sewardj5155dec2005-10-12 10:09:23 +0000402/*--- Instrumentation types and structures ---*/
403/*------------------------------------------------------------*/
404
405/* Maintain an ordered list of memory events which are outstanding, in
406 the sense that no IR has yet been generated to do the relevant
407 helper calls. The BB is scanned top to bottom and memory events
408 are added to the end of the list, merging with the most recent
409 notified event where possible (Dw immediately following Dr and
410 having the same size and EA can be merged).
411
412 This merging is done so that for architectures which have
413 load-op-store instructions (x86, amd64), the insn is treated as if
414 it makes just one memory reference (a modify), rather than two (a
415 read followed by a write at the same address).
416
417 At various points the list will need to be flushed, that is, IR
418 generated from it. That must happen before any possible exit from
419 the block (the end, or an IRStmt_Exit). Flushing also takes place
420 when there is no space to add a new event.
421
422 If we require the simulation statistics to be up to date with
423 respect to possible memory exceptions, then the list would have to
424 be flushed before each memory reference. That would however lose
425 performance by inhibiting event-merging during flushing.
426
427 Flushing the list consists of walking it start to end and emitting
428 instrumentation IR for each event, in the order in which they
429 appear. It may be possible to emit a single call for two adjacent
430 events in order to reduce the number of helper function calls made.
431 For example, it could well be profitable to handle two adjacent Ir
432 events with a single helper call. */
433
434typedef
435 IRExpr
436 IRAtom;
437
438typedef
sewardj8badbaa2007-05-08 09:20:25 +0000439 enum {
440 Ev_Ir, // Instruction read
441 Ev_Dr, // Data read
442 Ev_Dw, // Data write
443 Ev_Dm, // Data modify (read then write)
444 Ev_Bc, // branch conditional
445 Ev_Bi // branch indirect (to unknown destination)
446 }
447 EventTag;
sewardj5155dec2005-10-12 10:09:23 +0000448
449typedef
450 struct {
sewardj8badbaa2007-05-08 09:20:25 +0000451 EventTag tag;
452 InstrInfo* inode;
453 union {
454 struct {
455 } Ir;
456 struct {
457 IRAtom* ea;
458 Int szB;
459 } Dr;
460 struct {
461 IRAtom* ea;
462 Int szB;
463 } Dw;
464 struct {
465 IRAtom* ea;
466 Int szB;
467 } Dm;
468 struct {
469 IRAtom* taken; /* :: Ity_I1 */
470 } Bc;
471 struct {
472 IRAtom* dst;
473 } Bi;
474 } Ev;
sewardj5155dec2005-10-12 10:09:23 +0000475 }
476 Event;
477
sewardj8badbaa2007-05-08 09:20:25 +0000478static void init_Event ( Event* ev ) {
479 VG_(memset)(ev, 0, sizeof(Event));
480}
481
482static IRAtom* get_Event_dea ( Event* ev ) {
483 switch (ev->tag) {
484 case Ev_Dr: return ev->Ev.Dr.ea;
485 case Ev_Dw: return ev->Ev.Dw.ea;
486 case Ev_Dm: return ev->Ev.Dm.ea;
487 default: tl_assert(0);
488 }
489}
490
491static Int get_Event_dszB ( Event* ev ) {
492 switch (ev->tag) {
493 case Ev_Dr: return ev->Ev.Dr.szB;
494 case Ev_Dw: return ev->Ev.Dw.szB;
495 case Ev_Dm: return ev->Ev.Dm.szB;
496 default: tl_assert(0);
497 }
498}
499
500
sewardj5155dec2005-10-12 10:09:23 +0000501/* Up to this many unnotified events are allowed. Number is
502 arbitrary. Larger numbers allow more event merging to occur, but
503 potentially induce more spilling due to extending live ranges of
504 address temporaries. */
505#define N_EVENTS 16
506
507
508/* A struct which holds all the running state during instrumentation.
509 Mostly to avoid passing loads of parameters everywhere. */
510typedef
511 struct {
512 /* The current outstanding-memory-event list. */
513 Event events[N_EVENTS];
514 Int events_used;
515
njnd3bef4f2005-10-15 17:46:18 +0000516 /* The array of InstrInfo bins for the BB. */
sewardj0b9d74a2006-12-24 02:24:11 +0000517 SB_info* sbInfo;
sewardj5155dec2005-10-12 10:09:23 +0000518
njnd3bef4f2005-10-15 17:46:18 +0000519 /* Number InstrInfo bins 'used' so far. */
sewardj0b9d74a2006-12-24 02:24:11 +0000520 Int sbInfo_i;
sewardj5155dec2005-10-12 10:09:23 +0000521
sewardj0b9d74a2006-12-24 02:24:11 +0000522 /* The output SB being constructed. */
523 IRSB* sbOut;
sewardj5155dec2005-10-12 10:09:23 +0000524 }
525 CgState;
526
527
sewardj5155dec2005-10-12 10:09:23 +0000528/*------------------------------------------------------------*/
529/*--- Instrumentation main ---*/
nethercote9313ac42004-07-06 21:54:20 +0000530/*------------------------------------------------------------*/
531
sewardj4ba057c2005-10-18 12:04:18 +0000532// Note that origAddr is the real origAddr, not the address of the first
533// instruction in the block (they can be different due to redirection).
nethercote564b2b02004-08-07 15:54:53 +0000534static
sewardj0b9d74a2006-12-24 02:24:11 +0000535SB_info* get_SB_info(IRSB* sbIn, Addr origAddr)
nethercote9313ac42004-07-06 21:54:20 +0000536{
njn4bd67b52005-08-11 00:47:10 +0000537 Int i, n_instrs;
538 IRStmt* st;
sewardj0b9d74a2006-12-24 02:24:11 +0000539 SB_info* sbInfo;
njnd3bef4f2005-10-15 17:46:18 +0000540
sewardj0b9d74a2006-12-24 02:24:11 +0000541 // Count number of original instrs in SB
njn6a3009b2005-03-20 00:20:06 +0000542 n_instrs = 0;
sewardj0b9d74a2006-12-24 02:24:11 +0000543 for (i = 0; i < sbIn->stmts_used; i++) {
544 st = sbIn->stmts[i];
njn6a3009b2005-03-20 00:20:06 +0000545 if (Ist_IMark == st->tag) n_instrs++;
nethercote9313ac42004-07-06 21:54:20 +0000546 }
547
njnf7d26092005-10-12 16:45:17 +0000548 // Check that we don't have an entry for this BB in the instr-info table.
549 // If this assertion fails, there has been some screwup: some
550 // translations must have been discarded but Cachegrind hasn't discarded
551 // the corresponding entries in the instr-info table.
sewardj0b9d74a2006-12-24 02:24:11 +0000552 sbInfo = VG_(OSet_Lookup)(instrInfoTable, &origAddr);
553 tl_assert(NULL == sbInfo);
sewardja3a29a52005-10-12 16:16:03 +0000554
njnd3bef4f2005-10-15 17:46:18 +0000555 // BB never translated before (at this address, at least; could have
556 // been unloaded and then reloaded elsewhere in memory)
sewardj0b9d74a2006-12-24 02:24:11 +0000557 sbInfo = VG_(OSet_AllocNode)(instrInfoTable,
558 sizeof(SB_info) + n_instrs*sizeof(InstrInfo));
559 sbInfo->SB_addr = origAddr;
560 sbInfo->n_instrs = n_instrs;
561 VG_(OSet_Insert)( instrInfoTable, sbInfo );
sewardja3a29a52005-10-12 16:16:03 +0000562 distinct_instrs++;
563
sewardj0b9d74a2006-12-24 02:24:11 +0000564 return sbInfo;
nethercote9313ac42004-07-06 21:54:20 +0000565}
njn6a3009b2005-03-20 00:20:06 +0000566
nethercote9313ac42004-07-06 21:54:20 +0000567
sewardj5155dec2005-10-12 10:09:23 +0000568static void showEvent ( Event* ev )
nethercote9313ac42004-07-06 21:54:20 +0000569{
sewardj8badbaa2007-05-08 09:20:25 +0000570 switch (ev->tag) {
571 case Ev_Ir:
njnfd9f6222005-10-16 00:17:37 +0000572 VG_(printf)("Ir %p\n", ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000573 break;
sewardj8badbaa2007-05-08 09:20:25 +0000574 case Ev_Dr:
575 VG_(printf)("Dr %p %d EA=", ev->inode, ev->Ev.Dr.szB);
576 ppIRExpr(ev->Ev.Dr.ea);
sewardj5155dec2005-10-12 10:09:23 +0000577 VG_(printf)("\n");
578 break;
sewardj8badbaa2007-05-08 09:20:25 +0000579 case Ev_Dw:
580 VG_(printf)("Dw %p %d EA=", ev->inode, ev->Ev.Dw.szB);
581 ppIRExpr(ev->Ev.Dw.ea);
sewardj5155dec2005-10-12 10:09:23 +0000582 VG_(printf)("\n");
583 break;
sewardj8badbaa2007-05-08 09:20:25 +0000584 case Ev_Dm:
585 VG_(printf)("Dm %p %d EA=", ev->inode, ev->Ev.Dm.szB);
586 ppIRExpr(ev->Ev.Dm.ea);
587 VG_(printf)("\n");
588 break;
589 case Ev_Bc:
590 VG_(printf)("Bc %p GA=", ev->inode);
591 ppIRExpr(ev->Ev.Bc.taken);
592 VG_(printf)("\n");
593 break;
594 case Ev_Bi:
595 VG_(printf)("Bi %p DST=", ev->inode);
596 ppIRExpr(ev->Ev.Bi.dst);
sewardj5155dec2005-10-12 10:09:23 +0000597 VG_(printf)("\n");
598 break;
599 default:
600 tl_assert(0);
601 break;
602 }
njn6a3009b2005-03-20 00:20:06 +0000603}
604
njnfd9f6222005-10-16 00:17:37 +0000605// Reserve and initialise an InstrInfo for the first mention of a new insn.
606static
607InstrInfo* setup_InstrInfo ( CgState* cgs, Addr instr_addr, UInt instr_len )
njn6a3009b2005-03-20 00:20:06 +0000608{
njnd3bef4f2005-10-15 17:46:18 +0000609 InstrInfo* i_node;
sewardj0b9d74a2006-12-24 02:24:11 +0000610 tl_assert(cgs->sbInfo_i >= 0);
611 tl_assert(cgs->sbInfo_i < cgs->sbInfo->n_instrs);
612 i_node = &cgs->sbInfo->instrs[ cgs->sbInfo_i ];
njnfd9f6222005-10-16 00:17:37 +0000613 i_node->instr_addr = instr_addr;
614 i_node->instr_len = instr_len;
615 i_node->parent = get_lineCC(instr_addr);
sewardj0b9d74a2006-12-24 02:24:11 +0000616 cgs->sbInfo_i++;
sewardj5155dec2005-10-12 10:09:23 +0000617 return i_node;
618}
sewardj17a56bf2005-03-21 01:35:02 +0000619
sewardj17a56bf2005-03-21 01:35:02 +0000620
sewardj5155dec2005-10-12 10:09:23 +0000621/* Generate code for all outstanding memory events, and mark the queue
622 empty. Code is generated into cgs->bbOut, and this activity
sewardj0b9d74a2006-12-24 02:24:11 +0000623 'consumes' slots in cgs->sbInfo. */
njn6a3009b2005-03-20 00:20:06 +0000624
sewardj5155dec2005-10-12 10:09:23 +0000625static void flushEvents ( CgState* cgs )
626{
njnd3bef4f2005-10-15 17:46:18 +0000627 Int i, regparms;
628 Char* helperName;
629 void* helperAddr;
630 IRExpr** argv;
631 IRExpr* i_node_expr;
njnd3bef4f2005-10-15 17:46:18 +0000632 IRDirty* di;
njnc285dca2005-10-15 22:07:28 +0000633 Event* ev;
634 Event* ev2;
635 Event* ev3;
njn6a3009b2005-03-20 00:20:06 +0000636
sewardj5155dec2005-10-12 10:09:23 +0000637 i = 0;
638 while (i < cgs->events_used) {
njn6a3009b2005-03-20 00:20:06 +0000639
sewardj5155dec2005-10-12 10:09:23 +0000640 helperName = NULL;
641 helperAddr = NULL;
642 argv = NULL;
643 regparms = 0;
644
645 /* generate IR to notify event i and possibly the ones
646 immediately following it. */
647 tl_assert(i >= 0 && i < cgs->events_used);
njnc285dca2005-10-15 22:07:28 +0000648
649 ev = &cgs->events[i];
650 ev2 = ( i < cgs->events_used-1 ? &cgs->events[i+1] : NULL );
651 ev3 = ( i < cgs->events_used-2 ? &cgs->events[i+2] : NULL );
652
sewardj5155dec2005-10-12 10:09:23 +0000653 if (DEBUG_CG) {
654 VG_(printf)(" flush ");
njnc285dca2005-10-15 22:07:28 +0000655 showEvent( ev );
njn4f9c9342002-04-29 16:03:24 +0000656 }
sewardj5155dec2005-10-12 10:09:23 +0000657
njnfd9f6222005-10-16 00:17:37 +0000658 i_node_expr = mkIRExpr_HWord( (HWord)ev->inode );
sewardj5155dec2005-10-12 10:09:23 +0000659
660 /* Decide on helper fn to call and args to pass it, and advance
661 i appropriately. */
sewardj8badbaa2007-05-08 09:20:25 +0000662 switch (ev->tag) {
663 case Ev_Ir:
664 /* Merge an Ir with a following Dr/Dm. */
665 if (ev2 && (ev2->tag == Ev_Dr || ev2->tag == Ev_Dm)) {
666 /* Why is this true? It's because we're merging an Ir
667 with a following Dr or Dm. The Ir derives from the
668 instruction's IMark and the Dr/Dm from data
669 references which follow it. In short it holds
670 because each insn starts with an IMark, hence an
671 Ev_Ir, and so these Dr/Dm must pertain to the
672 immediately preceding Ir. Same applies to analogous
673 assertions in the subsequent cases. */
njnfd9f6222005-10-16 00:17:37 +0000674 tl_assert(ev2->inode == ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000675 helperName = "log_1I_1Dr_cache_access";
676 helperAddr = &log_1I_1Dr_cache_access;
677 argv = mkIRExprVec_3( i_node_expr,
sewardj8badbaa2007-05-08 09:20:25 +0000678 get_Event_dea(ev2),
679 mkIRExpr_HWord( get_Event_dszB(ev2) ) );
sewardj5155dec2005-10-12 10:09:23 +0000680 regparms = 3;
681 i += 2;
682 }
sewardj8badbaa2007-05-08 09:20:25 +0000683 /* Merge an Ir with a following Dw. */
sewardj5155dec2005-10-12 10:09:23 +0000684 else
sewardj8badbaa2007-05-08 09:20:25 +0000685 if (ev2 && ev2->tag == Ev_Dw) {
njnfd9f6222005-10-16 00:17:37 +0000686 tl_assert(ev2->inode == ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000687 helperName = "log_1I_1Dw_cache_access";
688 helperAddr = &log_1I_1Dw_cache_access;
689 argv = mkIRExprVec_3( i_node_expr,
sewardj8badbaa2007-05-08 09:20:25 +0000690 get_Event_dea(ev2),
691 mkIRExpr_HWord( get_Event_dszB(ev2) ) );
sewardj5155dec2005-10-12 10:09:23 +0000692 regparms = 3;
693 i += 2;
694 }
sewardj8badbaa2007-05-08 09:20:25 +0000695 /* Merge an Ir with two following Irs. */
sewardj5155dec2005-10-12 10:09:23 +0000696 else
sewardj8badbaa2007-05-08 09:20:25 +0000697 if (ev2 && ev3 && ev2->tag == Ev_Ir && ev3->tag == Ev_Ir)
njnc285dca2005-10-15 22:07:28 +0000698 {
sewardj5155dec2005-10-12 10:09:23 +0000699 helperName = "log_3I_0D_cache_access";
700 helperAddr = &log_3I_0D_cache_access;
njnfd9f6222005-10-16 00:17:37 +0000701 argv = mkIRExprVec_3( i_node_expr,
702 mkIRExpr_HWord( (HWord)ev2->inode ),
703 mkIRExpr_HWord( (HWord)ev3->inode ) );
sewardj5155dec2005-10-12 10:09:23 +0000704 regparms = 3;
705 i += 3;
706 }
sewardj8badbaa2007-05-08 09:20:25 +0000707 /* Merge an Ir with one following Ir. */
sewardj5155dec2005-10-12 10:09:23 +0000708 else
sewardj8badbaa2007-05-08 09:20:25 +0000709 if (ev2 && ev2->tag == Ev_Ir) {
sewardj5155dec2005-10-12 10:09:23 +0000710 helperName = "log_2I_0D_cache_access";
711 helperAddr = &log_2I_0D_cache_access;
njnfd9f6222005-10-16 00:17:37 +0000712 argv = mkIRExprVec_2( i_node_expr,
713 mkIRExpr_HWord( (HWord)ev2->inode ) );
sewardj5155dec2005-10-12 10:09:23 +0000714 regparms = 2;
715 i += 2;
716 }
717 /* No merging possible; emit as-is. */
718 else {
719 helperName = "log_1I_0D_cache_access";
720 helperAddr = &log_1I_0D_cache_access;
721 argv = mkIRExprVec_1( i_node_expr );
722 regparms = 1;
723 i++;
724 }
725 break;
sewardj8badbaa2007-05-08 09:20:25 +0000726 case Ev_Dr:
727 case Ev_Dm:
728 /* Data read or modify */
sewardj5155dec2005-10-12 10:09:23 +0000729 helperName = "log_0I_1Dr_cache_access";
730 helperAddr = &log_0I_1Dr_cache_access;
731 argv = mkIRExprVec_3( i_node_expr,
sewardj8badbaa2007-05-08 09:20:25 +0000732 get_Event_dea(ev),
733 mkIRExpr_HWord( get_Event_dszB(ev) ) );
sewardj5155dec2005-10-12 10:09:23 +0000734 regparms = 3;
735 i++;
736 break;
sewardj8badbaa2007-05-08 09:20:25 +0000737 case Ev_Dw:
738 /* Data write */
sewardj5155dec2005-10-12 10:09:23 +0000739 helperName = "log_0I_1Dw_cache_access";
740 helperAddr = &log_0I_1Dw_cache_access;
741 argv = mkIRExprVec_3( i_node_expr,
sewardj8badbaa2007-05-08 09:20:25 +0000742 get_Event_dea(ev),
743 mkIRExpr_HWord( get_Event_dszB(ev) ) );
sewardj5155dec2005-10-12 10:09:23 +0000744 regparms = 3;
745 i++;
746 break;
sewardj8badbaa2007-05-08 09:20:25 +0000747 case Ev_Bc:
748 /* Conditional branch */
749 helperName = "log_cond_branch";
750 helperAddr = &log_cond_branch;
751 argv = mkIRExprVec_2( i_node_expr, ev->Ev.Bc.taken );
752 regparms = 2;
753 i++;
754 break;
755 case Ev_Bi:
756 /* Branch to an unknown destination */
757 helperName = "log_ind_branch";
758 helperAddr = &log_ind_branch;
759 argv = mkIRExprVec_2( i_node_expr, ev->Ev.Bi.dst );
760 regparms = 2;
761 i++;
762 break;
sewardj5155dec2005-10-12 10:09:23 +0000763 default:
764 tl_assert(0);
765 }
766
767 /* Add the helper. */
768 tl_assert(helperName);
769 tl_assert(helperAddr);
770 tl_assert(argv);
sewardj5bb86822005-12-23 12:47:42 +0000771 di = unsafeIRDirty_0_N( regparms,
772 helperName, VG_(fnptr_to_fnentry)( helperAddr ),
773 argv );
sewardj0b9d74a2006-12-24 02:24:11 +0000774 addStmtToIRSB( cgs->sbOut, IRStmt_Dirty(di) );
njn4f9c9342002-04-29 16:03:24 +0000775 }
776
sewardj5155dec2005-10-12 10:09:23 +0000777 cgs->events_used = 0;
njn4f9c9342002-04-29 16:03:24 +0000778}
njn14d01ce2004-11-26 11:30:14 +0000779
njnfd9f6222005-10-16 00:17:37 +0000780static void addEvent_Ir ( CgState* cgs, InstrInfo* inode )
sewardj5155dec2005-10-12 10:09:23 +0000781{
782 Event* evt;
sewardj5155dec2005-10-12 10:09:23 +0000783 if (cgs->events_used == N_EVENTS)
784 flushEvents(cgs);
785 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
786 evt = &cgs->events[cgs->events_used];
sewardj8badbaa2007-05-08 09:20:25 +0000787 init_Event(evt);
788 evt->tag = Ev_Ir;
njnfd9f6222005-10-16 00:17:37 +0000789 evt->inode = inode;
sewardj5155dec2005-10-12 10:09:23 +0000790 cgs->events_used++;
791}
792
njnfd9f6222005-10-16 00:17:37 +0000793static
794void addEvent_Dr ( CgState* cgs, InstrInfo* inode, Int datasize, IRAtom* ea )
sewardj5155dec2005-10-12 10:09:23 +0000795{
njnfd9f6222005-10-16 00:17:37 +0000796 Event* evt;
sewardj5155dec2005-10-12 10:09:23 +0000797 tl_assert(isIRAtom(ea));
njnfd9f6222005-10-16 00:17:37 +0000798 tl_assert(datasize >= 1 && datasize <= MIN_LINE_SIZE);
sewardj8badbaa2007-05-08 09:20:25 +0000799 if (!clo_cache_sim)
800 return;
njnfd9f6222005-10-16 00:17:37 +0000801 if (cgs->events_used == N_EVENTS)
802 flushEvents(cgs);
803 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
804 evt = &cgs->events[cgs->events_used];
sewardj8badbaa2007-05-08 09:20:25 +0000805 init_Event(evt);
806 evt->tag = Ev_Dr;
807 evt->inode = inode;
808 evt->Ev.Dr.szB = datasize;
809 evt->Ev.Dr.ea = ea;
njnfd9f6222005-10-16 00:17:37 +0000810 cgs->events_used++;
811}
sewardj5155dec2005-10-12 10:09:23 +0000812
njnfd9f6222005-10-16 00:17:37 +0000813static
814void addEvent_Dw ( CgState* cgs, InstrInfo* inode, Int datasize, IRAtom* ea )
815{
816 Event* lastEvt;
817 Event* evt;
818
819 tl_assert(isIRAtom(ea));
820 tl_assert(datasize >= 1 && datasize <= MIN_LINE_SIZE);
821
sewardj8badbaa2007-05-08 09:20:25 +0000822 if (!clo_cache_sim)
823 return;
824
njnfd9f6222005-10-16 00:17:37 +0000825 /* Is it possible to merge this write with the preceding read? */
826 lastEvt = &cgs->events[cgs->events_used-1];
sewardj5155dec2005-10-12 10:09:23 +0000827 if (cgs->events_used > 0
sewardj8badbaa2007-05-08 09:20:25 +0000828 && lastEvt->tag == Ev_Dr
829 && lastEvt->Ev.Dr.szB == datasize
830 && lastEvt->inode == inode
831 && eqIRAtom(lastEvt->Ev.Dr.ea, ea))
njnfd9f6222005-10-16 00:17:37 +0000832 {
sewardj8badbaa2007-05-08 09:20:25 +0000833 lastEvt->tag = Ev_Dm;
sewardj5155dec2005-10-12 10:09:23 +0000834 return;
835 }
836
837 /* No. Add as normal. */
838 if (cgs->events_used == N_EVENTS)
839 flushEvents(cgs);
840 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
njnfd9f6222005-10-16 00:17:37 +0000841 evt = &cgs->events[cgs->events_used];
sewardj8badbaa2007-05-08 09:20:25 +0000842 init_Event(evt);
843 evt->tag = Ev_Dw;
844 evt->inode = inode;
845 evt->Ev.Dw.szB = datasize;
846 evt->Ev.Dw.ea = ea;
847 cgs->events_used++;
848}
849
850static
851void addEvent_Bc ( CgState* cgs, InstrInfo* inode, IRAtom* guard )
852{
853 Event* evt;
854 tl_assert(isIRAtom(guard));
855 tl_assert(typeOfIRExpr(cgs->sbOut->tyenv, guard)
856 == (sizeof(HWord)==4 ? Ity_I32 : Ity_I64));
857 if (!clo_branch_sim)
858 return;
859 if (cgs->events_used == N_EVENTS)
860 flushEvents(cgs);
861 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
862 evt = &cgs->events[cgs->events_used];
863 init_Event(evt);
864 evt->tag = Ev_Bc;
865 evt->inode = inode;
866 evt->Ev.Bc.taken = guard;
867 cgs->events_used++;
868}
869
870static
871void addEvent_Bi ( CgState* cgs, InstrInfo* inode, IRAtom* whereTo )
872{
873 Event* evt;
874 tl_assert(isIRAtom(whereTo));
875 tl_assert(typeOfIRExpr(cgs->sbOut->tyenv, whereTo)
876 == (sizeof(HWord)==4 ? Ity_I32 : Ity_I64));
877 if (!clo_branch_sim)
878 return;
879 if (cgs->events_used == N_EVENTS)
880 flushEvents(cgs);
881 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
882 evt = &cgs->events[cgs->events_used];
883 init_Event(evt);
884 evt->tag = Ev_Bi;
885 evt->inode = inode;
886 evt->Ev.Bi.dst = whereTo;
sewardj5155dec2005-10-12 10:09:23 +0000887 cgs->events_used++;
888}
889
890////////////////////////////////////////////////////////////
891
892
sewardj4ba057c2005-10-18 12:04:18 +0000893static
sewardj0b9d74a2006-12-24 02:24:11 +0000894IRSB* cg_instrument ( VgCallbackClosure* closure,
895 IRSB* sbIn,
sewardj461df9c2006-01-17 02:06:39 +0000896 VexGuestLayout* layout,
897 VexGuestExtents* vge,
sewardj4ba057c2005-10-18 12:04:18 +0000898 IRType gWordTy, IRType hWordTy )
njn14d01ce2004-11-26 11:30:14 +0000899{
njnfd9f6222005-10-16 00:17:37 +0000900 Int i, isize;
sewardj5155dec2005-10-12 10:09:23 +0000901 IRStmt* st;
902 Addr64 cia; /* address of current insn */
903 CgState cgs;
sewardj0b9d74a2006-12-24 02:24:11 +0000904 IRTypeEnv* tyenv = sbIn->tyenv;
njnfd9f6222005-10-16 00:17:37 +0000905 InstrInfo* curr_inode = NULL;
sewardj5155dec2005-10-12 10:09:23 +0000906
sewardjd54babf2005-03-21 00:55:49 +0000907 if (gWordTy != hWordTy) {
908 /* We don't currently support this case. */
909 VG_(tool_panic)("host/guest word size mismatch");
910 }
911
sewardj0b9d74a2006-12-24 02:24:11 +0000912 // Set up new SB
913 cgs.sbOut = deepCopyIRSBExceptStmts(sbIn);
njn6a3009b2005-03-20 00:20:06 +0000914
sewardja9f538c2005-10-23 12:06:55 +0000915 // Copy verbatim any IR preamble preceding the first IMark
njn6a3009b2005-03-20 00:20:06 +0000916 i = 0;
sewardj0b9d74a2006-12-24 02:24:11 +0000917 while (i < sbIn->stmts_used && sbIn->stmts[i]->tag != Ist_IMark) {
918 addStmtToIRSB( cgs.sbOut, sbIn->stmts[i] );
sewardja9f538c2005-10-23 12:06:55 +0000919 i++;
920 }
921
922 // Get the first statement, and initial cia from it
sewardj0b9d74a2006-12-24 02:24:11 +0000923 tl_assert(sbIn->stmts_used > 0);
924 tl_assert(i < sbIn->stmts_used);
925 st = sbIn->stmts[i];
njn6a3009b2005-03-20 00:20:06 +0000926 tl_assert(Ist_IMark == st->tag);
sewardj8badbaa2007-05-08 09:20:25 +0000927
928 cia = st->Ist.IMark.addr;
929 isize = st->Ist.IMark.len;
930 // If Vex fails to decode an instruction, the size will be zero.
931 // Pretend otherwise.
932 if (isize == 0) isize = VG_MIN_INSTR_SZB;
njn6a3009b2005-03-20 00:20:06 +0000933
sewardj5155dec2005-10-12 10:09:23 +0000934 // Set up running state and get block info
sewardj3a384b32006-01-22 01:12:51 +0000935 tl_assert(closure->readdr == vge->base[0]);
sewardj5155dec2005-10-12 10:09:23 +0000936 cgs.events_used = 0;
sewardj0b9d74a2006-12-24 02:24:11 +0000937 cgs.sbInfo = get_SB_info(sbIn, (Addr)closure->readdr);
938 cgs.sbInfo_i = 0;
njn6a3009b2005-03-20 00:20:06 +0000939
sewardj5155dec2005-10-12 10:09:23 +0000940 if (DEBUG_CG)
941 VG_(printf)("\n\n---------- cg_instrument ----------\n");
njn6a3009b2005-03-20 00:20:06 +0000942
njnfd9f6222005-10-16 00:17:37 +0000943 // Traverse the block, initialising inodes, adding events and flushing as
944 // necessary.
sewardj0b9d74a2006-12-24 02:24:11 +0000945 for (/*use current i*/; i < sbIn->stmts_used; i++) {
njn6a3009b2005-03-20 00:20:06 +0000946
sewardj0b9d74a2006-12-24 02:24:11 +0000947 st = sbIn->stmts[i];
sewardj5155dec2005-10-12 10:09:23 +0000948 tl_assert(isFlatIRStmt(st));
njnb3507ea2005-08-02 23:07:02 +0000949
sewardj5155dec2005-10-12 10:09:23 +0000950 switch (st->tag) {
951 case Ist_NoOp:
952 case Ist_AbiHint:
953 case Ist_Put:
954 case Ist_PutI:
955 case Ist_MFence:
956 break;
njn20677cc2005-08-12 23:47:51 +0000957
sewardj5155dec2005-10-12 10:09:23 +0000958 case Ist_IMark:
njnfd9f6222005-10-16 00:17:37 +0000959 cia = st->Ist.IMark.addr;
960 isize = st->Ist.IMark.len;
961
962 // If Vex fails to decode an instruction, the size will be zero.
963 // Pretend otherwise.
964 if (isize == 0) isize = VG_MIN_INSTR_SZB;
965
njna5ad9ba2005-11-10 15:20:37 +0000966 // Sanity-check size.
967 tl_assert( (VG_MIN_INSTR_SZB <= isize && isize <= VG_MAX_INSTR_SZB)
968 || VG_CLREQ_SZB == isize );
njnfd9f6222005-10-16 00:17:37 +0000969
970 // Get space for and init the inode, record it as the current one.
971 // Subsequent Dr/Dw/Dm events from the same instruction will
972 // also use it.
973 curr_inode = setup_InstrInfo(&cgs, cia, isize);
974
975 addEvent_Ir( &cgs, curr_inode );
sewardj5155dec2005-10-12 10:09:23 +0000976 break;
977
sewardj0b9d74a2006-12-24 02:24:11 +0000978 case Ist_WrTmp: {
979 IRExpr* data = st->Ist.WrTmp.data;
sewardj5155dec2005-10-12 10:09:23 +0000980 if (data->tag == Iex_Load) {
981 IRExpr* aexpr = data->Iex.Load.addr;
sewardj5155dec2005-10-12 10:09:23 +0000982 // Note also, endianness info is ignored. I guess
983 // that's not interesting.
njnfd9f6222005-10-16 00:17:37 +0000984 addEvent_Dr( &cgs, curr_inode, sizeofIRType(data->Iex.Load.ty),
985 aexpr );
sewardj5155dec2005-10-12 10:09:23 +0000986 }
987 break;
njnb3507ea2005-08-02 23:07:02 +0000988 }
989
sewardj5155dec2005-10-12 10:09:23 +0000990 case Ist_Store: {
991 IRExpr* data = st->Ist.Store.data;
992 IRExpr* aexpr = st->Ist.Store.addr;
njnfd9f6222005-10-16 00:17:37 +0000993 addEvent_Dw( &cgs, curr_inode,
994 sizeofIRType(typeOfIRExpr(tyenv, data)), aexpr );
sewardj5155dec2005-10-12 10:09:23 +0000995 break;
996 }
njnb3507ea2005-08-02 23:07:02 +0000997
sewardj5155dec2005-10-12 10:09:23 +0000998 case Ist_Dirty: {
999 Int dataSize;
1000 IRDirty* d = st->Ist.Dirty.details;
1001 if (d->mFx != Ifx_None) {
njnfd9f6222005-10-16 00:17:37 +00001002 /* This dirty helper accesses memory. Collect the details. */
sewardj5155dec2005-10-12 10:09:23 +00001003 tl_assert(d->mAddr != NULL);
1004 tl_assert(d->mSize != 0);
1005 dataSize = d->mSize;
1006 // Large (eg. 28B, 108B, 512B on x86) data-sized
1007 // instructions will be done inaccurately, but they're
1008 // very rare and this avoids errors from hitting more
1009 // than two cache lines in the simulation.
1010 if (dataSize > MIN_LINE_SIZE)
1011 dataSize = MIN_LINE_SIZE;
1012 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
njnfd9f6222005-10-16 00:17:37 +00001013 addEvent_Dr( &cgs, curr_inode, dataSize, d->mAddr );
sewardj5155dec2005-10-12 10:09:23 +00001014 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
njnfd9f6222005-10-16 00:17:37 +00001015 addEvent_Dw( &cgs, curr_inode, dataSize, d->mAddr );
sewardj5155dec2005-10-12 10:09:23 +00001016 } else {
1017 tl_assert(d->mAddr == NULL);
1018 tl_assert(d->mSize == 0);
1019 }
1020 break;
1021 }
njn6a3009b2005-03-20 00:20:06 +00001022
sewardj8badbaa2007-05-08 09:20:25 +00001023 case Ist_Exit: {
1024 /* Stuff to widen the guard expression to a host word, so
1025 we can pass it to the branch predictor simulation
1026 functions easily. */
1027 Bool inverted;
1028 Addr64 nia, sea;
1029 IRConst* dst;
1030 IROp tyW = hWordTy;
1031 IROp widen = tyW==Ity_I32 ? Iop_1Uto32 : Iop_1Uto64;
1032 IROp opXOR = tyW==Ity_I32 ? Iop_Xor32 : Iop_Xor64;
1033 IRTemp guard1 = newIRTemp(cgs.sbOut->tyenv, Ity_I1);
1034 IRTemp guardW = newIRTemp(cgs.sbOut->tyenv, tyW);
1035 IRTemp guard = newIRTemp(cgs.sbOut->tyenv, tyW);
1036 IRExpr* one = tyW==Ity_I32 ? IRExpr_Const(IRConst_U32(1))
1037 : IRExpr_Const(IRConst_U64(1));
1038
1039 /* First we need to figure out whether the side exit got
1040 inverted by the ir optimiser. To do that, figure out
1041 the next (fallthrough) instruction's address and the
1042 side exit address and see if they are the same. */
1043 nia = cia + (Addr64)isize;
1044 if (tyW == Ity_I32)
1045 nia &= 0xFFFFFFFFULL;
1046
1047 /* Side exit address */
1048 dst = st->Ist.Exit.dst;
1049 if (tyW == Ity_I32) {
1050 tl_assert(dst->tag == Ico_U32);
1051 sea = (Addr64)(UInt)dst->Ico.U32;
1052 } else {
1053 tl_assert(tyW == Ity_I64);
1054 tl_assert(dst->tag == Ico_U64);
1055 sea = dst->Ico.U64;
1056 }
1057
1058 inverted = nia == sea;
1059
1060 /* Widen the guard expression. */
1061 addStmtToIRSB( cgs.sbOut,
1062 IRStmt_WrTmp( guard1, st->Ist.Exit.guard ));
1063 addStmtToIRSB( cgs.sbOut,
1064 IRStmt_WrTmp( guardW,
1065 IRExpr_Unop(widen,
1066 IRExpr_RdTmp(guard1))) );
1067 /* If the exit is inverted, invert the sense of the guard. */
1068 addStmtToIRSB(
1069 cgs.sbOut,
1070 IRStmt_WrTmp(
1071 guard,
1072 inverted ? IRExpr_Binop(opXOR, IRExpr_RdTmp(guardW), one)
1073 : IRExpr_RdTmp(guardW)
1074 ));
1075 /* And post the event. */
1076 addEvent_Bc( &cgs, curr_inode, IRExpr_RdTmp(guard) );
1077
sewardj5155dec2005-10-12 10:09:23 +00001078 /* We may never reach the next statement, so need to flush
1079 all outstanding transactions now. */
1080 flushEvents( &cgs );
1081 break;
sewardj8badbaa2007-05-08 09:20:25 +00001082 }
sewardj5155dec2005-10-12 10:09:23 +00001083
1084 default:
1085 tl_assert(0);
1086 break;
njnb3507ea2005-08-02 23:07:02 +00001087 }
njn6a3009b2005-03-20 00:20:06 +00001088
sewardj5155dec2005-10-12 10:09:23 +00001089 /* Copy the original statement */
sewardj0b9d74a2006-12-24 02:24:11 +00001090 addStmtToIRSB( cgs.sbOut, st );
njn6a3009b2005-03-20 00:20:06 +00001091
sewardj5155dec2005-10-12 10:09:23 +00001092 if (DEBUG_CG) {
1093 ppIRStmt(st);
1094 VG_(printf)("\n");
1095 }
1096 }
1097
sewardj8badbaa2007-05-08 09:20:25 +00001098 /* Deal with branches to unknown destinations. Except ignore ones
1099 which are function returns as we assume the return stack
1100 predictor never mispredicts. */
1101 if (sbIn->jumpkind == Ijk_Boring) {
1102 if (0) { ppIRExpr( sbIn->next ); VG_(printf)("\n"); }
1103 switch (sbIn->next->tag) {
1104 case Iex_Const:
1105 break; /* boring - branch to known address */
1106 case Iex_RdTmp:
1107 /* looks like an indirect branch (branch to unknown) */
1108 addEvent_Bi( &cgs, curr_inode, sbIn->next );
1109 break;
1110 default:
1111 /* shouldn't happen - if the incoming IR is properly
1112 flattened, should only have tmp and const cases to
1113 consider. */
1114 tl_assert(0);
1115 }
1116 }
1117
sewardj5155dec2005-10-12 10:09:23 +00001118 /* At the end of the bb. Flush outstandings. */
sewardj5155dec2005-10-12 10:09:23 +00001119 flushEvents( &cgs );
1120
sewardj5155dec2005-10-12 10:09:23 +00001121 /* done. stay sane ... */
sewardj0b9d74a2006-12-24 02:24:11 +00001122 tl_assert(cgs.sbInfo_i == cgs.sbInfo->n_instrs);
sewardj5155dec2005-10-12 10:09:23 +00001123
1124 if (DEBUG_CG) {
1125 VG_(printf)( "goto {");
sewardj0b9d74a2006-12-24 02:24:11 +00001126 ppIRJumpKind(sbIn->jumpkind);
sewardj5155dec2005-10-12 10:09:23 +00001127 VG_(printf)( "} ");
sewardj0b9d74a2006-12-24 02:24:11 +00001128 ppIRExpr( sbIn->next );
sewardj5155dec2005-10-12 10:09:23 +00001129 VG_(printf)( "}\n");
1130 }
1131
sewardj0b9d74a2006-12-24 02:24:11 +00001132 return cgs.sbOut;
njn14d01ce2004-11-26 11:30:14 +00001133}
njn4f9c9342002-04-29 16:03:24 +00001134
1135/*------------------------------------------------------------*/
nethercoteb35a8b92004-09-11 16:45:27 +00001136/*--- Cache configuration ---*/
njn4f9c9342002-04-29 16:03:24 +00001137/*------------------------------------------------------------*/
1138
sewardjb5f6f512005-03-10 23:59:00 +00001139#define UNDEFINED_CACHE { -1, -1, -1 }
njn25e49d8e72002-09-23 09:36:25 +00001140
1141static cache_t clo_I1_cache = UNDEFINED_CACHE;
1142static cache_t clo_D1_cache = UNDEFINED_CACHE;
1143static cache_t clo_L2_cache = UNDEFINED_CACHE;
1144
njn7cf0bd32002-06-08 13:36:03 +00001145/* Checks cache config is ok; makes it so if not. */
sewardj07133bf2002-06-13 10:25:56 +00001146static
njna1d1a642004-11-26 18:36:02 +00001147void check_cache(cache_t* cache, Char *name)
njn7cf0bd32002-06-08 13:36:03 +00001148{
1149 /* First check they're all powers of two */
sewardj07133bf2002-06-13 10:25:56 +00001150 if (-1 == VG_(log2)(cache->size)) {
njn7cf0bd32002-06-08 13:36:03 +00001151 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +00001152 "error: %s size of %dB not a power of two; aborting.",
1153 name, cache->size);
1154 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +00001155 }
1156
sewardj07133bf2002-06-13 10:25:56 +00001157 if (-1 == VG_(log2)(cache->assoc)) {
njn7cf0bd32002-06-08 13:36:03 +00001158 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +00001159 "error: %s associativity of %d not a power of two; aborting.",
1160 name, cache->assoc);
1161 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +00001162 }
1163
sewardj07133bf2002-06-13 10:25:56 +00001164 if (-1 == VG_(log2)(cache->line_size)) {
njn7cf0bd32002-06-08 13:36:03 +00001165 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +00001166 "error: %s line size of %dB not a power of two; aborting.",
1167 name, cache->line_size);
1168 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +00001169 }
1170
njn6a3009b2005-03-20 00:20:06 +00001171 // Then check line size >= 16 -- any smaller and a single instruction could
1172 // straddle three cache lines, which breaks a simulation assertion and is
1173 // stupid anyway.
njn7cf0bd32002-06-08 13:36:03 +00001174 if (cache->line_size < MIN_LINE_SIZE) {
1175 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +00001176 "error: %s line size of %dB too small; aborting.",
1177 name, cache->line_size);
1178 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +00001179 }
1180
1181 /* Then check cache size > line size (causes seg faults if not). */
1182 if (cache->size <= cache->line_size) {
1183 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +00001184 "error: %s cache size of %dB <= line size of %dB; aborting.",
1185 name, cache->size, cache->line_size);
1186 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +00001187 }
1188
1189 /* Then check assoc <= (size / line size) (seg faults otherwise). */
1190 if (cache->assoc > (cache->size / cache->line_size)) {
1191 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +00001192 "warning: %s associativity > (size / line size); aborting.", name);
1193 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +00001194 }
1195}
1196
sewardj07133bf2002-06-13 10:25:56 +00001197static
nethercoteb35a8b92004-09-11 16:45:27 +00001198void configure_caches(cache_t* I1c, cache_t* D1c, cache_t* L2c)
njn7cf0bd32002-06-08 13:36:03 +00001199{
nethercote9313ac42004-07-06 21:54:20 +00001200#define DEFINED(L) (-1 != L.size || -1 != L.assoc || -1 != L.line_size)
1201
nethercoteb35a8b92004-09-11 16:45:27 +00001202 Int n_clos = 0;
nethercote9313ac42004-07-06 21:54:20 +00001203
nethercoteb35a8b92004-09-11 16:45:27 +00001204 // Count how many were defined on the command line.
1205 if (DEFINED(clo_I1_cache)) { n_clos++; }
1206 if (DEFINED(clo_D1_cache)) { n_clos++; }
1207 if (DEFINED(clo_L2_cache)) { n_clos++; }
njn7cf0bd32002-06-08 13:36:03 +00001208
njna1d1a642004-11-26 18:36:02 +00001209 // Set the cache config (using auto-detection, if supported by the
1210 // architecture)
njnaf839f52005-06-23 03:27:57 +00001211 VG_(configure_caches)( I1c, D1c, L2c, (3 == n_clos) );
sewardjb1a77a42002-07-13 13:31:20 +00001212
nethercote9313ac42004-07-06 21:54:20 +00001213 // Then replace with any defined on the command line.
nethercoteb35a8b92004-09-11 16:45:27 +00001214 if (DEFINED(clo_I1_cache)) { *I1c = clo_I1_cache; }
1215 if (DEFINED(clo_D1_cache)) { *D1c = clo_D1_cache; }
1216 if (DEFINED(clo_L2_cache)) { *L2c = clo_L2_cache; }
njn7cf0bd32002-06-08 13:36:03 +00001217
nethercote9313ac42004-07-06 21:54:20 +00001218 // Then check values and fix if not acceptable.
njna1d1a642004-11-26 18:36:02 +00001219 check_cache(I1c, "I1");
1220 check_cache(D1c, "D1");
1221 check_cache(L2c, "L2");
njn7cf0bd32002-06-08 13:36:03 +00001222
1223 if (VG_(clo_verbosity) > 1) {
1224 VG_(message)(Vg_UserMsg, "Cache configuration used:");
1225 VG_(message)(Vg_UserMsg, " I1: %dB, %d-way, %dB lines",
1226 I1c->size, I1c->assoc, I1c->line_size);
1227 VG_(message)(Vg_UserMsg, " D1: %dB, %d-way, %dB lines",
1228 D1c->size, D1c->assoc, D1c->line_size);
1229 VG_(message)(Vg_UserMsg, " L2: %dB, %d-way, %dB lines",
1230 L2c->size, L2c->assoc, L2c->line_size);
1231 }
nethercote9313ac42004-07-06 21:54:20 +00001232#undef CMD_LINE_DEFINED
njn7cf0bd32002-06-08 13:36:03 +00001233}
1234
njn4f9c9342002-04-29 16:03:24 +00001235/*------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +00001236/*--- cg_fini() and related function ---*/
njn4f9c9342002-04-29 16:03:24 +00001237/*------------------------------------------------------------*/
1238
nethercote9313ac42004-07-06 21:54:20 +00001239// Total reads/writes/misses. Calculated during CC traversal at the end.
1240// All auto-zeroed.
sewardj8badbaa2007-05-08 09:20:25 +00001241static CacheCC Ir_total;
1242static CacheCC Dr_total;
1243static CacheCC Dw_total;
1244static BranchCC Bc_total;
1245static BranchCC Bi_total;
nethercote9313ac42004-07-06 21:54:20 +00001246
sewardje1216cb2007-02-07 19:55:30 +00001247// The output file base name specified by the user using the
1248// --cachegrind-out-file switch. This is combined with the
1249// process ID and optional user-supplied qualifier (from
1250// --log-file-qualifier) to produce the name stored in
1251// cachegrind_out_file.
1252static Char* cachegrind_out_file_basename = "cachegrind.out";
1253
1254// The final, completed name for the output file.
1255static Char* cachegrind_out_file = NULL;
1256
nethercote9313ac42004-07-06 21:54:20 +00001257
nethercote9313ac42004-07-06 21:54:20 +00001258static void fprint_CC_table_and_calc_totals(void)
1259{
njnd3bef4f2005-10-15 17:46:18 +00001260 Int i, fd;
sewardj92645592005-07-23 09:18:34 +00001261 SysRes sres;
njnd3bef4f2005-10-15 17:46:18 +00001262 Char buf[512], *currFile = NULL, *currFn = NULL;
1263 LineCC* lineCC;
njn4f9c9342002-04-29 16:03:24 +00001264
sewardj92645592005-07-23 09:18:34 +00001265 sres = VG_(open)(cachegrind_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
1266 VKI_S_IRUSR|VKI_S_IWUSR);
1267 if (sres.isError) {
nethercote9313ac42004-07-06 21:54:20 +00001268 // If the file can't be opened for whatever reason (conflict
1269 // between multiple cachegrinded processes?), give up now.
njnee0e6a32005-04-24 00:21:01 +00001270 VG_(message)(Vg_UserMsg,
njn02bc4b82005-05-15 17:28:26 +00001271 "error: can't open cache simulation output file '%s'",
njnee0e6a32005-04-24 00:21:01 +00001272 cachegrind_out_file );
1273 VG_(message)(Vg_UserMsg,
1274 " ... so simulation results will be missing.");
sewardj0744b6c2002-12-11 00:45:42 +00001275 return;
sewardj92645592005-07-23 09:18:34 +00001276 } else {
sewardje8089302006-10-17 02:15:17 +00001277 fd = sres.res;
sewardj0744b6c2002-12-11 00:45:42 +00001278 }
njn4f9c9342002-04-29 16:03:24 +00001279
nethercote9313ac42004-07-06 21:54:20 +00001280 // "desc:" lines (giving I1/D1/L2 cache configuration). The spaces after
1281 // the 2nd colon makes cg_annotate's output look nicer.
1282 VG_(sprintf)(buf, "desc: I1 cache: %s\n"
1283 "desc: D1 cache: %s\n"
1284 "desc: L2 cache: %s\n",
1285 I1.desc_line, D1.desc_line, L2.desc_line);
njn7cf0bd32002-06-08 13:36:03 +00001286 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njn4f9c9342002-04-29 16:03:24 +00001287
nethercote9313ac42004-07-06 21:54:20 +00001288 // "cmd:" line
njn4f9c9342002-04-29 16:03:24 +00001289 VG_(strcpy)(buf, "cmd:");
1290 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
sewardj45f4e7c2005-09-27 19:20:21 +00001291 if (VG_(args_the_exename)) {
1292 VG_(write)(fd, " ", 1);
1293 VG_(write)(fd, VG_(args_the_exename),
1294 VG_(strlen)( VG_(args_the_exename) ));
1295 }
sewardj14c7cc52007-02-25 15:08:24 +00001296 for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
1297 HChar* arg = * (HChar**) VG_(indexXA)( VG_(args_for_client), i );
1298 if (arg) {
sewardj45f4e7c2005-09-27 19:20:21 +00001299 VG_(write)(fd, " ", 1);
sewardj14c7cc52007-02-25 15:08:24 +00001300 VG_(write)(fd, arg, VG_(strlen)( arg ));
sewardj45f4e7c2005-09-27 19:20:21 +00001301 }
njn4f9c9342002-04-29 16:03:24 +00001302 }
nethercote9313ac42004-07-06 21:54:20 +00001303 // "events:" line
sewardj8badbaa2007-05-08 09:20:25 +00001304 if (clo_cache_sim && clo_branch_sim) {
1305 VG_(sprintf)(buf, "\nevents: Ir I1mr I2mr Dr D1mr D2mr Dw D1mw D2mw "
1306 "Bc Bcm Bi Bim\n");
1307 }
1308 else if (clo_cache_sim && !clo_branch_sim) {
1309 VG_(sprintf)(buf, "\nevents: Ir I1mr I2mr Dr D1mr D2mr Dw D1mw D2mw "
1310 "\n");
1311 }
1312 else if (!clo_cache_sim && clo_branch_sim) {
1313 VG_(sprintf)(buf, "\nevents: Ir "
1314 "Bc Bcm Bi Bim\n");
1315 }
1316 else
1317 tl_assert(0); /* can't happen */
1318
njn4f9c9342002-04-29 16:03:24 +00001319 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1320
njnd3bef4f2005-10-15 17:46:18 +00001321 // Traverse every lineCC
1322 VG_(OSet_ResetIter)(CC_table);
1323 while ( (lineCC = VG_(OSet_Next)(CC_table)) ) {
njn4311fe62005-12-08 23:18:50 +00001324 Bool just_hit_a_new_file = False;
njnd3bef4f2005-10-15 17:46:18 +00001325 // If we've hit a new file, print a "fl=" line. Note that because
1326 // each string is stored exactly once in the string table, we can use
1327 // pointer comparison rather than strcmp() to test for equality, which
1328 // is good because most of the time the comparisons are equal and so
njn4311fe62005-12-08 23:18:50 +00001329 // the whole strings would have to be checked.
njnd3bef4f2005-10-15 17:46:18 +00001330 if ( lineCC->loc.file != currFile ) {
1331 currFile = lineCC->loc.file;
1332 VG_(sprintf)(buf, "fl=%s\n", currFile);
njn4f9c9342002-04-29 16:03:24 +00001333 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njnd3bef4f2005-10-15 17:46:18 +00001334 distinct_files++;
njn4311fe62005-12-08 23:18:50 +00001335 just_hit_a_new_file = True;
njn4f9c9342002-04-29 16:03:24 +00001336 }
njn4311fe62005-12-08 23:18:50 +00001337 // If we've hit a new function, print a "fn=" line. We know to do
1338 // this when the function name changes, and also every time we hit a
1339 // new file (in which case the new function name might be the same as
1340 // in the old file, hence the just_hit_a_new_file test).
1341 if ( just_hit_a_new_file || lineCC->loc.fn != currFn ) {
njnd3bef4f2005-10-15 17:46:18 +00001342 currFn = lineCC->loc.fn;
1343 VG_(sprintf)(buf, "fn=%s\n", currFn);
1344 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1345 distinct_fns++;
njn4311fe62005-12-08 23:18:50 +00001346 just_hit_a_new_file = False;
njnd3bef4f2005-10-15 17:46:18 +00001347 }
1348
1349 // Print the LineCC
sewardj8badbaa2007-05-08 09:20:25 +00001350 if (clo_cache_sim && clo_branch_sim) {
1351 VG_(sprintf)(buf, "%u %llu %llu %llu"
1352 " %llu %llu %llu"
1353 " %llu %llu %llu"
1354 " %llu %llu %llu %llu\n",
1355 lineCC->loc.line,
1356 lineCC->Ir.a, lineCC->Ir.m1, lineCC->Ir.m2,
1357 lineCC->Dr.a, lineCC->Dr.m1, lineCC->Dr.m2,
1358 lineCC->Dw.a, lineCC->Dw.m1, lineCC->Dw.m2,
1359 lineCC->Bc.b, lineCC->Bc.mp,
1360 lineCC->Bi.b, lineCC->Bi.mp);
1361 }
1362 else if (clo_cache_sim && !clo_branch_sim) {
1363 VG_(sprintf)(buf, "%u %llu %llu %llu"
1364 " %llu %llu %llu"
1365 " %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 }
1371 else if (!clo_cache_sim && clo_branch_sim) {
1372 VG_(sprintf)(buf, "%u %llu"
1373 " %llu %llu %llu %llu\n",
1374 lineCC->loc.line,
1375 lineCC->Ir.a,
1376 lineCC->Bc.b, lineCC->Bc.mp,
1377 lineCC->Bi.b, lineCC->Bi.mp);
1378 }
1379 else
1380 tl_assert(0);
1381
njnd3bef4f2005-10-15 17:46:18 +00001382 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1383
1384 // Update summary stats
1385 Ir_total.a += lineCC->Ir.a;
1386 Ir_total.m1 += lineCC->Ir.m1;
1387 Ir_total.m2 += lineCC->Ir.m2;
1388 Dr_total.a += lineCC->Dr.a;
1389 Dr_total.m1 += lineCC->Dr.m1;
1390 Dr_total.m2 += lineCC->Dr.m2;
1391 Dw_total.a += lineCC->Dw.a;
1392 Dw_total.m1 += lineCC->Dw.m1;
1393 Dw_total.m2 += lineCC->Dw.m2;
sewardj8badbaa2007-05-08 09:20:25 +00001394 Bc_total.b += lineCC->Bc.b;
1395 Bc_total.mp += lineCC->Bc.mp;
1396 Bi_total.b += lineCC->Bi.b;
1397 Bi_total.mp += lineCC->Bi.mp;
njnd3bef4f2005-10-15 17:46:18 +00001398
1399 distinct_lines++;
njn4f9c9342002-04-29 16:03:24 +00001400 }
1401
nethercote9313ac42004-07-06 21:54:20 +00001402 // Summary stats must come after rest of table, since we calculate them
sewardj8badbaa2007-05-08 09:20:25 +00001403 // during traversal. */
1404 if (clo_cache_sim && clo_branch_sim) {
1405 VG_(sprintf)(buf, "summary:"
1406 " %llu %llu %llu"
1407 " %llu %llu %llu"
1408 " %llu %llu %llu"
1409 " %llu %llu %llu %llu\n",
1410 Ir_total.a, Ir_total.m1, Ir_total.m2,
1411 Dr_total.a, Dr_total.m1, Dr_total.m2,
1412 Dw_total.a, Dw_total.m1, Dw_total.m2,
1413 Bc_total.b, Bc_total.mp,
1414 Bi_total.b, Bi_total.mp);
1415 }
1416 else if (clo_cache_sim && !clo_branch_sim) {
1417 VG_(sprintf)(buf, "summary:"
1418 " %llu %llu %llu"
1419 " %llu %llu %llu"
1420 " %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 }
1425 else if (!clo_cache_sim && clo_branch_sim) {
1426 VG_(sprintf)(buf, "summary:"
1427 " %llu"
1428 " %llu %llu %llu %llu\n",
1429 Ir_total.a,
1430 Bc_total.b, Bc_total.mp,
1431 Bi_total.b, Bi_total.mp);
1432 }
1433 else
1434 tl_assert(0);
1435
njn4f9c9342002-04-29 16:03:24 +00001436 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1437 VG_(close)(fd);
1438}
1439
njn607adfc2003-09-30 14:15:44 +00001440static UInt ULong_width(ULong n)
njn4f9c9342002-04-29 16:03:24 +00001441{
njn607adfc2003-09-30 14:15:44 +00001442 UInt w = 0;
1443 while (n > 0) {
1444 n = n / 10;
1445 w++;
njn4f9c9342002-04-29 16:03:24 +00001446 }
sewardj46c59b12005-11-01 02:20:19 +00001447 if (w == 0) w = 1;
njn607adfc2003-09-30 14:15:44 +00001448 return w + (w-1)/3; // add space for commas
njn4f9c9342002-04-29 16:03:24 +00001449}
1450
njn51d827b2005-05-09 01:02:08 +00001451static void cg_fini(Int exitcode)
njn4f9c9342002-04-29 16:03:24 +00001452{
njn1baf7db2006-04-18 22:34:48 +00001453 static Char buf1[128], buf2[128], buf3[128], buf4[123], fmt[128];
njn607adfc2003-09-30 14:15:44 +00001454
sewardj8badbaa2007-05-08 09:20:25 +00001455 CacheCC D_total;
1456 BranchCC B_total;
njn1d021fa2002-05-02 13:56:34 +00001457 ULong L2_total_m, L2_total_mr, L2_total_mw,
1458 L2_total, L2_total_r, L2_total_w;
sewardj8badbaa2007-05-08 09:20:25 +00001459 Int l1, l2, l3, l4;
njn4f9c9342002-04-29 16:03:24 +00001460 Int p;
1461
sewardj8badbaa2007-05-08 09:20:25 +00001462 /* Running with both cache and branch simulation disabled is not
1463 allowed (checked during command line option processing). */
1464 tl_assert(clo_cache_sim || clo_branch_sim);
1465
nethercote9313ac42004-07-06 21:54:20 +00001466 fprint_CC_table_and_calc_totals();
njn4f9c9342002-04-29 16:03:24 +00001467
njn7cf0bd32002-06-08 13:36:03 +00001468 if (VG_(clo_verbosity) == 0)
1469 return;
1470
njn4f9c9342002-04-29 16:03:24 +00001471 /* I cache results. Use the I_refs value to determine the first column
1472 * width. */
njn607adfc2003-09-30 14:15:44 +00001473 l1 = ULong_width(Ir_total.a);
1474 l2 = ULong_width(Dr_total.a);
1475 l3 = ULong_width(Dw_total.a);
sewardj8badbaa2007-05-08 09:20:25 +00001476 l4 = ULong_width(Bc_total.b + Bi_total.b);
njn4f9c9342002-04-29 16:03:24 +00001477
njn607adfc2003-09-30 14:15:44 +00001478 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001479 VG_(sprintf)(fmt, "%%s %%,%dllu", l1);
njnd3bef4f2005-10-15 17:46:18 +00001480
sewardj8badbaa2007-05-08 09:20:25 +00001481 /* Always print this */
njn607adfc2003-09-30 14:15:44 +00001482 VG_(message)(Vg_UserMsg, fmt, "I refs: ", Ir_total.a);
njn4f9c9342002-04-29 16:03:24 +00001483
sewardj8badbaa2007-05-08 09:20:25 +00001484 /* If cache profiling is enabled, show D access numbers and all
1485 miss numbers */
1486 if (clo_cache_sim) {
1487 VG_(message)(Vg_UserMsg, fmt, "I1 misses: ", Ir_total.m1);
1488 VG_(message)(Vg_UserMsg, fmt, "L2i misses: ", Ir_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001489
sewardj8badbaa2007-05-08 09:20:25 +00001490 p = 100;
njnd3bef4f2005-10-15 17:46:18 +00001491
sewardj8badbaa2007-05-08 09:20:25 +00001492 if (0 == Ir_total.a) Ir_total.a = 1;
1493 VG_(percentify)(Ir_total.m1, Ir_total.a, 2, l1+1, buf1);
1494 VG_(message)(Vg_UserMsg, "I1 miss rate: %s", buf1);
njn4f9c9342002-04-29 16:03:24 +00001495
sewardj8badbaa2007-05-08 09:20:25 +00001496 VG_(percentify)(Ir_total.m2, Ir_total.a, 2, l1+1, buf1);
1497 VG_(message)(Vg_UserMsg, "L2i miss rate: %s", buf1);
1498 VG_(message)(Vg_UserMsg, "");
njnd3bef4f2005-10-15 17:46:18 +00001499
sewardj8badbaa2007-05-08 09:20:25 +00001500 /* D cache results. Use the D_refs.rd and D_refs.wr values to
1501 * determine the width of columns 2 & 3. */
1502 D_total.a = Dr_total.a + Dw_total.a;
1503 D_total.m1 = Dr_total.m1 + Dw_total.m1;
1504 D_total.m2 = Dr_total.m2 + Dw_total.m2;
njn4f9c9342002-04-29 16:03:24 +00001505
sewardj8badbaa2007-05-08 09:20:25 +00001506 /* Make format string, getting width right for numbers */
1507 VG_(sprintf)(fmt, "%%s %%,%dllu (%%,%dllu rd + %%,%dllu wr)", l1, l2, l3);
njn4f9c9342002-04-29 16:03:24 +00001508
sewardj8badbaa2007-05-08 09:20:25 +00001509 VG_(message)(Vg_UserMsg, fmt, "D refs: ",
1510 D_total.a, Dr_total.a, Dw_total.a);
1511 VG_(message)(Vg_UserMsg, fmt, "D1 misses: ",
1512 D_total.m1, Dr_total.m1, Dw_total.m1);
1513 VG_(message)(Vg_UserMsg, fmt, "L2d misses: ",
1514 D_total.m2, Dr_total.m2, Dw_total.m2);
njnd3bef4f2005-10-15 17:46:18 +00001515
sewardj8badbaa2007-05-08 09:20:25 +00001516 p = 10;
njn4f9c9342002-04-29 16:03:24 +00001517
sewardj8badbaa2007-05-08 09:20:25 +00001518 if (0 == D_total.a) D_total.a = 1;
1519 if (0 == Dr_total.a) Dr_total.a = 1;
1520 if (0 == Dw_total.a) Dw_total.a = 1;
1521 VG_(percentify)( D_total.m1, D_total.a, 1, l1+1, buf1);
1522 VG_(percentify)(Dr_total.m1, Dr_total.a, 1, l2+1, buf2);
1523 VG_(percentify)(Dw_total.m1, Dw_total.a, 1, l3+1, buf3);
1524 VG_(message)(Vg_UserMsg, "D1 miss rate: %s (%s + %s )", buf1, buf2,buf3);
njn4f9c9342002-04-29 16:03:24 +00001525
sewardj8badbaa2007-05-08 09:20:25 +00001526 VG_(percentify)( D_total.m2, D_total.a, 1, l1+1, buf1);
1527 VG_(percentify)(Dr_total.m2, Dr_total.a, 1, l2+1, buf2);
1528 VG_(percentify)(Dw_total.m2, Dw_total.a, 1, l3+1, buf3);
1529 VG_(message)(Vg_UserMsg, "L2d miss rate: %s (%s + %s )", buf1, buf2,buf3);
1530 VG_(message)(Vg_UserMsg, "");
njn1d021fa2002-05-02 13:56:34 +00001531
sewardj8badbaa2007-05-08 09:20:25 +00001532 /* L2 overall results */
njn1d021fa2002-05-02 13:56:34 +00001533
sewardj8badbaa2007-05-08 09:20:25 +00001534 L2_total = Dr_total.m1 + Dw_total.m1 + Ir_total.m1;
1535 L2_total_r = Dr_total.m1 + Ir_total.m1;
1536 L2_total_w = Dw_total.m1;
1537 VG_(message)(Vg_UserMsg, fmt, "L2 refs: ",
1538 L2_total, L2_total_r, L2_total_w);
njn4f9c9342002-04-29 16:03:24 +00001539
sewardj8badbaa2007-05-08 09:20:25 +00001540 L2_total_m = Dr_total.m2 + Dw_total.m2 + Ir_total.m2;
1541 L2_total_mr = Dr_total.m2 + Ir_total.m2;
1542 L2_total_mw = Dw_total.m2;
1543 VG_(message)(Vg_UserMsg, fmt, "L2 misses: ",
1544 L2_total_m, L2_total_mr, L2_total_mw);
njnd3bef4f2005-10-15 17:46:18 +00001545
sewardj8badbaa2007-05-08 09:20:25 +00001546 VG_(percentify)(L2_total_m, (Ir_total.a + D_total.a), 1, l1+1, buf1);
1547 VG_(percentify)(L2_total_mr, (Ir_total.a + Dr_total.a), 1, l2+1, buf2);
1548 VG_(percentify)(L2_total_mw, Dw_total.a, 1, l3+1, buf3);
1549 VG_(message)(Vg_UserMsg, "L2 miss rate: %s (%s + %s )", buf1, buf2,buf3);
1550 }
1551
1552 /* If branch profiling is enabled, show branch overall results. */
1553 if (clo_branch_sim) {
1554 /* Make format string, getting width right for numbers */
1555 VG_(sprintf)(fmt, "%%s %%,%dllu (%%,%dllu cond + %%,%dllu ind)", l1, l2, l3);
1556
1557 if (0 == Bc_total.b) Bc_total.b = 1;
1558 if (0 == Bi_total.b) Bi_total.b = 1;
1559 B_total.b = Bc_total.b + Bi_total.b;
1560 B_total.mp = Bc_total.mp + Bi_total.mp;
1561
1562 VG_(message)(Vg_UserMsg, "");
1563 VG_(message)(Vg_UserMsg, fmt, "Branches: ",
1564 B_total.b, Bc_total.b, Bi_total.b);
1565
1566 VG_(message)(Vg_UserMsg, fmt, "Mispredicts: ",
1567 B_total.mp, Bc_total.mp, Bi_total.mp);
1568
1569 VG_(percentify)(B_total.mp, B_total.b, 1, l1+1, buf1);
1570 VG_(percentify)(Bc_total.mp, Bc_total.b, 1, l2+1, buf2);
1571 VG_(percentify)(Bi_total.mp, Bi_total.b, 1, l3+1, buf3);
1572
1573 VG_(message)(Vg_UserMsg, "Mispred rate: %s (%s + %s )", buf1, buf2,buf3);
1574 }
njn4f9c9342002-04-29 16:03:24 +00001575
nethercote9313ac42004-07-06 21:54:20 +00001576 // Various stats
njn4f9c9342002-04-29 16:03:24 +00001577 if (VG_(clo_verbosity) > 1) {
njn1baf7db2006-04-18 22:34:48 +00001578 Int debug_lookups = full_debugs + fn_debugs +
1579 file_line_debugs + no_debugs;
njnd3bef4f2005-10-15 17:46:18 +00001580
njn1baf7db2006-04-18 22:34:48 +00001581 VG_(message)(Vg_DebugMsg, "");
1582 VG_(message)(Vg_DebugMsg, "cachegrind: distinct files: %d", distinct_files);
1583 VG_(message)(Vg_DebugMsg, "cachegrind: distinct fns: %d", distinct_fns);
1584 VG_(message)(Vg_DebugMsg, "cachegrind: distinct lines: %d", distinct_lines);
1585 VG_(message)(Vg_DebugMsg, "cachegrind: distinct instrs:%d", distinct_instrs);
1586 VG_(message)(Vg_DebugMsg, "cachegrind: debug lookups : %d", debug_lookups);
1587
1588 VG_(percentify)(full_debugs, debug_lookups, 1, 6, buf1);
1589 VG_(percentify)(file_line_debugs, debug_lookups, 1, 6, buf2);
1590 VG_(percentify)(fn_debugs, debug_lookups, 1, 6, buf3);
1591 VG_(percentify)(no_debugs, debug_lookups, 1, 6, buf4);
1592 VG_(message)(Vg_DebugMsg, "cachegrind: with full info:%s (%d)",
1593 buf1, full_debugs);
1594 VG_(message)(Vg_DebugMsg, "cachegrind: with file/line info:%s (%d)",
1595 buf2, file_line_debugs);
1596 VG_(message)(Vg_DebugMsg, "cachegrind: with fn name info:%s (%d)",
1597 buf3, fn_debugs);
1598 VG_(message)(Vg_DebugMsg, "cachegrind: with zero info:%s (%d)",
1599 buf4, no_debugs);
1600
1601 VG_(message)(Vg_DebugMsg, "cachegrind: string table size: %u",
1602 VG_(OSet_Size)(stringTable));
1603 VG_(message)(Vg_DebugMsg, "cachegrind: CC table size: %u",
1604 VG_(OSet_Size)(CC_table));
1605 VG_(message)(Vg_DebugMsg, "cachegrind: InstrInfo table size: %u",
1606 VG_(OSet_Size)(instrInfoTable));
njn4f9c9342002-04-29 16:03:24 +00001607 }
njn4f9c9342002-04-29 16:03:24 +00001608}
1609
nethercote9313ac42004-07-06 21:54:20 +00001610/*--------------------------------------------------------------------*/
1611/*--- Discarding BB info ---*/
1612/*--------------------------------------------------------------------*/
sewardj18d75132002-05-16 11:06:21 +00001613
sewardja3a29a52005-10-12 16:16:03 +00001614// Called when a translation is removed from the translation cache for
1615// any reason at all: to free up space, because the guest code was
1616// unmapped or modified, or for any arbitrary reason.
sewardj4ba057c2005-10-18 12:04:18 +00001617static
sewardj0b9d74a2006-12-24 02:24:11 +00001618void cg_discard_superblock_info ( Addr64 orig_addr64, VexGuestExtents vge )
sewardj18d75132002-05-16 11:06:21 +00001619{
sewardj0b9d74a2006-12-24 02:24:11 +00001620 SB_info* sbInfo;
sewardj3a384b32006-01-22 01:12:51 +00001621 Addr orig_addr = (Addr)vge.base[0];
njn4294fd42002-06-05 14:41:10 +00001622
sewardj5155dec2005-10-12 10:09:23 +00001623 tl_assert(vge.n_used > 0);
1624
1625 if (DEBUG_CG)
sewardj4ba057c2005-10-18 12:04:18 +00001626 VG_(printf)( "discard_basic_block_info: %p, %p, %llu\n",
1627 (void*)(Addr)orig_addr,
sewardj5155dec2005-10-12 10:09:23 +00001628 (void*)(Addr)vge.base[0], (ULong)vge.len[0]);
njn4294fd42002-06-05 14:41:10 +00001629
sewardj4ba057c2005-10-18 12:04:18 +00001630 // Get BB info, remove from table, free BB info. Simple! Note that we
1631 // use orig_addr, not the first instruction address in vge.
sewardj0b9d74a2006-12-24 02:24:11 +00001632 sbInfo = VG_(OSet_Remove)(instrInfoTable, &orig_addr);
1633 tl_assert(NULL != sbInfo);
1634 VG_(OSet_FreeNode)(instrInfoTable, sbInfo);
sewardj18d75132002-05-16 11:06:21 +00001635}
1636
1637/*--------------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001638/*--- Command line processing ---*/
1639/*--------------------------------------------------------------------*/
1640
njn0103de52005-10-10 16:49:01 +00001641static void parse_cache_opt ( cache_t* cache, Char* opt )
njn25e49d8e72002-09-23 09:36:25 +00001642{
njn0103de52005-10-10 16:49:01 +00001643 Int i = 0, i2, i3;
njn25e49d8e72002-09-23 09:36:25 +00001644
nethercote9313ac42004-07-06 21:54:20 +00001645 // Option argument looks like "65536,2,64".
1646 // Find commas, replace with NULs to make three independent
1647 // strings, then extract numbers, put NULs back. Yuck.
njn25e49d8e72002-09-23 09:36:25 +00001648 while (VG_(isdigit)(opt[i])) i++;
1649 if (',' == opt[i]) {
1650 opt[i++] = '\0';
1651 i2 = i;
1652 } else goto bad;
1653 while (VG_(isdigit)(opt[i])) i++;
1654 if (',' == opt[i]) {
1655 opt[i++] = '\0';
1656 i3 = i;
1657 } else goto bad;
1658 while (VG_(isdigit)(opt[i])) i++;
1659 if ('\0' != opt[i]) goto bad;
1660
nethercote9313ac42004-07-06 21:54:20 +00001661 cache->size = (Int)VG_(atoll)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001662 cache->assoc = (Int)VG_(atoll)(opt + i2);
1663 cache->line_size = (Int)VG_(atoll)(opt + i3);
1664
nethercote9313ac42004-07-06 21:54:20 +00001665 opt[i2-1] = ',';
1666 opt[i3-1] = ',';
njn25e49d8e72002-09-23 09:36:25 +00001667 return;
1668
1669 bad:
sewardj6893d652006-10-15 01:25:13 +00001670 VG_(err_bad_option)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001671}
1672
njn51d827b2005-05-09 01:02:08 +00001673static Bool cg_process_cmd_line_option(Char* arg)
njn25e49d8e72002-09-23 09:36:25 +00001674{
nethercote9313ac42004-07-06 21:54:20 +00001675 // 5 is length of "--I1="
njn39c86652003-05-21 10:13:39 +00001676 if (VG_CLO_STREQN(5, arg, "--I1="))
nethercote9313ac42004-07-06 21:54:20 +00001677 parse_cache_opt(&clo_I1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001678 else if (VG_CLO_STREQN(5, arg, "--D1="))
nethercote9313ac42004-07-06 21:54:20 +00001679 parse_cache_opt(&clo_D1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001680 else if (VG_CLO_STREQN(5, arg, "--L2="))
nethercote9313ac42004-07-06 21:54:20 +00001681 parse_cache_opt(&clo_L2_cache, &arg[5]);
sewardje1216cb2007-02-07 19:55:30 +00001682 else if (VG_CLO_STREQN(22, arg, "--cachegrind-out-file=")) {
1683 cachegrind_out_file_basename = &arg[22];
1684 }
sewardj8badbaa2007-05-08 09:20:25 +00001685 else VG_BOOL_CLO(arg, "--cache-sim", clo_cache_sim)
1686 else VG_BOOL_CLO(arg, "--branch-sim", clo_branch_sim)
njn25e49d8e72002-09-23 09:36:25 +00001687 else
1688 return False;
1689
1690 return True;
1691}
1692
njn51d827b2005-05-09 01:02:08 +00001693static void cg_print_usage(void)
njn25e49d8e72002-09-23 09:36:25 +00001694{
njn3e884182003-04-15 13:03:23 +00001695 VG_(printf)(
njn25e49d8e72002-09-23 09:36:25 +00001696" --I1=<size>,<assoc>,<line_size> set I1 cache manually\n"
1697" --D1=<size>,<assoc>,<line_size> set D1 cache manually\n"
njn3e884182003-04-15 13:03:23 +00001698" --L2=<size>,<assoc>,<line_size> set L2 cache manually\n"
sewardj8badbaa2007-05-08 09:20:25 +00001699" --cache-sim=yes|no [yes] collect cache stats?\n"
1700" --branch-sim=yes|no [no] collect branch prediction stats?\n"
sewardje1216cb2007-02-07 19:55:30 +00001701" --cachegrind-out-file=<file> write profile data to <file>.<pid>\n"
1702" [cachegrind.out.<pid>]\n"
njn3e884182003-04-15 13:03:23 +00001703 );
1704}
1705
njn51d827b2005-05-09 01:02:08 +00001706static void cg_print_debug_usage(void)
njn3e884182003-04-15 13:03:23 +00001707{
1708 VG_(printf)(
1709" (none)\n"
1710 );
njn25e49d8e72002-09-23 09:36:25 +00001711}
1712
1713/*--------------------------------------------------------------------*/
1714/*--- Setup ---*/
1715/*--------------------------------------------------------------------*/
1716
njn57ca7ab2005-06-21 23:44:58 +00001717static Char base_dir[VKI_PATH_MAX];
1718
sewardje1216cb2007-02-07 19:55:30 +00001719static void cg_post_clo_init(void); /* just below */
1720
njn51d827b2005-05-09 01:02:08 +00001721static void cg_pre_clo_init(void)
1722{
njn51d827b2005-05-09 01:02:08 +00001723 VG_(details_name) ("Cachegrind");
1724 VG_(details_version) (NULL);
sewardj8badbaa2007-05-08 09:20:25 +00001725 VG_(details_description) ("a cache and branch-prediction profiler");
njn51d827b2005-05-09 01:02:08 +00001726 VG_(details_copyright_author)(
sewardj9ebd6e02007-01-08 06:01:59 +00001727 "Copyright (C) 2002-2007, and GNU GPL'd, by Nicholas Nethercote et al.");
njn51d827b2005-05-09 01:02:08 +00001728 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardje8089302006-10-17 02:15:17 +00001729 VG_(details_avg_translation_sizeB) ( 500 );
njn51d827b2005-05-09 01:02:08 +00001730
1731 VG_(basic_tool_funcs) (cg_post_clo_init,
1732 cg_instrument,
1733 cg_fini);
1734
sewardj0b9d74a2006-12-24 02:24:11 +00001735 VG_(needs_superblock_discards)(cg_discard_superblock_info);
njn51d827b2005-05-09 01:02:08 +00001736 VG_(needs_command_line_options)(cg_process_cmd_line_option,
1737 cg_print_usage,
1738 cg_print_debug_usage);
sewardje1216cb2007-02-07 19:55:30 +00001739}
1740
1741static void cg_post_clo_init(void)
1742{
1743 HChar* qual = NULL;
1744 cache_t I1c, D1c, L2c;
1745 Int filename_szB;
njn51d827b2005-05-09 01:02:08 +00001746
sewardj8badbaa2007-05-08 09:20:25 +00001747 /* Can't disable both cache and branch profiling */
1748 if ((!clo_cache_sim) && (!clo_branch_sim)) {
1749 VG_(message)(Vg_DebugMsg,
1750 "ERROR: --cache-sim=no --branch-sim=no is not allowed.");
1751 VG_(message)(Vg_DebugMsg,
1752 "You must select cache profiling, or branch profiling, or both.");
1753 VG_(exit)(2);
1754 }
1755
njn51d827b2005-05-09 01:02:08 +00001756 /* Get working directory */
sewardj198f34f2007-07-09 23:13:07 +00001757 tl_assert( VG_(get_startup_wd)(base_dir, VKI_PATH_MAX) );
njn51d827b2005-05-09 01:02:08 +00001758
sewardje1216cb2007-02-07 19:55:30 +00001759 /* Do we have a --log-file-qualifier= to consider? */
1760 if (VG_(clo_log_file_qualifier)) {
1761 qual = VG_(getenv)(VG_(clo_log_file_qualifier));
1762 }
1763
1764 /* Block is big enough for
1765 dir name ++ cachegrind_out_file_basename
1766 ++ ".<pid>"
1767 ++ the log file qualifier, if in use */
1768 filename_szB
1769 = VG_(strlen)(base_dir)
1770 + 1 /* "/" */
1771 + VG_(strlen)(cachegrind_out_file_basename)
1772 + 11 /* "." <pid>, assuming sizeof(pid) <= 4 */
1773 + (qual ? (10 + VG_(strlen)(qual)) : 0)
1774 + 1; /* to guarantee checkable zero at the end */
1775
1776 tl_assert(filename_szB > 0);
1777 cachegrind_out_file
1778 = VG_(calloc)( sizeof(Char), filename_szB );
1779
1780 if (qual) {
1781 VG_(sprintf)(cachegrind_out_file, "%s/%s.%d.lfq.%s",
1782 base_dir, cachegrind_out_file_basename,
1783 VG_(getpid)(), qual);
1784 } else {
1785 VG_(sprintf)(cachegrind_out_file, "%s/%s.%d",
1786 base_dir, cachegrind_out_file_basename,
1787 VG_(getpid)());
1788 }
1789
1790 tl_assert( cachegrind_out_file[filename_szB-1] == 0 );
njn51d827b2005-05-09 01:02:08 +00001791
njnd3bef4f2005-10-15 17:46:18 +00001792 CC_table = VG_(OSet_Create)(offsetof(LineCC, loc),
1793 cmp_CodeLoc_LineCC,
1794 VG_(malloc), VG_(free));
sewardj4ba057c2005-10-18 12:04:18 +00001795 instrInfoTable = VG_(OSet_Create)(/*keyOff*/0,
njnd3bef4f2005-10-15 17:46:18 +00001796 NULL,
1797 VG_(malloc), VG_(free));
1798 stringTable = VG_(OSet_Create)(/*keyOff*/0,
1799 stringCmp,
1800 VG_(malloc), VG_(free));
sewardje1216cb2007-02-07 19:55:30 +00001801
1802 configure_caches(&I1c, &D1c, &L2c);
1803
1804 cachesim_I1_initcache(I1c);
1805 cachesim_D1_initcache(D1c);
1806 cachesim_L2_initcache(L2c);
njn51d827b2005-05-09 01:02:08 +00001807}
1808
sewardj45f4e7c2005-09-27 19:20:21 +00001809VG_DETERMINE_INTERFACE_VERSION(cg_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00001810
njn25e49d8e72002-09-23 09:36:25 +00001811/*--------------------------------------------------------------------*/
njnf69f9452005-07-03 17:53:11 +00001812/*--- end ---*/
sewardj18d75132002-05-16 11:06:21 +00001813/*--------------------------------------------------------------------*/
njnd3bef4f2005-10-15 17:46:18 +00001814