blob: c218253f77aa871f4161f1ee51a73308865bd41f [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
njn53612422005-03-12 16:22:54 +000011 Copyright (C) 2002-2005 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"
njnea27e462005-05-31 02:38:09 +000033#include "pub_tool_debuginfo.h"
njn97405b22005-06-02 03:39:33 +000034#include "pub_tool_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000035#include "pub_tool_libcassert.h"
njneb8896b2005-06-04 20:03:55 +000036#include "pub_tool_libcfile.h"
njn36a20fa2005-06-03 03:08:39 +000037#include "pub_tool_libcprint.h"
njnf39e9a32005-06-12 02:43:17 +000038#include "pub_tool_libcproc.h"
njnf536bbb2005-06-13 04:21:38 +000039#include "pub_tool_machine.h"
njn717cde52005-05-10 02:47:21 +000040#include "pub_tool_mallocfree.h"
njn20242342005-05-16 23:31:24 +000041#include "pub_tool_options.h"
njnd3bef4f2005-10-15 17:46:18 +000042#include "pub_tool_oset.h"
njn43b9a8a2005-05-10 04:37:01 +000043#include "pub_tool_tooliface.h"
sewardj45f4e7c2005-09-27 19:20:21 +000044#include "pub_tool_clientstate.h"
sewardj5bb86822005-12-23 12:47:42 +000045#include "pub_tool_machine.h" // VG_(fnptr_to_fnentry)
njn25e49d8e72002-09-23 09:36:25 +000046
nethercoteb35a8b92004-09-11 16:45:27 +000047#include "cg_arch.h"
nethercote27fc1da2004-01-04 16:56:57 +000048#include "cg_sim.c"
njn4f9c9342002-04-29 16:03:24 +000049
njn25e49d8e72002-09-23 09:36:25 +000050/*------------------------------------------------------------*/
51/*--- Constants ---*/
52/*------------------------------------------------------------*/
njn4f9c9342002-04-29 16:03:24 +000053
sewardj5155dec2005-10-12 10:09:23 +000054/* Set to 1 for very verbose debugging */
55#define DEBUG_CG 0
56
nethercote9313ac42004-07-06 21:54:20 +000057#define MIN_LINE_SIZE 16
njnd3bef4f2005-10-15 17:46:18 +000058#define FILE_LEN VKI_PATH_MAX
nethercote9313ac42004-07-06 21:54:20 +000059#define FN_LEN 256
njn7cf0bd32002-06-08 13:36:03 +000060
61/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +000062/*--- Types and Data Structures ---*/
njn4f9c9342002-04-29 16:03:24 +000063/*------------------------------------------------------------*/
64
65typedef struct _CC CC;
66struct _CC {
67 ULong a;
68 ULong m1;
69 ULong m2;
70};
71
nethercote9313ac42004-07-06 21:54:20 +000072//------------------------------------------------------------
73// Primary data structure #1: CC table
74// - Holds the per-source-line hit/miss stats, grouped by file/function/line.
njnd3bef4f2005-10-15 17:46:18 +000075// - an ordered set of CCs. CC indexing done by file/function/line (as
76// determined from the instrAddr).
nethercote9313ac42004-07-06 21:54:20 +000077// - Traversed for dumping stats at end in file/func/line hierarchy.
njn4f9c9342002-04-29 16:03:24 +000078
njnd3bef4f2005-10-15 17:46:18 +000079typedef struct {
80 Char* file;
81 Char* fn;
82 Int line;
83}
84CodeLoc;
njn4f9c9342002-04-29 16:03:24 +000085
njnd3bef4f2005-10-15 17:46:18 +000086typedef struct _LineCC LineCC;
87struct _LineCC {
88 CodeLoc loc;
89 CC Ir;
90 CC Dr;
91 CC Dw;
njn4f9c9342002-04-29 16:03:24 +000092};
93
njnd3bef4f2005-10-15 17:46:18 +000094// First compare file, then fn, then line.
njnafa12262005-12-24 03:10:56 +000095static Word cmp_CodeLoc_LineCC(void *vloc, void *vcc)
njnd3bef4f2005-10-15 17:46:18 +000096{
njnafa12262005-12-24 03:10:56 +000097 Word res;
njnd3bef4f2005-10-15 17:46:18 +000098 CodeLoc* a = (CodeLoc*)vloc;
99 CodeLoc* b = &(((LineCC*)vcc)->loc);
njn4f9c9342002-04-29 16:03:24 +0000100
njnd3bef4f2005-10-15 17:46:18 +0000101 res = VG_(strcmp)(a->file, b->file);
102 if (0 != res)
103 return res;
njn4f9c9342002-04-29 16:03:24 +0000104
njnd3bef4f2005-10-15 17:46:18 +0000105 res = VG_(strcmp)(a->fn, b->fn);
106 if (0 != res)
107 return res;
108
109 return a->line - b->line;
110}
111
112static OSet* CC_table;
njn4f9c9342002-04-29 16:03:24 +0000113
nethercote9313ac42004-07-06 21:54:20 +0000114//------------------------------------------------------------
njnd3bef4f2005-10-15 17:46:18 +0000115// Primary data structure #2: InstrInfo table
nethercote9313ac42004-07-06 21:54:20 +0000116// - Holds the cached info about each instr that is used for simulation.
njnd3bef4f2005-10-15 17:46:18 +0000117// - table(BB_start_addr, list(InstrInfo))
118// - For each BB, each InstrInfo in the list holds info about the
119// instruction (instrLen, instrAddr, etc), plus a pointer to its line
nethercote9313ac42004-07-06 21:54:20 +0000120// CC. This node is what's passed to the simulation function.
121// - When BBs are discarded the relevant list(instr_details) is freed.
122
njnd3bef4f2005-10-15 17:46:18 +0000123typedef struct _InstrInfo InstrInfo;
124struct _InstrInfo {
nethercoteca1f2dc2004-07-21 08:49:02 +0000125 Addr instr_addr;
njn6a3009b2005-03-20 00:20:06 +0000126 UChar instr_len;
njnd3bef4f2005-10-15 17:46:18 +0000127 LineCC* parent; // parent line-CC
nethercote9313ac42004-07-06 21:54:20 +0000128};
129
130typedef struct _BB_info BB_info;
131struct _BB_info {
sewardj4ba057c2005-10-18 12:04:18 +0000132 Addr BB_addr; // key; MUST BE FIRST
njnd3bef4f2005-10-15 17:46:18 +0000133 Int n_instrs;
134 InstrInfo instrs[0];
nethercote9313ac42004-07-06 21:54:20 +0000135};
136
njnd3bef4f2005-10-15 17:46:18 +0000137static OSet* instrInfoTable;
138
139//------------------------------------------------------------
140// Secondary data structure: string table
141// - holds strings, avoiding dups
142// - used for filenames and function names, each of which will be
143// pointed to by one or more CCs.
144// - it also allows equality checks just by pointer comparison, which
145// is good when printing the output file at the end.
146
147static OSet* stringTable;
nethercote9313ac42004-07-06 21:54:20 +0000148
149//------------------------------------------------------------
150// Stats
sewardj4f29ddf2002-05-03 22:29:04 +0000151static Int distinct_files = 0;
152static Int distinct_fns = 0;
nethercote9313ac42004-07-06 21:54:20 +0000153static Int distinct_lines = 0;
sewardj4f29ddf2002-05-03 22:29:04 +0000154static Int distinct_instrs = 0;
nethercote9313ac42004-07-06 21:54:20 +0000155
njnd3bef4f2005-10-15 17:46:18 +0000156static Int full_debugs = 0;
157static Int file_line_debugs = 0;
158static Int fn_debugs = 0;
159static Int no_debugs = 0;
njn4f9c9342002-04-29 16:03:24 +0000160
nethercote9313ac42004-07-06 21:54:20 +0000161/*------------------------------------------------------------*/
njnd3bef4f2005-10-15 17:46:18 +0000162/*--- String table operations ---*/
163/*------------------------------------------------------------*/
164
njnafa12262005-12-24 03:10:56 +0000165static Word stringCmp( void* key, void* elem )
njnd3bef4f2005-10-15 17:46:18 +0000166{
167 return VG_(strcmp)(*(Char**)key, *(Char**)elem);
168}
169
170// Get a permanent string; either pull it out of the string table if it's
171// been encountered before, or dup it and put it into the string table.
172static Char* get_perm_string(Char* s)
173{
174 Char** s_ptr = VG_(OSet_Lookup)(stringTable, &s);
175 if (s_ptr) {
176 return *s_ptr;
177 } else {
178 Char** s_node = VG_(OSet_AllocNode)(stringTable, sizeof(Char*));
179 *s_node = VG_(strdup)(s);
180 VG_(OSet_Insert)(stringTable, s_node);
181 return *s_node;
182 }
183}
184
185/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +0000186/*--- CC table operations ---*/
187/*------------------------------------------------------------*/
njn4294fd42002-06-05 14:41:10 +0000188
nethercote9313ac42004-07-06 21:54:20 +0000189static void get_debug_info(Addr instr_addr, Char file[FILE_LEN],
190 Char fn[FN_LEN], Int* line)
njn4f9c9342002-04-29 16:03:24 +0000191{
sewardj7cee6f92005-06-13 17:39:06 +0000192 Bool found_file_line = VG_(get_filename_linenum)(
193 instr_addr,
194 file, FILE_LEN,
195 NULL, 0, NULL,
196 line
197 );
nethercote9313ac42004-07-06 21:54:20 +0000198 Bool found_fn = VG_(get_fnname)(instr_addr, fn, FN_LEN);
njn4f9c9342002-04-29 16:03:24 +0000199
nethercote9313ac42004-07-06 21:54:20 +0000200 if (!found_file_line) {
201 VG_(strcpy)(file, "???");
202 *line = 0;
203 }
204 if (!found_fn) {
205 VG_(strcpy)(fn, "???");
206 }
207 if (found_file_line) {
njnd3bef4f2005-10-15 17:46:18 +0000208 if (found_fn) full_debugs++;
209 else file_line_debugs++;
nethercote9313ac42004-07-06 21:54:20 +0000210 } else {
njnd3bef4f2005-10-15 17:46:18 +0000211 if (found_fn) fn_debugs++;
212 else no_debugs++;
njn4f9c9342002-04-29 16:03:24 +0000213 }
214}
215
nethercote9313ac42004-07-06 21:54:20 +0000216// Do a three step traversal: by file, then fn, then line.
njnd3bef4f2005-10-15 17:46:18 +0000217// Returns a pointer to the line CC, creates a new one if necessary.
218static LineCC* get_lineCC(Addr origAddr)
nethercote9313ac42004-07-06 21:54:20 +0000219{
nethercote9313ac42004-07-06 21:54:20 +0000220 Char file[FILE_LEN], fn[FN_LEN];
221 Int line;
njnd3bef4f2005-10-15 17:46:18 +0000222 CodeLoc loc;
223 LineCC* lineCC;
nethercote9313ac42004-07-06 21:54:20 +0000224
njn6a3009b2005-03-20 00:20:06 +0000225 get_debug_info(origAddr, file, fn, &line);
nethercote9313ac42004-07-06 21:54:20 +0000226
njnd3bef4f2005-10-15 17:46:18 +0000227 loc.file = file;
228 loc.fn = fn;
229 loc.line = line;
njn4f9c9342002-04-29 16:03:24 +0000230
njnd3bef4f2005-10-15 17:46:18 +0000231 lineCC = VG_(OSet_Lookup)(CC_table, &loc);
232 if (!lineCC) {
233 // Allocate and zero a new node.
234 lineCC = VG_(OSet_AllocNode)(CC_table, sizeof(LineCC));
235 lineCC->loc.file = get_perm_string(loc.file);
236 lineCC->loc.fn = get_perm_string(loc.fn);
237 lineCC->loc.line = loc.line;
238 VG_(OSet_Insert)(CC_table, lineCC);
njn4f9c9342002-04-29 16:03:24 +0000239 }
nethercote9313ac42004-07-06 21:54:20 +0000240
njnd3bef4f2005-10-15 17:46:18 +0000241 return lineCC;
njn4f9c9342002-04-29 16:03:24 +0000242}
243
244/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +0000245/*--- Cache simulation functions ---*/
njn4f9c9342002-04-29 16:03:24 +0000246/*------------------------------------------------------------*/
247
njnaf839f52005-06-23 03:27:57 +0000248static VG_REGPARM(1)
njnd3bef4f2005-10-15 17:46:18 +0000249void log_1I_0D_cache_access(InstrInfo* n)
njn25e49d8e72002-09-23 09:36:25 +0000250{
sewardj5155dec2005-10-12 10:09:23 +0000251 //VG_(printf)("1I_0D : CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n",
252 // n, n->instr_addr, n->instr_len);
njn6a3009b2005-03-20 00:20:06 +0000253 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000254 &n->parent->Ir.m1, &n->parent->Ir.m2);
255 n->parent->Ir.a++;
njn25e49d8e72002-09-23 09:36:25 +0000256}
257
njnaf839f52005-06-23 03:27:57 +0000258static VG_REGPARM(2)
njnd3bef4f2005-10-15 17:46:18 +0000259void log_2I_0D_cache_access(InstrInfo* n, InstrInfo* n2)
njn25e49d8e72002-09-23 09:36:25 +0000260{
sewardj5155dec2005-10-12 10:09:23 +0000261 //VG_(printf)("2I_0D : CC1addr=0x%010lx, i1addr=0x%010lx, i1size=%lu\n"
262 // " CC2addr=0x%010lx, i2addr=0x%010lx, i2size=%lu\n",
263 // n, n->instr_addr, n->instr_len,
264 // n2, n2->instr_addr, n2->instr_len);
sewardj5155dec2005-10-12 10:09:23 +0000265 cachesim_I1_doref(n->instr_addr, n->instr_len,
266 &n->parent->Ir.m1, &n->parent->Ir.m2);
267 n->parent->Ir.a++;
268 cachesim_I1_doref(n2->instr_addr, n2->instr_len,
269 &n2->parent->Ir.m1, &n2->parent->Ir.m2);
270 n2->parent->Ir.a++;
sewardj5155dec2005-10-12 10:09:23 +0000271}
272
273static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000274void log_3I_0D_cache_access(InstrInfo* n, InstrInfo* n2, InstrInfo* n3)
sewardj5155dec2005-10-12 10:09:23 +0000275{
276 //VG_(printf)("3I_0D : CC1addr=0x%010lx, i1addr=0x%010lx, i1size=%lu\n"
277 // " CC2addr=0x%010lx, i2addr=0x%010lx, i2size=%lu\n"
278 // " CC3addr=0x%010lx, i3addr=0x%010lx, i3size=%lu\n",
279 // n, n->instr_addr, n->instr_len,
280 // n2, n2->instr_addr, n2->instr_len,
281 // n3, n3->instr_addr, n3->instr_len);
sewardj5155dec2005-10-12 10:09:23 +0000282 cachesim_I1_doref(n->instr_addr, n->instr_len,
283 &n->parent->Ir.m1, &n->parent->Ir.m2);
284 n->parent->Ir.a++;
285 cachesim_I1_doref(n2->instr_addr, n2->instr_len,
286 &n2->parent->Ir.m1, &n2->parent->Ir.m2);
287 n2->parent->Ir.a++;
288 cachesim_I1_doref(n3->instr_addr, n3->instr_len,
289 &n3->parent->Ir.m1, &n3->parent->Ir.m2);
290 n3->parent->Ir.a++;
sewardj5155dec2005-10-12 10:09:23 +0000291}
292
293static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000294void log_1I_1Dr_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
sewardj5155dec2005-10-12 10:09:23 +0000295{
296 //VG_(printf)("1I_1Dr: CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n"
297 // " daddr=0x%010lx, dsize=%lu\n",
298 // n, n->instr_addr, n->instr_len, data_addr, data_size);
njn6a3009b2005-03-20 00:20:06 +0000299 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000300 &n->parent->Ir.m1, &n->parent->Ir.m2);
301 n->parent->Ir.a++;
njn25e49d8e72002-09-23 09:36:25 +0000302
sewardj5155dec2005-10-12 10:09:23 +0000303 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000304 &n->parent->Dr.m1, &n->parent->Dr.m2);
305 n->parent->Dr.a++;
njn25e49d8e72002-09-23 09:36:25 +0000306}
307
sewardj5155dec2005-10-12 10:09:23 +0000308static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000309void log_1I_1Dw_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
njn25e49d8e72002-09-23 09:36:25 +0000310{
sewardj5155dec2005-10-12 10:09:23 +0000311 //VG_(printf)("1I_1Dw: CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n"
312 // " daddr=0x%010lx, dsize=%lu\n",
313 // n, n->instr_addr, n->instr_len, data_addr, data_size);
njn6a3009b2005-03-20 00:20:06 +0000314 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000315 &n->parent->Ir.m1, &n->parent->Ir.m2);
316 n->parent->Ir.a++;
317
sewardj5155dec2005-10-12 10:09:23 +0000318 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000319 &n->parent->Dw.m1, &n->parent->Dw.m2);
320 n->parent->Dw.a++;
njn25e49d8e72002-09-23 09:36:25 +0000321}
322
njnaf839f52005-06-23 03:27:57 +0000323static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000324void log_0I_1Dr_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
njn25e49d8e72002-09-23 09:36:25 +0000325{
sewardj5155dec2005-10-12 10:09:23 +0000326 //VG_(printf)("0I_1Dr: CCaddr=0x%010lx, daddr=0x%010lx, dsize=%lu\n",
327 // n, data_addr, data_size);
sewardj5155dec2005-10-12 10:09:23 +0000328 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000329 &n->parent->Dr.m1, &n->parent->Dr.m2);
330 n->parent->Dr.a++;
sewardj5155dec2005-10-12 10:09:23 +0000331}
332
333static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000334void log_0I_1Dw_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
sewardj5155dec2005-10-12 10:09:23 +0000335{
336 //VG_(printf)("0I_1Dw: CCaddr=0x%010lx, daddr=0x%010lx, dsize=%lu\n",
337 // n, data_addr, data_size);
sewardj5155dec2005-10-12 10:09:23 +0000338 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000339 &n->parent->Dw.m1, &n->parent->Dw.m2);
340 n->parent->Dw.a++;
njn25e49d8e72002-09-23 09:36:25 +0000341}
342
nethercote9313ac42004-07-06 21:54:20 +0000343/*------------------------------------------------------------*/
sewardj5155dec2005-10-12 10:09:23 +0000344/*--- Instrumentation types and structures ---*/
345/*------------------------------------------------------------*/
346
347/* Maintain an ordered list of memory events which are outstanding, in
348 the sense that no IR has yet been generated to do the relevant
349 helper calls. The BB is scanned top to bottom and memory events
350 are added to the end of the list, merging with the most recent
351 notified event where possible (Dw immediately following Dr and
352 having the same size and EA can be merged).
353
354 This merging is done so that for architectures which have
355 load-op-store instructions (x86, amd64), the insn is treated as if
356 it makes just one memory reference (a modify), rather than two (a
357 read followed by a write at the same address).
358
359 At various points the list will need to be flushed, that is, IR
360 generated from it. That must happen before any possible exit from
361 the block (the end, or an IRStmt_Exit). Flushing also takes place
362 when there is no space to add a new event.
363
364 If we require the simulation statistics to be up to date with
365 respect to possible memory exceptions, then the list would have to
366 be flushed before each memory reference. That would however lose
367 performance by inhibiting event-merging during flushing.
368
369 Flushing the list consists of walking it start to end and emitting
370 instrumentation IR for each event, in the order in which they
371 appear. It may be possible to emit a single call for two adjacent
372 events in order to reduce the number of helper function calls made.
373 For example, it could well be profitable to handle two adjacent Ir
374 events with a single helper call. */
375
376typedef
377 IRExpr
378 IRAtom;
379
380typedef
sewardj20edebf2005-10-12 10:29:40 +0000381 enum { Event_Ir, Event_Dr, Event_Dw, Event_Dm }
sewardj5155dec2005-10-12 10:09:23 +0000382 EventKind;
383
384typedef
385 struct {
njnfd9f6222005-10-16 00:17:37 +0000386 EventKind ekind; // All
387 InstrInfo* inode; // All; inode for this event's instruction
388 Int datasize; // Dr/Dw/Dm only
389 IRAtom* dataEA; // Dr/Dw/Dm only; IR ATOM ONLY
sewardj5155dec2005-10-12 10:09:23 +0000390 }
391 Event;
392
393/* Up to this many unnotified events are allowed. Number is
394 arbitrary. Larger numbers allow more event merging to occur, but
395 potentially induce more spilling due to extending live ranges of
396 address temporaries. */
397#define N_EVENTS 16
398
399
400/* A struct which holds all the running state during instrumentation.
401 Mostly to avoid passing loads of parameters everywhere. */
402typedef
403 struct {
404 /* The current outstanding-memory-event list. */
405 Event events[N_EVENTS];
406 Int events_used;
407
njnd3bef4f2005-10-15 17:46:18 +0000408 /* The array of InstrInfo bins for the BB. */
sewardj5155dec2005-10-12 10:09:23 +0000409 BB_info* bbInfo;
410
njnd3bef4f2005-10-15 17:46:18 +0000411 /* Number InstrInfo bins 'used' so far. */
sewardj5155dec2005-10-12 10:09:23 +0000412 Int bbInfo_i;
413
sewardj5155dec2005-10-12 10:09:23 +0000414 /* The output BB being constructed. */
415 IRBB* bbOut;
416 }
417 CgState;
418
419
sewardj5155dec2005-10-12 10:09:23 +0000420/*------------------------------------------------------------*/
421/*--- Instrumentation main ---*/
nethercote9313ac42004-07-06 21:54:20 +0000422/*------------------------------------------------------------*/
423
sewardj4ba057c2005-10-18 12:04:18 +0000424// Note that origAddr is the real origAddr, not the address of the first
425// instruction in the block (they can be different due to redirection).
nethercote564b2b02004-08-07 15:54:53 +0000426static
sewardja3a29a52005-10-12 16:16:03 +0000427BB_info* get_BB_info(IRBB* bbIn, Addr origAddr)
nethercote9313ac42004-07-06 21:54:20 +0000428{
njn4bd67b52005-08-11 00:47:10 +0000429 Int i, n_instrs;
430 IRStmt* st;
431 BB_info* bbInfo;
njnd3bef4f2005-10-15 17:46:18 +0000432
njn6a3009b2005-03-20 00:20:06 +0000433 // Count number of original instrs in BB
434 n_instrs = 0;
435 for (i = 0; i < bbIn->stmts_used; i++) {
436 st = bbIn->stmts[i];
437 if (Ist_IMark == st->tag) n_instrs++;
nethercote9313ac42004-07-06 21:54:20 +0000438 }
439
njnf7d26092005-10-12 16:45:17 +0000440 // Check that we don't have an entry for this BB in the instr-info table.
441 // If this assertion fails, there has been some screwup: some
442 // translations must have been discarded but Cachegrind hasn't discarded
443 // the corresponding entries in the instr-info table.
njnd3bef4f2005-10-15 17:46:18 +0000444 bbInfo = VG_(OSet_Lookup)(instrInfoTable, &origAddr);
sewardja3a29a52005-10-12 16:16:03 +0000445 tl_assert(NULL == bbInfo);
446
njnd3bef4f2005-10-15 17:46:18 +0000447 // BB never translated before (at this address, at least; could have
448 // been unloaded and then reloaded elsewhere in memory)
449 bbInfo = VG_(OSet_AllocNode)(instrInfoTable,
450 sizeof(BB_info) + n_instrs*sizeof(InstrInfo));
451 bbInfo->BB_addr = origAddr;
sewardja3a29a52005-10-12 16:16:03 +0000452 bbInfo->n_instrs = n_instrs;
njnd3bef4f2005-10-15 17:46:18 +0000453 VG_(OSet_Insert)( instrInfoTable, bbInfo );
sewardja3a29a52005-10-12 16:16:03 +0000454 distinct_instrs++;
455
njn6a3009b2005-03-20 00:20:06 +0000456 return bbInfo;
nethercote9313ac42004-07-06 21:54:20 +0000457}
njn6a3009b2005-03-20 00:20:06 +0000458
nethercote9313ac42004-07-06 21:54:20 +0000459
sewardj5155dec2005-10-12 10:09:23 +0000460static void showEvent ( Event* ev )
nethercote9313ac42004-07-06 21:54:20 +0000461{
sewardj5155dec2005-10-12 10:09:23 +0000462 switch (ev->ekind) {
463 case Event_Ir:
njnfd9f6222005-10-16 00:17:37 +0000464 VG_(printf)("Ir %p\n", ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000465 break;
466 case Event_Dr:
njnfd9f6222005-10-16 00:17:37 +0000467 VG_(printf)("Dr %p %d EA=", ev->inode, ev->datasize);
sewardj5155dec2005-10-12 10:09:23 +0000468 ppIRExpr(ev->dataEA);
469 VG_(printf)("\n");
470 break;
471 case Event_Dw:
njnfd9f6222005-10-16 00:17:37 +0000472 VG_(printf)("Dw %p %d EA=", ev->inode, ev->datasize);
sewardj5155dec2005-10-12 10:09:23 +0000473 ppIRExpr(ev->dataEA);
474 VG_(printf)("\n");
475 break;
476 case Event_Dm:
njnfd9f6222005-10-16 00:17:37 +0000477 VG_(printf)("Dm %p %d EA=", ev->inode, ev->datasize);
sewardj5155dec2005-10-12 10:09:23 +0000478 ppIRExpr(ev->dataEA);
479 VG_(printf)("\n");
480 break;
481 default:
482 tl_assert(0);
483 break;
484 }
njn6a3009b2005-03-20 00:20:06 +0000485}
486
njnfd9f6222005-10-16 00:17:37 +0000487// Reserve and initialise an InstrInfo for the first mention of a new insn.
488static
489InstrInfo* setup_InstrInfo ( CgState* cgs, Addr instr_addr, UInt instr_len )
njn6a3009b2005-03-20 00:20:06 +0000490{
njnd3bef4f2005-10-15 17:46:18 +0000491 InstrInfo* i_node;
sewardj5155dec2005-10-12 10:09:23 +0000492 tl_assert(cgs->bbInfo_i >= 0);
493 tl_assert(cgs->bbInfo_i < cgs->bbInfo->n_instrs);
494 i_node = &cgs->bbInfo->instrs[ cgs->bbInfo_i ];
njnfd9f6222005-10-16 00:17:37 +0000495 i_node->instr_addr = instr_addr;
496 i_node->instr_len = instr_len;
497 i_node->parent = get_lineCC(instr_addr);
sewardj5155dec2005-10-12 10:09:23 +0000498 cgs->bbInfo_i++;
499 return i_node;
500}
sewardj17a56bf2005-03-21 01:35:02 +0000501
sewardj17a56bf2005-03-21 01:35:02 +0000502
sewardj5155dec2005-10-12 10:09:23 +0000503/* Generate code for all outstanding memory events, and mark the queue
504 empty. Code is generated into cgs->bbOut, and this activity
505 'consumes' slots in cgs->bbInfo. */
njn6a3009b2005-03-20 00:20:06 +0000506
sewardj5155dec2005-10-12 10:09:23 +0000507static void flushEvents ( CgState* cgs )
508{
njnd3bef4f2005-10-15 17:46:18 +0000509 Int i, regparms;
510 Char* helperName;
511 void* helperAddr;
512 IRExpr** argv;
513 IRExpr* i_node_expr;
njnd3bef4f2005-10-15 17:46:18 +0000514 IRDirty* di;
njnc285dca2005-10-15 22:07:28 +0000515 Event* ev;
516 Event* ev2;
517 Event* ev3;
njn6a3009b2005-03-20 00:20:06 +0000518
sewardj5155dec2005-10-12 10:09:23 +0000519 i = 0;
520 while (i < cgs->events_used) {
njn6a3009b2005-03-20 00:20:06 +0000521
sewardj5155dec2005-10-12 10:09:23 +0000522 helperName = NULL;
523 helperAddr = NULL;
524 argv = NULL;
525 regparms = 0;
526
527 /* generate IR to notify event i and possibly the ones
528 immediately following it. */
529 tl_assert(i >= 0 && i < cgs->events_used);
njnc285dca2005-10-15 22:07:28 +0000530
531 ev = &cgs->events[i];
532 ev2 = ( i < cgs->events_used-1 ? &cgs->events[i+1] : NULL );
533 ev3 = ( i < cgs->events_used-2 ? &cgs->events[i+2] : NULL );
534
sewardj5155dec2005-10-12 10:09:23 +0000535 if (DEBUG_CG) {
536 VG_(printf)(" flush ");
njnc285dca2005-10-15 22:07:28 +0000537 showEvent( ev );
njn4f9c9342002-04-29 16:03:24 +0000538 }
sewardj5155dec2005-10-12 10:09:23 +0000539
njnfd9f6222005-10-16 00:17:37 +0000540 i_node_expr = mkIRExpr_HWord( (HWord)ev->inode );
sewardj5155dec2005-10-12 10:09:23 +0000541
542 /* Decide on helper fn to call and args to pass it, and advance
543 i appropriately. */
njnc285dca2005-10-15 22:07:28 +0000544 switch (ev->ekind) {
sewardj5155dec2005-10-12 10:09:23 +0000545 case Event_Ir:
546 /* Merge with a following Dr/Dm if it is from this insn. */
njnc285dca2005-10-15 22:07:28 +0000547 if (ev2 && (ev2->ekind == Event_Dr || ev2->ekind == Event_Dm)) {
njnfd9f6222005-10-16 00:17:37 +0000548 tl_assert(ev2->inode == ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000549 helperName = "log_1I_1Dr_cache_access";
550 helperAddr = &log_1I_1Dr_cache_access;
551 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000552 ev2->dataEA,
njnfd9f6222005-10-16 00:17:37 +0000553 mkIRExpr_HWord( ev2->datasize ) );
sewardj5155dec2005-10-12 10:09:23 +0000554 regparms = 3;
555 i += 2;
556 }
557 /* Merge with a following Dw if it is from this insn. */
558 else
njnc285dca2005-10-15 22:07:28 +0000559 if (ev2 && ev2->ekind == Event_Dw) {
njnfd9f6222005-10-16 00:17:37 +0000560 tl_assert(ev2->inode == ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000561 helperName = "log_1I_1Dw_cache_access";
562 helperAddr = &log_1I_1Dw_cache_access;
563 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000564 ev2->dataEA,
njnfd9f6222005-10-16 00:17:37 +0000565 mkIRExpr_HWord( ev2->datasize ) );
sewardj5155dec2005-10-12 10:09:23 +0000566 regparms = 3;
567 i += 2;
568 }
569 /* Merge with two following Irs if possible. */
570 else
njnc285dca2005-10-15 22:07:28 +0000571 if (ev2 && ev3 && ev2->ekind == Event_Ir && ev3->ekind == Event_Ir)
572 {
sewardj5155dec2005-10-12 10:09:23 +0000573 helperName = "log_3I_0D_cache_access";
574 helperAddr = &log_3I_0D_cache_access;
njnfd9f6222005-10-16 00:17:37 +0000575 argv = mkIRExprVec_3( i_node_expr,
576 mkIRExpr_HWord( (HWord)ev2->inode ),
577 mkIRExpr_HWord( (HWord)ev3->inode ) );
sewardj5155dec2005-10-12 10:09:23 +0000578 regparms = 3;
579 i += 3;
580 }
581 /* Merge with a following Ir if possible. */
582 else
njnc285dca2005-10-15 22:07:28 +0000583 if (ev2 && ev2->ekind == Event_Ir) {
sewardj5155dec2005-10-12 10:09:23 +0000584 helperName = "log_2I_0D_cache_access";
585 helperAddr = &log_2I_0D_cache_access;
njnfd9f6222005-10-16 00:17:37 +0000586 argv = mkIRExprVec_2( i_node_expr,
587 mkIRExpr_HWord( (HWord)ev2->inode ) );
sewardj5155dec2005-10-12 10:09:23 +0000588 regparms = 2;
589 i += 2;
590 }
591 /* No merging possible; emit as-is. */
592 else {
njnc285dca2005-10-15 22:07:28 +0000593 // Assertion: this Event_Ir must be the last one in the
594 // events buffer, otherwise it would have been merged with a
595 // following event.
596 tl_assert(!ev2 && !ev3);
sewardj5155dec2005-10-12 10:09:23 +0000597 helperName = "log_1I_0D_cache_access";
598 helperAddr = &log_1I_0D_cache_access;
599 argv = mkIRExprVec_1( i_node_expr );
600 regparms = 1;
601 i++;
602 }
603 break;
604 case Event_Dr:
605 case Event_Dm:
606 helperName = "log_0I_1Dr_cache_access";
607 helperAddr = &log_0I_1Dr_cache_access;
608 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000609 ev->dataEA,
njnfd9f6222005-10-16 00:17:37 +0000610 mkIRExpr_HWord( ev->datasize ) );
sewardj5155dec2005-10-12 10:09:23 +0000611 regparms = 3;
612 i++;
613 break;
614 case Event_Dw:
615 helperName = "log_0I_1Dw_cache_access";
616 helperAddr = &log_0I_1Dw_cache_access;
617 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000618 ev->dataEA,
njnfd9f6222005-10-16 00:17:37 +0000619 mkIRExpr_HWord( ev->datasize ) );
sewardj5155dec2005-10-12 10:09:23 +0000620 regparms = 3;
621 i++;
622 break;
623 default:
624 tl_assert(0);
625 }
626
627 /* Add the helper. */
628 tl_assert(helperName);
629 tl_assert(helperAddr);
630 tl_assert(argv);
sewardj5bb86822005-12-23 12:47:42 +0000631 di = unsafeIRDirty_0_N( regparms,
632 helperName, VG_(fnptr_to_fnentry)( helperAddr ),
633 argv );
sewardj5155dec2005-10-12 10:09:23 +0000634 addStmtToIRBB( cgs->bbOut, IRStmt_Dirty(di) );
njn4f9c9342002-04-29 16:03:24 +0000635 }
636
sewardj5155dec2005-10-12 10:09:23 +0000637 cgs->events_used = 0;
njn4f9c9342002-04-29 16:03:24 +0000638}
njn14d01ce2004-11-26 11:30:14 +0000639
njnfd9f6222005-10-16 00:17:37 +0000640static void addEvent_Ir ( CgState* cgs, InstrInfo* inode )
sewardj5155dec2005-10-12 10:09:23 +0000641{
642 Event* evt;
sewardj5155dec2005-10-12 10:09:23 +0000643 if (cgs->events_used == N_EVENTS)
644 flushEvents(cgs);
645 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
646 evt = &cgs->events[cgs->events_used];
njnfd9f6222005-10-16 00:17:37 +0000647 evt->ekind = Event_Ir;
648 evt->inode = inode;
649 evt->datasize = 0;
650 evt->dataEA = NULL; /*paranoia*/
sewardj5155dec2005-10-12 10:09:23 +0000651 cgs->events_used++;
652}
653
njnfd9f6222005-10-16 00:17:37 +0000654static
655void addEvent_Dr ( CgState* cgs, InstrInfo* inode, Int datasize, IRAtom* ea )
sewardj5155dec2005-10-12 10:09:23 +0000656{
njnfd9f6222005-10-16 00:17:37 +0000657 Event* evt;
sewardj5155dec2005-10-12 10:09:23 +0000658 tl_assert(isIRAtom(ea));
njnfd9f6222005-10-16 00:17:37 +0000659 tl_assert(datasize >= 1 && datasize <= MIN_LINE_SIZE);
660 if (cgs->events_used == N_EVENTS)
661 flushEvents(cgs);
662 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
663 evt = &cgs->events[cgs->events_used];
664 evt->ekind = Event_Dr;
665 evt->inode = inode;
666 evt->datasize = datasize;
667 evt->dataEA = ea;
668 cgs->events_used++;
669}
sewardj5155dec2005-10-12 10:09:23 +0000670
njnfd9f6222005-10-16 00:17:37 +0000671static
672void addEvent_Dw ( CgState* cgs, InstrInfo* inode, Int datasize, IRAtom* ea )
673{
674 Event* lastEvt;
675 Event* evt;
676
677 tl_assert(isIRAtom(ea));
678 tl_assert(datasize >= 1 && datasize <= MIN_LINE_SIZE);
679
680 /* Is it possible to merge this write with the preceding read? */
681 lastEvt = &cgs->events[cgs->events_used-1];
sewardj5155dec2005-10-12 10:09:23 +0000682 if (cgs->events_used > 0
njnfd9f6222005-10-16 00:17:37 +0000683 && lastEvt->ekind == Event_Dr
684 && lastEvt->datasize == datasize
685 && lastEvt->inode == inode
686 && eqIRAtom(lastEvt->dataEA, ea))
687 {
688 lastEvt->ekind = Event_Dm;
sewardj5155dec2005-10-12 10:09:23 +0000689 return;
690 }
691
692 /* No. Add as normal. */
693 if (cgs->events_used == N_EVENTS)
694 flushEvents(cgs);
695 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
njnfd9f6222005-10-16 00:17:37 +0000696 evt = &cgs->events[cgs->events_used];
697 evt->ekind = Event_Dw;
698 evt->inode = inode;
699 evt->datasize = datasize;
700 evt->dataEA = ea;
sewardj5155dec2005-10-12 10:09:23 +0000701 cgs->events_used++;
702}
703
704////////////////////////////////////////////////////////////
705
706
sewardj4ba057c2005-10-18 12:04:18 +0000707static
sewardj461df9c2006-01-17 02:06:39 +0000708IRBB* cg_instrument ( VgCallbackClosure* closure,
709 IRBB* bbIn,
710 VexGuestLayout* layout,
711 VexGuestExtents* vge,
sewardj4ba057c2005-10-18 12:04:18 +0000712 IRType gWordTy, IRType hWordTy )
njn14d01ce2004-11-26 11:30:14 +0000713{
njnfd9f6222005-10-16 00:17:37 +0000714 Int i, isize;
sewardj5155dec2005-10-12 10:09:23 +0000715 IRStmt* st;
716 Addr64 cia; /* address of current insn */
717 CgState cgs;
718 IRTypeEnv* tyenv = bbIn->tyenv;
njnfd9f6222005-10-16 00:17:37 +0000719 InstrInfo* curr_inode = NULL;
sewardj5155dec2005-10-12 10:09:23 +0000720
sewardjd54babf2005-03-21 00:55:49 +0000721 if (gWordTy != hWordTy) {
722 /* We don't currently support this case. */
723 VG_(tool_panic)("host/guest word size mismatch");
724 }
725
njnfd9f6222005-10-16 00:17:37 +0000726 /* Set up BB, including copying of the where-next stuff. */
727 cgs.bbOut = emptyIRBB();
728 cgs.bbOut->tyenv = dopyIRTypeEnv(tyenv);
729 tl_assert( isIRAtom(bbIn->next) );
730 cgs.bbOut->next = dopyIRExpr(bbIn->next);
731 cgs.bbOut->jumpkind = bbIn->jumpkind;
njn6a3009b2005-03-20 00:20:06 +0000732
sewardja9f538c2005-10-23 12:06:55 +0000733 // Copy verbatim any IR preamble preceding the first IMark
njn6a3009b2005-03-20 00:20:06 +0000734 i = 0;
sewardja9f538c2005-10-23 12:06:55 +0000735 while (i < bbIn->stmts_used && bbIn->stmts[i]->tag != Ist_IMark) {
736 addStmtToIRBB( cgs.bbOut, bbIn->stmts[i] );
737 i++;
738 }
739
740 // Get the first statement, and initial cia from it
njn6a3009b2005-03-20 00:20:06 +0000741 tl_assert(bbIn->stmts_used > 0);
sewardja9f538c2005-10-23 12:06:55 +0000742 tl_assert(i < bbIn->stmts_used);
743 st = bbIn->stmts[i];
njn6a3009b2005-03-20 00:20:06 +0000744 tl_assert(Ist_IMark == st->tag);
sewardj5155dec2005-10-12 10:09:23 +0000745 cia = st->Ist.IMark.addr;
njn6a3009b2005-03-20 00:20:06 +0000746
sewardj5155dec2005-10-12 10:09:23 +0000747 // Set up running state and get block info
sewardj3a384b32006-01-22 01:12:51 +0000748 tl_assert(closure->readdr == vge->base[0]);
sewardj5155dec2005-10-12 10:09:23 +0000749 cgs.events_used = 0;
sewardj3a384b32006-01-22 01:12:51 +0000750 cgs.bbInfo = get_BB_info(bbIn, (Addr)closure->readdr);
sewardj5155dec2005-10-12 10:09:23 +0000751 cgs.bbInfo_i = 0;
njn6a3009b2005-03-20 00:20:06 +0000752
sewardj5155dec2005-10-12 10:09:23 +0000753 if (DEBUG_CG)
754 VG_(printf)("\n\n---------- cg_instrument ----------\n");
njn6a3009b2005-03-20 00:20:06 +0000755
njnfd9f6222005-10-16 00:17:37 +0000756 // Traverse the block, initialising inodes, adding events and flushing as
757 // necessary.
sewardja9f538c2005-10-23 12:06:55 +0000758 for (/*use current i*/; i < bbIn->stmts_used; i++) {
njn6a3009b2005-03-20 00:20:06 +0000759
sewardj5155dec2005-10-12 10:09:23 +0000760 st = bbIn->stmts[i];
761 tl_assert(isFlatIRStmt(st));
njnb3507ea2005-08-02 23:07:02 +0000762
sewardj5155dec2005-10-12 10:09:23 +0000763 switch (st->tag) {
764 case Ist_NoOp:
765 case Ist_AbiHint:
766 case Ist_Put:
767 case Ist_PutI:
768 case Ist_MFence:
769 break;
njn20677cc2005-08-12 23:47:51 +0000770
sewardj5155dec2005-10-12 10:09:23 +0000771 case Ist_IMark:
njnfd9f6222005-10-16 00:17:37 +0000772 cia = st->Ist.IMark.addr;
773 isize = st->Ist.IMark.len;
774
775 // If Vex fails to decode an instruction, the size will be zero.
776 // Pretend otherwise.
777 if (isize == 0) isize = VG_MIN_INSTR_SZB;
778
njna5ad9ba2005-11-10 15:20:37 +0000779 // Sanity-check size.
780 tl_assert( (VG_MIN_INSTR_SZB <= isize && isize <= VG_MAX_INSTR_SZB)
781 || VG_CLREQ_SZB == isize );
njnfd9f6222005-10-16 00:17:37 +0000782
783 // Get space for and init the inode, record it as the current one.
784 // Subsequent Dr/Dw/Dm events from the same instruction will
785 // also use it.
786 curr_inode = setup_InstrInfo(&cgs, cia, isize);
787
788 addEvent_Ir( &cgs, curr_inode );
sewardj5155dec2005-10-12 10:09:23 +0000789 break;
790
791 case Ist_Tmp: {
792 IRExpr* data = st->Ist.Tmp.data;
793 if (data->tag == Iex_Load) {
794 IRExpr* aexpr = data->Iex.Load.addr;
sewardj5155dec2005-10-12 10:09:23 +0000795 // Note also, endianness info is ignored. I guess
796 // that's not interesting.
njnfd9f6222005-10-16 00:17:37 +0000797 addEvent_Dr( &cgs, curr_inode, sizeofIRType(data->Iex.Load.ty),
798 aexpr );
sewardj5155dec2005-10-12 10:09:23 +0000799 }
800 break;
njnb3507ea2005-08-02 23:07:02 +0000801 }
802
sewardj5155dec2005-10-12 10:09:23 +0000803 case Ist_Store: {
804 IRExpr* data = st->Ist.Store.data;
805 IRExpr* aexpr = st->Ist.Store.addr;
njnfd9f6222005-10-16 00:17:37 +0000806 addEvent_Dw( &cgs, curr_inode,
807 sizeofIRType(typeOfIRExpr(tyenv, data)), aexpr );
sewardj5155dec2005-10-12 10:09:23 +0000808 break;
809 }
njnb3507ea2005-08-02 23:07:02 +0000810
sewardj5155dec2005-10-12 10:09:23 +0000811 case Ist_Dirty: {
812 Int dataSize;
813 IRDirty* d = st->Ist.Dirty.details;
814 if (d->mFx != Ifx_None) {
njnfd9f6222005-10-16 00:17:37 +0000815 /* This dirty helper accesses memory. Collect the details. */
sewardj5155dec2005-10-12 10:09:23 +0000816 tl_assert(d->mAddr != NULL);
817 tl_assert(d->mSize != 0);
818 dataSize = d->mSize;
819 // Large (eg. 28B, 108B, 512B on x86) data-sized
820 // instructions will be done inaccurately, but they're
821 // very rare and this avoids errors from hitting more
822 // than two cache lines in the simulation.
823 if (dataSize > MIN_LINE_SIZE)
824 dataSize = MIN_LINE_SIZE;
825 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
njnfd9f6222005-10-16 00:17:37 +0000826 addEvent_Dr( &cgs, curr_inode, dataSize, d->mAddr );
sewardj5155dec2005-10-12 10:09:23 +0000827 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
njnfd9f6222005-10-16 00:17:37 +0000828 addEvent_Dw( &cgs, curr_inode, dataSize, d->mAddr );
sewardj5155dec2005-10-12 10:09:23 +0000829 } else {
830 tl_assert(d->mAddr == NULL);
831 tl_assert(d->mSize == 0);
832 }
833 break;
834 }
njn6a3009b2005-03-20 00:20:06 +0000835
sewardj5155dec2005-10-12 10:09:23 +0000836 case Ist_Exit:
837 /* We may never reach the next statement, so need to flush
838 all outstanding transactions now. */
839 flushEvents( &cgs );
840 break;
841
842 default:
843 tl_assert(0);
844 break;
njnb3507ea2005-08-02 23:07:02 +0000845 }
njn6a3009b2005-03-20 00:20:06 +0000846
sewardj5155dec2005-10-12 10:09:23 +0000847 /* Copy the original statement */
848 addStmtToIRBB( cgs.bbOut, st );
njn6a3009b2005-03-20 00:20:06 +0000849
sewardj5155dec2005-10-12 10:09:23 +0000850 if (DEBUG_CG) {
851 ppIRStmt(st);
852 VG_(printf)("\n");
853 }
854 }
855
856 /* At the end of the bb. Flush outstandings. */
sewardj5155dec2005-10-12 10:09:23 +0000857 flushEvents( &cgs );
858
sewardj5155dec2005-10-12 10:09:23 +0000859 /* done. stay sane ... */
860 tl_assert(cgs.bbInfo_i == cgs.bbInfo->n_instrs);
861
862 if (DEBUG_CG) {
863 VG_(printf)( "goto {");
864 ppIRJumpKind(bbIn->jumpkind);
865 VG_(printf)( "} ");
866 ppIRExpr( bbIn->next );
867 VG_(printf)( "}\n");
868 }
869
870 return cgs.bbOut;
njn14d01ce2004-11-26 11:30:14 +0000871}
njn4f9c9342002-04-29 16:03:24 +0000872
873/*------------------------------------------------------------*/
nethercoteb35a8b92004-09-11 16:45:27 +0000874/*--- Cache configuration ---*/
njn4f9c9342002-04-29 16:03:24 +0000875/*------------------------------------------------------------*/
876
sewardjb5f6f512005-03-10 23:59:00 +0000877#define UNDEFINED_CACHE { -1, -1, -1 }
njn25e49d8e72002-09-23 09:36:25 +0000878
879static cache_t clo_I1_cache = UNDEFINED_CACHE;
880static cache_t clo_D1_cache = UNDEFINED_CACHE;
881static cache_t clo_L2_cache = UNDEFINED_CACHE;
882
njn7cf0bd32002-06-08 13:36:03 +0000883/* Checks cache config is ok; makes it so if not. */
sewardj07133bf2002-06-13 10:25:56 +0000884static
njna1d1a642004-11-26 18:36:02 +0000885void check_cache(cache_t* cache, Char *name)
njn7cf0bd32002-06-08 13:36:03 +0000886{
887 /* First check they're all powers of two */
sewardj07133bf2002-06-13 10:25:56 +0000888 if (-1 == VG_(log2)(cache->size)) {
njn7cf0bd32002-06-08 13:36:03 +0000889 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000890 "error: %s size of %dB not a power of two; aborting.",
891 name, cache->size);
892 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000893 }
894
sewardj07133bf2002-06-13 10:25:56 +0000895 if (-1 == VG_(log2)(cache->assoc)) {
njn7cf0bd32002-06-08 13:36:03 +0000896 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000897 "error: %s associativity of %d not a power of two; aborting.",
898 name, cache->assoc);
899 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000900 }
901
sewardj07133bf2002-06-13 10:25:56 +0000902 if (-1 == VG_(log2)(cache->line_size)) {
njn7cf0bd32002-06-08 13:36:03 +0000903 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000904 "error: %s line size of %dB not a power of two; aborting.",
905 name, cache->line_size);
906 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000907 }
908
njn6a3009b2005-03-20 00:20:06 +0000909 // Then check line size >= 16 -- any smaller and a single instruction could
910 // straddle three cache lines, which breaks a simulation assertion and is
911 // stupid anyway.
njn7cf0bd32002-06-08 13:36:03 +0000912 if (cache->line_size < MIN_LINE_SIZE) {
913 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000914 "error: %s line size of %dB too small; aborting.",
915 name, cache->line_size);
916 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000917 }
918
919 /* Then check cache size > line size (causes seg faults if not). */
920 if (cache->size <= cache->line_size) {
921 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000922 "error: %s cache size of %dB <= line size of %dB; aborting.",
923 name, cache->size, cache->line_size);
924 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000925 }
926
927 /* Then check assoc <= (size / line size) (seg faults otherwise). */
928 if (cache->assoc > (cache->size / cache->line_size)) {
929 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000930 "warning: %s associativity > (size / line size); aborting.", name);
931 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000932 }
933}
934
sewardj07133bf2002-06-13 10:25:56 +0000935static
nethercoteb35a8b92004-09-11 16:45:27 +0000936void configure_caches(cache_t* I1c, cache_t* D1c, cache_t* L2c)
njn7cf0bd32002-06-08 13:36:03 +0000937{
nethercote9313ac42004-07-06 21:54:20 +0000938#define DEFINED(L) (-1 != L.size || -1 != L.assoc || -1 != L.line_size)
939
nethercoteb35a8b92004-09-11 16:45:27 +0000940 Int n_clos = 0;
nethercote9313ac42004-07-06 21:54:20 +0000941
nethercoteb35a8b92004-09-11 16:45:27 +0000942 // Count how many were defined on the command line.
943 if (DEFINED(clo_I1_cache)) { n_clos++; }
944 if (DEFINED(clo_D1_cache)) { n_clos++; }
945 if (DEFINED(clo_L2_cache)) { n_clos++; }
njn7cf0bd32002-06-08 13:36:03 +0000946
njna1d1a642004-11-26 18:36:02 +0000947 // Set the cache config (using auto-detection, if supported by the
948 // architecture)
njnaf839f52005-06-23 03:27:57 +0000949 VG_(configure_caches)( I1c, D1c, L2c, (3 == n_clos) );
sewardjb1a77a42002-07-13 13:31:20 +0000950
nethercote9313ac42004-07-06 21:54:20 +0000951 // Then replace with any defined on the command line.
nethercoteb35a8b92004-09-11 16:45:27 +0000952 if (DEFINED(clo_I1_cache)) { *I1c = clo_I1_cache; }
953 if (DEFINED(clo_D1_cache)) { *D1c = clo_D1_cache; }
954 if (DEFINED(clo_L2_cache)) { *L2c = clo_L2_cache; }
njn7cf0bd32002-06-08 13:36:03 +0000955
nethercote9313ac42004-07-06 21:54:20 +0000956 // Then check values and fix if not acceptable.
njna1d1a642004-11-26 18:36:02 +0000957 check_cache(I1c, "I1");
958 check_cache(D1c, "D1");
959 check_cache(L2c, "L2");
njn7cf0bd32002-06-08 13:36:03 +0000960
961 if (VG_(clo_verbosity) > 1) {
962 VG_(message)(Vg_UserMsg, "Cache configuration used:");
963 VG_(message)(Vg_UserMsg, " I1: %dB, %d-way, %dB lines",
964 I1c->size, I1c->assoc, I1c->line_size);
965 VG_(message)(Vg_UserMsg, " D1: %dB, %d-way, %dB lines",
966 D1c->size, D1c->assoc, D1c->line_size);
967 VG_(message)(Vg_UserMsg, " L2: %dB, %d-way, %dB lines",
968 L2c->size, L2c->assoc, L2c->line_size);
969 }
nethercote9313ac42004-07-06 21:54:20 +0000970#undef CMD_LINE_DEFINED
njn7cf0bd32002-06-08 13:36:03 +0000971}
972
njn4f9c9342002-04-29 16:03:24 +0000973/*------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +0000974/*--- cg_fini() and related function ---*/
njn4f9c9342002-04-29 16:03:24 +0000975/*------------------------------------------------------------*/
976
nethercote9313ac42004-07-06 21:54:20 +0000977// Total reads/writes/misses. Calculated during CC traversal at the end.
978// All auto-zeroed.
979static CC Ir_total;
980static CC Dr_total;
981static CC Dw_total;
982
983static Char* cachegrind_out_file;
984
nethercote9313ac42004-07-06 21:54:20 +0000985static void fprint_CC_table_and_calc_totals(void)
986{
njnd3bef4f2005-10-15 17:46:18 +0000987 Int i, fd;
sewardj92645592005-07-23 09:18:34 +0000988 SysRes sres;
njnd3bef4f2005-10-15 17:46:18 +0000989 Char buf[512], *currFile = NULL, *currFn = NULL;
990 LineCC* lineCC;
njn4f9c9342002-04-29 16:03:24 +0000991
sewardj92645592005-07-23 09:18:34 +0000992 sres = VG_(open)(cachegrind_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
993 VKI_S_IRUSR|VKI_S_IWUSR);
994 if (sres.isError) {
nethercote9313ac42004-07-06 21:54:20 +0000995 // If the file can't be opened for whatever reason (conflict
996 // between multiple cachegrinded processes?), give up now.
njnee0e6a32005-04-24 00:21:01 +0000997 VG_(message)(Vg_UserMsg,
njn02bc4b82005-05-15 17:28:26 +0000998 "error: can't open cache simulation output file '%s'",
njnee0e6a32005-04-24 00:21:01 +0000999 cachegrind_out_file );
1000 VG_(message)(Vg_UserMsg,
1001 " ... so simulation results will be missing.");
sewardj0744b6c2002-12-11 00:45:42 +00001002 return;
sewardj92645592005-07-23 09:18:34 +00001003 } else {
1004 fd = sres.val;
sewardj0744b6c2002-12-11 00:45:42 +00001005 }
njn4f9c9342002-04-29 16:03:24 +00001006
nethercote9313ac42004-07-06 21:54:20 +00001007 // "desc:" lines (giving I1/D1/L2 cache configuration). The spaces after
1008 // the 2nd colon makes cg_annotate's output look nicer.
1009 VG_(sprintf)(buf, "desc: I1 cache: %s\n"
1010 "desc: D1 cache: %s\n"
1011 "desc: L2 cache: %s\n",
1012 I1.desc_line, D1.desc_line, L2.desc_line);
njn7cf0bd32002-06-08 13:36:03 +00001013 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njn4f9c9342002-04-29 16:03:24 +00001014
nethercote9313ac42004-07-06 21:54:20 +00001015 // "cmd:" line
njn4f9c9342002-04-29 16:03:24 +00001016 VG_(strcpy)(buf, "cmd:");
1017 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
sewardj45f4e7c2005-09-27 19:20:21 +00001018 if (VG_(args_the_exename)) {
1019 VG_(write)(fd, " ", 1);
1020 VG_(write)(fd, VG_(args_the_exename),
1021 VG_(strlen)( VG_(args_the_exename) ));
1022 }
1023 for (i = 0; i < VG_(args_for_client).used; i++) {
1024 if (VG_(args_for_client).strs[i]) {
1025 VG_(write)(fd, " ", 1);
1026 VG_(write)(fd, VG_(args_for_client).strs[i],
1027 VG_(strlen)(VG_(args_for_client).strs[i]));
1028 }
njn4f9c9342002-04-29 16:03:24 +00001029 }
nethercote9313ac42004-07-06 21:54:20 +00001030 // "events:" line
njn4f9c9342002-04-29 16:03:24 +00001031 VG_(sprintf)(buf, "\nevents: Ir I1mr I2mr Dr D1mr D2mr Dw D1mw D2mw\n");
1032 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1033
njnd3bef4f2005-10-15 17:46:18 +00001034 // Traverse every lineCC
1035 VG_(OSet_ResetIter)(CC_table);
1036 while ( (lineCC = VG_(OSet_Next)(CC_table)) ) {
njn4311fe62005-12-08 23:18:50 +00001037 Bool just_hit_a_new_file = False;
njnd3bef4f2005-10-15 17:46:18 +00001038 // If we've hit a new file, print a "fl=" line. Note that because
1039 // each string is stored exactly once in the string table, we can use
1040 // pointer comparison rather than strcmp() to test for equality, which
1041 // is good because most of the time the comparisons are equal and so
njn4311fe62005-12-08 23:18:50 +00001042 // the whole strings would have to be checked.
njnd3bef4f2005-10-15 17:46:18 +00001043 if ( lineCC->loc.file != currFile ) {
1044 currFile = lineCC->loc.file;
1045 VG_(sprintf)(buf, "fl=%s\n", currFile);
njn4f9c9342002-04-29 16:03:24 +00001046 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njnd3bef4f2005-10-15 17:46:18 +00001047 distinct_files++;
njn4311fe62005-12-08 23:18:50 +00001048 just_hit_a_new_file = True;
njn4f9c9342002-04-29 16:03:24 +00001049 }
njn4311fe62005-12-08 23:18:50 +00001050 // If we've hit a new function, print a "fn=" line. We know to do
1051 // this when the function name changes, and also every time we hit a
1052 // new file (in which case the new function name might be the same as
1053 // in the old file, hence the just_hit_a_new_file test).
1054 if ( just_hit_a_new_file || lineCC->loc.fn != currFn ) {
njnd3bef4f2005-10-15 17:46:18 +00001055 currFn = lineCC->loc.fn;
1056 VG_(sprintf)(buf, "fn=%s\n", currFn);
1057 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1058 distinct_fns++;
njn4311fe62005-12-08 23:18:50 +00001059 just_hit_a_new_file = False;
njnd3bef4f2005-10-15 17:46:18 +00001060 }
1061
1062 // Print the LineCC
1063 VG_(sprintf)(buf, "%u %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
1064 lineCC->loc.line,
1065 lineCC->Ir.a, lineCC->Ir.m1, lineCC->Ir.m2,
1066 lineCC->Dr.a, lineCC->Dr.m1, lineCC->Dr.m2,
1067 lineCC->Dw.a, lineCC->Dw.m1, lineCC->Dw.m2);
1068 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1069
1070 // Update summary stats
1071 Ir_total.a += lineCC->Ir.a;
1072 Ir_total.m1 += lineCC->Ir.m1;
1073 Ir_total.m2 += lineCC->Ir.m2;
1074 Dr_total.a += lineCC->Dr.a;
1075 Dr_total.m1 += lineCC->Dr.m1;
1076 Dr_total.m2 += lineCC->Dr.m2;
1077 Dw_total.a += lineCC->Dw.a;
1078 Dw_total.m1 += lineCC->Dw.m1;
1079 Dw_total.m2 += lineCC->Dw.m2;
1080
1081 distinct_lines++;
njn4f9c9342002-04-29 16:03:24 +00001082 }
1083
nethercote9313ac42004-07-06 21:54:20 +00001084 // Summary stats must come after rest of table, since we calculate them
1085 // during traversal. */
njn4f9c9342002-04-29 16:03:24 +00001086 VG_(sprintf)(buf, "summary: "
nethercote9313ac42004-07-06 21:54:20 +00001087 "%llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
njn4f9c9342002-04-29 16:03:24 +00001088 Ir_total.a, Ir_total.m1, Ir_total.m2,
1089 Dr_total.a, Dr_total.m1, Dr_total.m2,
1090 Dw_total.a, Dw_total.m1, Dw_total.m2);
1091 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1092 VG_(close)(fd);
1093}
1094
njn607adfc2003-09-30 14:15:44 +00001095static UInt ULong_width(ULong n)
njn4f9c9342002-04-29 16:03:24 +00001096{
njn607adfc2003-09-30 14:15:44 +00001097 UInt w = 0;
1098 while (n > 0) {
1099 n = n / 10;
1100 w++;
njn4f9c9342002-04-29 16:03:24 +00001101 }
sewardj46c59b12005-11-01 02:20:19 +00001102 if (w == 0) w = 1;
njn607adfc2003-09-30 14:15:44 +00001103 return w + (w-1)/3; // add space for commas
njn4f9c9342002-04-29 16:03:24 +00001104}
1105
njn51d827b2005-05-09 01:02:08 +00001106static void cg_fini(Int exitcode)
njn4f9c9342002-04-29 16:03:24 +00001107{
njn1baf7db2006-04-18 22:34:48 +00001108 static Char buf1[128], buf2[128], buf3[128], buf4[123], fmt[128];
njn607adfc2003-09-30 14:15:44 +00001109
njn4f9c9342002-04-29 16:03:24 +00001110 CC D_total;
njn1d021fa2002-05-02 13:56:34 +00001111 ULong L2_total_m, L2_total_mr, L2_total_mw,
1112 L2_total, L2_total_r, L2_total_w;
njn4f9c9342002-04-29 16:03:24 +00001113 Int l1, l2, l3;
1114 Int p;
1115
nethercote9313ac42004-07-06 21:54:20 +00001116 fprint_CC_table_and_calc_totals();
njn4f9c9342002-04-29 16:03:24 +00001117
njn7cf0bd32002-06-08 13:36:03 +00001118 if (VG_(clo_verbosity) == 0)
1119 return;
1120
njn4f9c9342002-04-29 16:03:24 +00001121 /* I cache results. Use the I_refs value to determine the first column
1122 * width. */
njn607adfc2003-09-30 14:15:44 +00001123 l1 = ULong_width(Ir_total.a);
1124 l2 = ULong_width(Dr_total.a);
1125 l3 = ULong_width(Dw_total.a);
njn4f9c9342002-04-29 16:03:24 +00001126
njn607adfc2003-09-30 14:15:44 +00001127 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001128 VG_(sprintf)(fmt, "%%s %%,%dllu", l1);
njnd3bef4f2005-10-15 17:46:18 +00001129
njn607adfc2003-09-30 14:15:44 +00001130 VG_(message)(Vg_UserMsg, fmt, "I refs: ", Ir_total.a);
1131 VG_(message)(Vg_UserMsg, fmt, "I1 misses: ", Ir_total.m1);
1132 VG_(message)(Vg_UserMsg, fmt, "L2i misses: ", Ir_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001133
1134 p = 100;
1135
njn25e49d8e72002-09-23 09:36:25 +00001136 if (0 == Ir_total.a) Ir_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001137 VG_(percentify)(Ir_total.m1, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001138 VG_(message)(Vg_UserMsg, "I1 miss rate: %s", buf1);
njnd3bef4f2005-10-15 17:46:18 +00001139
njn856c54e2005-06-26 18:43:40 +00001140 VG_(percentify)(Ir_total.m2, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001141 VG_(message)(Vg_UserMsg, "L2i miss rate: %s", buf1);
1142 VG_(message)(Vg_UserMsg, "");
1143
1144 /* D cache results. Use the D_refs.rd and D_refs.wr values to determine the
1145 * width of columns 2 & 3. */
1146 D_total.a = Dr_total.a + Dw_total.a;
1147 D_total.m1 = Dr_total.m1 + Dw_total.m1;
1148 D_total.m2 = Dr_total.m2 + Dw_total.m2;
njnd3bef4f2005-10-15 17:46:18 +00001149
njn607adfc2003-09-30 14:15:44 +00001150 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001151 VG_(sprintf)(fmt, "%%s %%,%dllu (%%,%dllu rd + %%,%dllu wr)", l1, l2, l3);
njn4f9c9342002-04-29 16:03:24 +00001152
njn607adfc2003-09-30 14:15:44 +00001153 VG_(message)(Vg_UserMsg, fmt, "D refs: ",
1154 D_total.a, Dr_total.a, Dw_total.a);
1155 VG_(message)(Vg_UserMsg, fmt, "D1 misses: ",
1156 D_total.m1, Dr_total.m1, Dw_total.m1);
1157 VG_(message)(Vg_UserMsg, fmt, "L2d misses: ",
1158 D_total.m2, Dr_total.m2, Dw_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001159
1160 p = 10;
njnd3bef4f2005-10-15 17:46:18 +00001161
njn25e49d8e72002-09-23 09:36:25 +00001162 if (0 == D_total.a) D_total.a = 1;
1163 if (0 == Dr_total.a) Dr_total.a = 1;
1164 if (0 == Dw_total.a) Dw_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001165 VG_(percentify)( D_total.m1, D_total.a, 1, l1+1, buf1);
1166 VG_(percentify)(Dr_total.m1, Dr_total.a, 1, l2+1, buf2);
1167 VG_(percentify)(Dw_total.m1, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001168 VG_(message)(Vg_UserMsg, "D1 miss rate: %s (%s + %s )", buf1, buf2,buf3);
1169
njn856c54e2005-06-26 18:43:40 +00001170 VG_(percentify)( D_total.m2, D_total.a, 1, l1+1, buf1);
1171 VG_(percentify)(Dr_total.m2, Dr_total.a, 1, l2+1, buf2);
1172 VG_(percentify)(Dw_total.m2, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001173 VG_(message)(Vg_UserMsg, "L2d miss rate: %s (%s + %s )", buf1, buf2,buf3);
1174 VG_(message)(Vg_UserMsg, "");
1175
1176 /* L2 overall results */
njn1d021fa2002-05-02 13:56:34 +00001177
1178 L2_total = Dr_total.m1 + Dw_total.m1 + Ir_total.m1;
1179 L2_total_r = Dr_total.m1 + Ir_total.m1;
1180 L2_total_w = Dw_total.m1;
njn607adfc2003-09-30 14:15:44 +00001181 VG_(message)(Vg_UserMsg, fmt, "L2 refs: ",
1182 L2_total, L2_total_r, L2_total_w);
njn1d021fa2002-05-02 13:56:34 +00001183
njn4f9c9342002-04-29 16:03:24 +00001184 L2_total_m = Dr_total.m2 + Dw_total.m2 + Ir_total.m2;
1185 L2_total_mr = Dr_total.m2 + Ir_total.m2;
1186 L2_total_mw = Dw_total.m2;
njn607adfc2003-09-30 14:15:44 +00001187 VG_(message)(Vg_UserMsg, fmt, "L2 misses: ",
1188 L2_total_m, L2_total_mr, L2_total_mw);
njn4f9c9342002-04-29 16:03:24 +00001189
njn856c54e2005-06-26 18:43:40 +00001190 VG_(percentify)(L2_total_m, (Ir_total.a + D_total.a), 1, l1+1, buf1);
1191 VG_(percentify)(L2_total_mr, (Ir_total.a + Dr_total.a), 1, l2+1, buf2);
1192 VG_(percentify)(L2_total_mw, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001193 VG_(message)(Vg_UserMsg, "L2 miss rate: %s (%s + %s )", buf1, buf2,buf3);
njnd3bef4f2005-10-15 17:46:18 +00001194
njn4f9c9342002-04-29 16:03:24 +00001195
nethercote9313ac42004-07-06 21:54:20 +00001196 // Various stats
njn4f9c9342002-04-29 16:03:24 +00001197 if (VG_(clo_verbosity) > 1) {
njn1baf7db2006-04-18 22:34:48 +00001198 Int debug_lookups = full_debugs + fn_debugs +
1199 file_line_debugs + no_debugs;
njnd3bef4f2005-10-15 17:46:18 +00001200
njn1baf7db2006-04-18 22:34:48 +00001201 VG_(message)(Vg_DebugMsg, "");
1202 VG_(message)(Vg_DebugMsg, "cachegrind: distinct files: %d", distinct_files);
1203 VG_(message)(Vg_DebugMsg, "cachegrind: distinct fns: %d", distinct_fns);
1204 VG_(message)(Vg_DebugMsg, "cachegrind: distinct lines: %d", distinct_lines);
1205 VG_(message)(Vg_DebugMsg, "cachegrind: distinct instrs:%d", distinct_instrs);
1206 VG_(message)(Vg_DebugMsg, "cachegrind: debug lookups : %d", debug_lookups);
1207
1208 VG_(percentify)(full_debugs, debug_lookups, 1, 6, buf1);
1209 VG_(percentify)(file_line_debugs, debug_lookups, 1, 6, buf2);
1210 VG_(percentify)(fn_debugs, debug_lookups, 1, 6, buf3);
1211 VG_(percentify)(no_debugs, debug_lookups, 1, 6, buf4);
1212 VG_(message)(Vg_DebugMsg, "cachegrind: with full info:%s (%d)",
1213 buf1, full_debugs);
1214 VG_(message)(Vg_DebugMsg, "cachegrind: with file/line info:%s (%d)",
1215 buf2, file_line_debugs);
1216 VG_(message)(Vg_DebugMsg, "cachegrind: with fn name info:%s (%d)",
1217 buf3, fn_debugs);
1218 VG_(message)(Vg_DebugMsg, "cachegrind: with zero info:%s (%d)",
1219 buf4, no_debugs);
1220
1221 VG_(message)(Vg_DebugMsg, "cachegrind: string table size: %u",
1222 VG_(OSet_Size)(stringTable));
1223 VG_(message)(Vg_DebugMsg, "cachegrind: CC table size: %u",
1224 VG_(OSet_Size)(CC_table));
1225 VG_(message)(Vg_DebugMsg, "cachegrind: InstrInfo table size: %u",
1226 VG_(OSet_Size)(instrInfoTable));
njn4f9c9342002-04-29 16:03:24 +00001227 }
njn4f9c9342002-04-29 16:03:24 +00001228}
1229
nethercote9313ac42004-07-06 21:54:20 +00001230/*--------------------------------------------------------------------*/
1231/*--- Discarding BB info ---*/
1232/*--------------------------------------------------------------------*/
sewardj18d75132002-05-16 11:06:21 +00001233
sewardja3a29a52005-10-12 16:16:03 +00001234// Called when a translation is removed from the translation cache for
1235// any reason at all: to free up space, because the guest code was
1236// unmapped or modified, or for any arbitrary reason.
sewardj4ba057c2005-10-18 12:04:18 +00001237static
1238void cg_discard_basic_block_info ( Addr64 orig_addr64, VexGuestExtents vge )
sewardj18d75132002-05-16 11:06:21 +00001239{
njnd3bef4f2005-10-15 17:46:18 +00001240 BB_info* bbInfo;
sewardj3a384b32006-01-22 01:12:51 +00001241 Addr orig_addr = (Addr)vge.base[0];
njn4294fd42002-06-05 14:41:10 +00001242
sewardj5155dec2005-10-12 10:09:23 +00001243 tl_assert(vge.n_used > 0);
1244
1245 if (DEBUG_CG)
sewardj4ba057c2005-10-18 12:04:18 +00001246 VG_(printf)( "discard_basic_block_info: %p, %p, %llu\n",
1247 (void*)(Addr)orig_addr,
sewardj5155dec2005-10-12 10:09:23 +00001248 (void*)(Addr)vge.base[0], (ULong)vge.len[0]);
njn4294fd42002-06-05 14:41:10 +00001249
sewardj4ba057c2005-10-18 12:04:18 +00001250 // Get BB info, remove from table, free BB info. Simple! Note that we
1251 // use orig_addr, not the first instruction address in vge.
1252 bbInfo = VG_(OSet_Remove)(instrInfoTable, &orig_addr);
njn6a3009b2005-03-20 00:20:06 +00001253 tl_assert(NULL != bbInfo);
njnd3bef4f2005-10-15 17:46:18 +00001254 VG_(OSet_FreeNode)(instrInfoTable, bbInfo);
sewardj18d75132002-05-16 11:06:21 +00001255}
1256
1257/*--------------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001258/*--- Command line processing ---*/
1259/*--------------------------------------------------------------------*/
1260
njn0103de52005-10-10 16:49:01 +00001261static void parse_cache_opt ( cache_t* cache, Char* opt )
njn25e49d8e72002-09-23 09:36:25 +00001262{
njn0103de52005-10-10 16:49:01 +00001263 Int i = 0, i2, i3;
njn25e49d8e72002-09-23 09:36:25 +00001264
nethercote9313ac42004-07-06 21:54:20 +00001265 // Option argument looks like "65536,2,64".
1266 // Find commas, replace with NULs to make three independent
1267 // strings, then extract numbers, put NULs back. Yuck.
njn25e49d8e72002-09-23 09:36:25 +00001268 while (VG_(isdigit)(opt[i])) i++;
1269 if (',' == opt[i]) {
1270 opt[i++] = '\0';
1271 i2 = i;
1272 } else goto bad;
1273 while (VG_(isdigit)(opt[i])) i++;
1274 if (',' == opt[i]) {
1275 opt[i++] = '\0';
1276 i3 = i;
1277 } else goto bad;
1278 while (VG_(isdigit)(opt[i])) i++;
1279 if ('\0' != opt[i]) goto bad;
1280
nethercote9313ac42004-07-06 21:54:20 +00001281 cache->size = (Int)VG_(atoll)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001282 cache->assoc = (Int)VG_(atoll)(opt + i2);
1283 cache->line_size = (Int)VG_(atoll)(opt + i3);
1284
nethercote9313ac42004-07-06 21:54:20 +00001285 opt[i2-1] = ',';
1286 opt[i3-1] = ',';
njn25e49d8e72002-09-23 09:36:25 +00001287 return;
1288
1289 bad:
nethercote9313ac42004-07-06 21:54:20 +00001290 VG_(bad_option)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001291}
1292
njn51d827b2005-05-09 01:02:08 +00001293static Bool cg_process_cmd_line_option(Char* arg)
njn25e49d8e72002-09-23 09:36:25 +00001294{
nethercote9313ac42004-07-06 21:54:20 +00001295 // 5 is length of "--I1="
njn39c86652003-05-21 10:13:39 +00001296 if (VG_CLO_STREQN(5, arg, "--I1="))
nethercote9313ac42004-07-06 21:54:20 +00001297 parse_cache_opt(&clo_I1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001298 else if (VG_CLO_STREQN(5, arg, "--D1="))
nethercote9313ac42004-07-06 21:54:20 +00001299 parse_cache_opt(&clo_D1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001300 else if (VG_CLO_STREQN(5, arg, "--L2="))
nethercote9313ac42004-07-06 21:54:20 +00001301 parse_cache_opt(&clo_L2_cache, &arg[5]);
njn25e49d8e72002-09-23 09:36:25 +00001302 else
1303 return False;
1304
1305 return True;
1306}
1307
njn51d827b2005-05-09 01:02:08 +00001308static void cg_print_usage(void)
njn25e49d8e72002-09-23 09:36:25 +00001309{
njn3e884182003-04-15 13:03:23 +00001310 VG_(printf)(
njn25e49d8e72002-09-23 09:36:25 +00001311" --I1=<size>,<assoc>,<line_size> set I1 cache manually\n"
1312" --D1=<size>,<assoc>,<line_size> set D1 cache manually\n"
njn3e884182003-04-15 13:03:23 +00001313" --L2=<size>,<assoc>,<line_size> set L2 cache manually\n"
1314 );
1315}
1316
njn51d827b2005-05-09 01:02:08 +00001317static void cg_print_debug_usage(void)
njn3e884182003-04-15 13:03:23 +00001318{
1319 VG_(printf)(
1320" (none)\n"
1321 );
njn25e49d8e72002-09-23 09:36:25 +00001322}
1323
1324/*--------------------------------------------------------------------*/
1325/*--- Setup ---*/
1326/*--------------------------------------------------------------------*/
1327
njn51d827b2005-05-09 01:02:08 +00001328static void cg_post_clo_init(void)
njn25e49d8e72002-09-23 09:36:25 +00001329{
1330 cache_t I1c, D1c, L2c;
njn25e49d8e72002-09-23 09:36:25 +00001331
nethercoteb35a8b92004-09-11 16:45:27 +00001332 configure_caches(&I1c, &D1c, &L2c);
njn25e49d8e72002-09-23 09:36:25 +00001333
1334 cachesim_I1_initcache(I1c);
1335 cachesim_D1_initcache(D1c);
1336 cachesim_L2_initcache(L2c);
njn25e49d8e72002-09-23 09:36:25 +00001337}
1338
njn57ca7ab2005-06-21 23:44:58 +00001339static Char base_dir[VKI_PATH_MAX];
1340
njn51d827b2005-05-09 01:02:08 +00001341static void cg_pre_clo_init(void)
1342{
njn51d827b2005-05-09 01:02:08 +00001343 VG_(details_name) ("Cachegrind");
1344 VG_(details_version) (NULL);
1345 VG_(details_description) ("an I1/D1/L2 cache profiler");
1346 VG_(details_copyright_author)(
1347 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote et al.");
1348 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj5155dec2005-10-12 10:09:23 +00001349 VG_(details_avg_translation_sizeB) ( 245 );
njn51d827b2005-05-09 01:02:08 +00001350
1351 VG_(basic_tool_funcs) (cg_post_clo_init,
1352 cg_instrument,
1353 cg_fini);
1354
1355 VG_(needs_basic_block_discards)(cg_discard_basic_block_info);
1356 VG_(needs_command_line_options)(cg_process_cmd_line_option,
1357 cg_print_usage,
1358 cg_print_debug_usage);
1359
1360 /* Get working directory */
njn57ca7ab2005-06-21 23:44:58 +00001361 tl_assert( VG_(getcwd)(base_dir, VKI_PATH_MAX) );
njn51d827b2005-05-09 01:02:08 +00001362
1363 /* Block is big enough for dir name + cachegrind.out.<pid> */
1364 cachegrind_out_file = VG_(malloc)((VG_(strlen)(base_dir) + 32)*sizeof(Char));
1365 VG_(sprintf)(cachegrind_out_file, "%s/cachegrind.out.%d",
1366 base_dir, VG_(getpid)());
njn51d827b2005-05-09 01:02:08 +00001367
njnd3bef4f2005-10-15 17:46:18 +00001368 CC_table = VG_(OSet_Create)(offsetof(LineCC, loc),
1369 cmp_CodeLoc_LineCC,
1370 VG_(malloc), VG_(free));
sewardj4ba057c2005-10-18 12:04:18 +00001371 instrInfoTable = VG_(OSet_Create)(/*keyOff*/0,
njnd3bef4f2005-10-15 17:46:18 +00001372 NULL,
1373 VG_(malloc), VG_(free));
1374 stringTable = VG_(OSet_Create)(/*keyOff*/0,
1375 stringCmp,
1376 VG_(malloc), VG_(free));
njn51d827b2005-05-09 01:02:08 +00001377}
1378
sewardj45f4e7c2005-09-27 19:20:21 +00001379VG_DETERMINE_INTERFACE_VERSION(cg_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00001380
njn25e49d8e72002-09-23 09:36:25 +00001381/*--------------------------------------------------------------------*/
njnf69f9452005-07-03 17:53:11 +00001382/*--- end ---*/
sewardj18d75132002-05-16 11:06:21 +00001383/*--------------------------------------------------------------------*/
njnd3bef4f2005-10-15 17:46:18 +00001384