blob: 7d5f6667135841457ccbceeb28e164385f6b67b0 [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
708IRBB* cg_instrument ( IRBB* bbIn, VexGuestLayout* layout,
709 Addr64 orig_addr_noredir, VexGuestExtents* vge,
710 IRType gWordTy, IRType hWordTy )
njn14d01ce2004-11-26 11:30:14 +0000711{
njnfd9f6222005-10-16 00:17:37 +0000712 Int i, isize;
sewardj5155dec2005-10-12 10:09:23 +0000713 IRStmt* st;
714 Addr64 cia; /* address of current insn */
715 CgState cgs;
716 IRTypeEnv* tyenv = bbIn->tyenv;
njnfd9f6222005-10-16 00:17:37 +0000717 InstrInfo* curr_inode = NULL;
sewardj5155dec2005-10-12 10:09:23 +0000718
sewardjd54babf2005-03-21 00:55:49 +0000719 if (gWordTy != hWordTy) {
720 /* We don't currently support this case. */
721 VG_(tool_panic)("host/guest word size mismatch");
722 }
723
njnfd9f6222005-10-16 00:17:37 +0000724 /* Set up BB, including copying of the where-next stuff. */
725 cgs.bbOut = emptyIRBB();
726 cgs.bbOut->tyenv = dopyIRTypeEnv(tyenv);
727 tl_assert( isIRAtom(bbIn->next) );
728 cgs.bbOut->next = dopyIRExpr(bbIn->next);
729 cgs.bbOut->jumpkind = bbIn->jumpkind;
njn6a3009b2005-03-20 00:20:06 +0000730
sewardja9f538c2005-10-23 12:06:55 +0000731 // Copy verbatim any IR preamble preceding the first IMark
njn6a3009b2005-03-20 00:20:06 +0000732 i = 0;
sewardja9f538c2005-10-23 12:06:55 +0000733 while (i < bbIn->stmts_used && bbIn->stmts[i]->tag != Ist_IMark) {
734 addStmtToIRBB( cgs.bbOut, bbIn->stmts[i] );
735 i++;
736 }
737
738 // Get the first statement, and initial cia from it
njn6a3009b2005-03-20 00:20:06 +0000739 tl_assert(bbIn->stmts_used > 0);
sewardja9f538c2005-10-23 12:06:55 +0000740 tl_assert(i < bbIn->stmts_used);
741 st = bbIn->stmts[i];
njn6a3009b2005-03-20 00:20:06 +0000742 tl_assert(Ist_IMark == st->tag);
sewardj5155dec2005-10-12 10:09:23 +0000743 cia = st->Ist.IMark.addr;
njn6a3009b2005-03-20 00:20:06 +0000744
sewardj5155dec2005-10-12 10:09:23 +0000745 // Set up running state and get block info
746 cgs.events_used = 0;
sewardj4ba057c2005-10-18 12:04:18 +0000747 cgs.bbInfo = get_BB_info(bbIn, (Addr)orig_addr_noredir);
sewardj5155dec2005-10-12 10:09:23 +0000748 cgs.bbInfo_i = 0;
njn6a3009b2005-03-20 00:20:06 +0000749
sewardj5155dec2005-10-12 10:09:23 +0000750 if (DEBUG_CG)
751 VG_(printf)("\n\n---------- cg_instrument ----------\n");
njn6a3009b2005-03-20 00:20:06 +0000752
njnfd9f6222005-10-16 00:17:37 +0000753 // Traverse the block, initialising inodes, adding events and flushing as
754 // necessary.
sewardja9f538c2005-10-23 12:06:55 +0000755 for (/*use current i*/; i < bbIn->stmts_used; i++) {
njn6a3009b2005-03-20 00:20:06 +0000756
sewardj5155dec2005-10-12 10:09:23 +0000757 st = bbIn->stmts[i];
758 tl_assert(isFlatIRStmt(st));
njnb3507ea2005-08-02 23:07:02 +0000759
sewardj5155dec2005-10-12 10:09:23 +0000760 switch (st->tag) {
761 case Ist_NoOp:
762 case Ist_AbiHint:
763 case Ist_Put:
764 case Ist_PutI:
765 case Ist_MFence:
766 break;
njn20677cc2005-08-12 23:47:51 +0000767
sewardj5155dec2005-10-12 10:09:23 +0000768 case Ist_IMark:
njnfd9f6222005-10-16 00:17:37 +0000769 cia = st->Ist.IMark.addr;
770 isize = st->Ist.IMark.len;
771
772 // If Vex fails to decode an instruction, the size will be zero.
773 // Pretend otherwise.
774 if (isize == 0) isize = VG_MIN_INSTR_SZB;
775
njna5ad9ba2005-11-10 15:20:37 +0000776 // Sanity-check size.
777 tl_assert( (VG_MIN_INSTR_SZB <= isize && isize <= VG_MAX_INSTR_SZB)
778 || VG_CLREQ_SZB == isize );
njnfd9f6222005-10-16 00:17:37 +0000779
780 // Get space for and init the inode, record it as the current one.
781 // Subsequent Dr/Dw/Dm events from the same instruction will
782 // also use it.
783 curr_inode = setup_InstrInfo(&cgs, cia, isize);
784
785 addEvent_Ir( &cgs, curr_inode );
sewardj5155dec2005-10-12 10:09:23 +0000786 break;
787
788 case Ist_Tmp: {
789 IRExpr* data = st->Ist.Tmp.data;
790 if (data->tag == Iex_Load) {
791 IRExpr* aexpr = data->Iex.Load.addr;
sewardj5155dec2005-10-12 10:09:23 +0000792 // Note also, endianness info is ignored. I guess
793 // that's not interesting.
njnfd9f6222005-10-16 00:17:37 +0000794 addEvent_Dr( &cgs, curr_inode, sizeofIRType(data->Iex.Load.ty),
795 aexpr );
sewardj5155dec2005-10-12 10:09:23 +0000796 }
797 break;
njnb3507ea2005-08-02 23:07:02 +0000798 }
799
sewardj5155dec2005-10-12 10:09:23 +0000800 case Ist_Store: {
801 IRExpr* data = st->Ist.Store.data;
802 IRExpr* aexpr = st->Ist.Store.addr;
njnfd9f6222005-10-16 00:17:37 +0000803 addEvent_Dw( &cgs, curr_inode,
804 sizeofIRType(typeOfIRExpr(tyenv, data)), aexpr );
sewardj5155dec2005-10-12 10:09:23 +0000805 break;
806 }
njnb3507ea2005-08-02 23:07:02 +0000807
sewardj5155dec2005-10-12 10:09:23 +0000808 case Ist_Dirty: {
809 Int dataSize;
810 IRDirty* d = st->Ist.Dirty.details;
811 if (d->mFx != Ifx_None) {
njnfd9f6222005-10-16 00:17:37 +0000812 /* This dirty helper accesses memory. Collect the details. */
sewardj5155dec2005-10-12 10:09:23 +0000813 tl_assert(d->mAddr != NULL);
814 tl_assert(d->mSize != 0);
815 dataSize = d->mSize;
816 // Large (eg. 28B, 108B, 512B on x86) data-sized
817 // instructions will be done inaccurately, but they're
818 // very rare and this avoids errors from hitting more
819 // than two cache lines in the simulation.
820 if (dataSize > MIN_LINE_SIZE)
821 dataSize = MIN_LINE_SIZE;
822 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
njnfd9f6222005-10-16 00:17:37 +0000823 addEvent_Dr( &cgs, curr_inode, dataSize, d->mAddr );
sewardj5155dec2005-10-12 10:09:23 +0000824 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
njnfd9f6222005-10-16 00:17:37 +0000825 addEvent_Dw( &cgs, curr_inode, dataSize, d->mAddr );
sewardj5155dec2005-10-12 10:09:23 +0000826 } else {
827 tl_assert(d->mAddr == NULL);
828 tl_assert(d->mSize == 0);
829 }
830 break;
831 }
njn6a3009b2005-03-20 00:20:06 +0000832
sewardj5155dec2005-10-12 10:09:23 +0000833 case Ist_Exit:
834 /* We may never reach the next statement, so need to flush
835 all outstanding transactions now. */
836 flushEvents( &cgs );
837 break;
838
839 default:
840 tl_assert(0);
841 break;
njnb3507ea2005-08-02 23:07:02 +0000842 }
njn6a3009b2005-03-20 00:20:06 +0000843
sewardj5155dec2005-10-12 10:09:23 +0000844 /* Copy the original statement */
845 addStmtToIRBB( cgs.bbOut, st );
njn6a3009b2005-03-20 00:20:06 +0000846
sewardj5155dec2005-10-12 10:09:23 +0000847 if (DEBUG_CG) {
848 ppIRStmt(st);
849 VG_(printf)("\n");
850 }
851 }
852
853 /* At the end of the bb. Flush outstandings. */
sewardj5155dec2005-10-12 10:09:23 +0000854 flushEvents( &cgs );
855
sewardj5155dec2005-10-12 10:09:23 +0000856 /* done. stay sane ... */
857 tl_assert(cgs.bbInfo_i == cgs.bbInfo->n_instrs);
858
859 if (DEBUG_CG) {
860 VG_(printf)( "goto {");
861 ppIRJumpKind(bbIn->jumpkind);
862 VG_(printf)( "} ");
863 ppIRExpr( bbIn->next );
864 VG_(printf)( "}\n");
865 }
866
867 return cgs.bbOut;
njn14d01ce2004-11-26 11:30:14 +0000868}
njn4f9c9342002-04-29 16:03:24 +0000869
870/*------------------------------------------------------------*/
nethercoteb35a8b92004-09-11 16:45:27 +0000871/*--- Cache configuration ---*/
njn4f9c9342002-04-29 16:03:24 +0000872/*------------------------------------------------------------*/
873
sewardjb5f6f512005-03-10 23:59:00 +0000874#define UNDEFINED_CACHE { -1, -1, -1 }
njn25e49d8e72002-09-23 09:36:25 +0000875
876static cache_t clo_I1_cache = UNDEFINED_CACHE;
877static cache_t clo_D1_cache = UNDEFINED_CACHE;
878static cache_t clo_L2_cache = UNDEFINED_CACHE;
879
njn7cf0bd32002-06-08 13:36:03 +0000880/* Checks cache config is ok; makes it so if not. */
sewardj07133bf2002-06-13 10:25:56 +0000881static
njna1d1a642004-11-26 18:36:02 +0000882void check_cache(cache_t* cache, Char *name)
njn7cf0bd32002-06-08 13:36:03 +0000883{
884 /* First check they're all powers of two */
sewardj07133bf2002-06-13 10:25:56 +0000885 if (-1 == VG_(log2)(cache->size)) {
njn7cf0bd32002-06-08 13:36:03 +0000886 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000887 "error: %s size of %dB not a power of two; aborting.",
888 name, cache->size);
889 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000890 }
891
sewardj07133bf2002-06-13 10:25:56 +0000892 if (-1 == VG_(log2)(cache->assoc)) {
njn7cf0bd32002-06-08 13:36:03 +0000893 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000894 "error: %s associativity of %d not a power of two; aborting.",
895 name, cache->assoc);
896 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000897 }
898
sewardj07133bf2002-06-13 10:25:56 +0000899 if (-1 == VG_(log2)(cache->line_size)) {
njn7cf0bd32002-06-08 13:36:03 +0000900 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000901 "error: %s line size of %dB not a power of two; aborting.",
902 name, cache->line_size);
903 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000904 }
905
njn6a3009b2005-03-20 00:20:06 +0000906 // Then check line size >= 16 -- any smaller and a single instruction could
907 // straddle three cache lines, which breaks a simulation assertion and is
908 // stupid anyway.
njn7cf0bd32002-06-08 13:36:03 +0000909 if (cache->line_size < MIN_LINE_SIZE) {
910 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000911 "error: %s line size of %dB too small; aborting.",
912 name, cache->line_size);
913 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000914 }
915
916 /* Then check cache size > line size (causes seg faults if not). */
917 if (cache->size <= cache->line_size) {
918 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000919 "error: %s cache size of %dB <= line size of %dB; aborting.",
920 name, cache->size, cache->line_size);
921 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000922 }
923
924 /* Then check assoc <= (size / line size) (seg faults otherwise). */
925 if (cache->assoc > (cache->size / cache->line_size)) {
926 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000927 "warning: %s associativity > (size / line size); aborting.", name);
928 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000929 }
930}
931
sewardj07133bf2002-06-13 10:25:56 +0000932static
nethercoteb35a8b92004-09-11 16:45:27 +0000933void configure_caches(cache_t* I1c, cache_t* D1c, cache_t* L2c)
njn7cf0bd32002-06-08 13:36:03 +0000934{
nethercote9313ac42004-07-06 21:54:20 +0000935#define DEFINED(L) (-1 != L.size || -1 != L.assoc || -1 != L.line_size)
936
nethercoteb35a8b92004-09-11 16:45:27 +0000937 Int n_clos = 0;
nethercote9313ac42004-07-06 21:54:20 +0000938
nethercoteb35a8b92004-09-11 16:45:27 +0000939 // Count how many were defined on the command line.
940 if (DEFINED(clo_I1_cache)) { n_clos++; }
941 if (DEFINED(clo_D1_cache)) { n_clos++; }
942 if (DEFINED(clo_L2_cache)) { n_clos++; }
njn7cf0bd32002-06-08 13:36:03 +0000943
njna1d1a642004-11-26 18:36:02 +0000944 // Set the cache config (using auto-detection, if supported by the
945 // architecture)
njnaf839f52005-06-23 03:27:57 +0000946 VG_(configure_caches)( I1c, D1c, L2c, (3 == n_clos) );
sewardjb1a77a42002-07-13 13:31:20 +0000947
nethercote9313ac42004-07-06 21:54:20 +0000948 // Then replace with any defined on the command line.
nethercoteb35a8b92004-09-11 16:45:27 +0000949 if (DEFINED(clo_I1_cache)) { *I1c = clo_I1_cache; }
950 if (DEFINED(clo_D1_cache)) { *D1c = clo_D1_cache; }
951 if (DEFINED(clo_L2_cache)) { *L2c = clo_L2_cache; }
njn7cf0bd32002-06-08 13:36:03 +0000952
nethercote9313ac42004-07-06 21:54:20 +0000953 // Then check values and fix if not acceptable.
njna1d1a642004-11-26 18:36:02 +0000954 check_cache(I1c, "I1");
955 check_cache(D1c, "D1");
956 check_cache(L2c, "L2");
njn7cf0bd32002-06-08 13:36:03 +0000957
958 if (VG_(clo_verbosity) > 1) {
959 VG_(message)(Vg_UserMsg, "Cache configuration used:");
960 VG_(message)(Vg_UserMsg, " I1: %dB, %d-way, %dB lines",
961 I1c->size, I1c->assoc, I1c->line_size);
962 VG_(message)(Vg_UserMsg, " D1: %dB, %d-way, %dB lines",
963 D1c->size, D1c->assoc, D1c->line_size);
964 VG_(message)(Vg_UserMsg, " L2: %dB, %d-way, %dB lines",
965 L2c->size, L2c->assoc, L2c->line_size);
966 }
nethercote9313ac42004-07-06 21:54:20 +0000967#undef CMD_LINE_DEFINED
njn7cf0bd32002-06-08 13:36:03 +0000968}
969
njn4f9c9342002-04-29 16:03:24 +0000970/*------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +0000971/*--- cg_fini() and related function ---*/
njn4f9c9342002-04-29 16:03:24 +0000972/*------------------------------------------------------------*/
973
nethercote9313ac42004-07-06 21:54:20 +0000974// Total reads/writes/misses. Calculated during CC traversal at the end.
975// All auto-zeroed.
976static CC Ir_total;
977static CC Dr_total;
978static CC Dw_total;
979
980static Char* cachegrind_out_file;
981
nethercote9313ac42004-07-06 21:54:20 +0000982static void fprint_CC_table_and_calc_totals(void)
983{
njnd3bef4f2005-10-15 17:46:18 +0000984 Int i, fd;
sewardj92645592005-07-23 09:18:34 +0000985 SysRes sres;
njnd3bef4f2005-10-15 17:46:18 +0000986 Char buf[512], *currFile = NULL, *currFn = NULL;
987 LineCC* lineCC;
njn4f9c9342002-04-29 16:03:24 +0000988
sewardj92645592005-07-23 09:18:34 +0000989 sres = VG_(open)(cachegrind_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
990 VKI_S_IRUSR|VKI_S_IWUSR);
991 if (sres.isError) {
nethercote9313ac42004-07-06 21:54:20 +0000992 // If the file can't be opened for whatever reason (conflict
993 // between multiple cachegrinded processes?), give up now.
njnee0e6a32005-04-24 00:21:01 +0000994 VG_(message)(Vg_UserMsg,
njn02bc4b82005-05-15 17:28:26 +0000995 "error: can't open cache simulation output file '%s'",
njnee0e6a32005-04-24 00:21:01 +0000996 cachegrind_out_file );
997 VG_(message)(Vg_UserMsg,
998 " ... so simulation results will be missing.");
sewardj0744b6c2002-12-11 00:45:42 +0000999 return;
sewardj92645592005-07-23 09:18:34 +00001000 } else {
1001 fd = sres.val;
sewardj0744b6c2002-12-11 00:45:42 +00001002 }
njn4f9c9342002-04-29 16:03:24 +00001003
nethercote9313ac42004-07-06 21:54:20 +00001004 // "desc:" lines (giving I1/D1/L2 cache configuration). The spaces after
1005 // the 2nd colon makes cg_annotate's output look nicer.
1006 VG_(sprintf)(buf, "desc: I1 cache: %s\n"
1007 "desc: D1 cache: %s\n"
1008 "desc: L2 cache: %s\n",
1009 I1.desc_line, D1.desc_line, L2.desc_line);
njn7cf0bd32002-06-08 13:36:03 +00001010 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njn4f9c9342002-04-29 16:03:24 +00001011
nethercote9313ac42004-07-06 21:54:20 +00001012 // "cmd:" line
njn4f9c9342002-04-29 16:03:24 +00001013 VG_(strcpy)(buf, "cmd:");
1014 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
sewardj45f4e7c2005-09-27 19:20:21 +00001015 if (VG_(args_the_exename)) {
1016 VG_(write)(fd, " ", 1);
1017 VG_(write)(fd, VG_(args_the_exename),
1018 VG_(strlen)( VG_(args_the_exename) ));
1019 }
1020 for (i = 0; i < VG_(args_for_client).used; i++) {
1021 if (VG_(args_for_client).strs[i]) {
1022 VG_(write)(fd, " ", 1);
1023 VG_(write)(fd, VG_(args_for_client).strs[i],
1024 VG_(strlen)(VG_(args_for_client).strs[i]));
1025 }
njn4f9c9342002-04-29 16:03:24 +00001026 }
nethercote9313ac42004-07-06 21:54:20 +00001027 // "events:" line
njn4f9c9342002-04-29 16:03:24 +00001028 VG_(sprintf)(buf, "\nevents: Ir I1mr I2mr Dr D1mr D2mr Dw D1mw D2mw\n");
1029 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1030
njnd3bef4f2005-10-15 17:46:18 +00001031 // Traverse every lineCC
1032 VG_(OSet_ResetIter)(CC_table);
1033 while ( (lineCC = VG_(OSet_Next)(CC_table)) ) {
njn4311fe62005-12-08 23:18:50 +00001034 Bool just_hit_a_new_file = False;
njnd3bef4f2005-10-15 17:46:18 +00001035 // If we've hit a new file, print a "fl=" line. Note that because
1036 // each string is stored exactly once in the string table, we can use
1037 // pointer comparison rather than strcmp() to test for equality, which
1038 // is good because most of the time the comparisons are equal and so
njn4311fe62005-12-08 23:18:50 +00001039 // the whole strings would have to be checked.
njnd3bef4f2005-10-15 17:46:18 +00001040 if ( lineCC->loc.file != currFile ) {
1041 currFile = lineCC->loc.file;
1042 VG_(sprintf)(buf, "fl=%s\n", currFile);
njn4f9c9342002-04-29 16:03:24 +00001043 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njnd3bef4f2005-10-15 17:46:18 +00001044 distinct_files++;
njn4311fe62005-12-08 23:18:50 +00001045 just_hit_a_new_file = True;
njn4f9c9342002-04-29 16:03:24 +00001046 }
njn4311fe62005-12-08 23:18:50 +00001047 // If we've hit a new function, print a "fn=" line. We know to do
1048 // this when the function name changes, and also every time we hit a
1049 // new file (in which case the new function name might be the same as
1050 // in the old file, hence the just_hit_a_new_file test).
1051 if ( just_hit_a_new_file || lineCC->loc.fn != currFn ) {
njnd3bef4f2005-10-15 17:46:18 +00001052 currFn = lineCC->loc.fn;
1053 VG_(sprintf)(buf, "fn=%s\n", currFn);
1054 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1055 distinct_fns++;
njn4311fe62005-12-08 23:18:50 +00001056 just_hit_a_new_file = False;
njnd3bef4f2005-10-15 17:46:18 +00001057 }
1058
1059 // Print the LineCC
1060 VG_(sprintf)(buf, "%u %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
1061 lineCC->loc.line,
1062 lineCC->Ir.a, lineCC->Ir.m1, lineCC->Ir.m2,
1063 lineCC->Dr.a, lineCC->Dr.m1, lineCC->Dr.m2,
1064 lineCC->Dw.a, lineCC->Dw.m1, lineCC->Dw.m2);
1065 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1066
1067 // Update summary stats
1068 Ir_total.a += lineCC->Ir.a;
1069 Ir_total.m1 += lineCC->Ir.m1;
1070 Ir_total.m2 += lineCC->Ir.m2;
1071 Dr_total.a += lineCC->Dr.a;
1072 Dr_total.m1 += lineCC->Dr.m1;
1073 Dr_total.m2 += lineCC->Dr.m2;
1074 Dw_total.a += lineCC->Dw.a;
1075 Dw_total.m1 += lineCC->Dw.m1;
1076 Dw_total.m2 += lineCC->Dw.m2;
1077
1078 distinct_lines++;
njn4f9c9342002-04-29 16:03:24 +00001079 }
1080
nethercote9313ac42004-07-06 21:54:20 +00001081 // Summary stats must come after rest of table, since we calculate them
1082 // during traversal. */
njn4f9c9342002-04-29 16:03:24 +00001083 VG_(sprintf)(buf, "summary: "
nethercote9313ac42004-07-06 21:54:20 +00001084 "%llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
njn4f9c9342002-04-29 16:03:24 +00001085 Ir_total.a, Ir_total.m1, Ir_total.m2,
1086 Dr_total.a, Dr_total.m1, Dr_total.m2,
1087 Dw_total.a, Dw_total.m1, Dw_total.m2);
1088 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1089 VG_(close)(fd);
1090}
1091
njn607adfc2003-09-30 14:15:44 +00001092static UInt ULong_width(ULong n)
njn4f9c9342002-04-29 16:03:24 +00001093{
njn607adfc2003-09-30 14:15:44 +00001094 UInt w = 0;
1095 while (n > 0) {
1096 n = n / 10;
1097 w++;
njn4f9c9342002-04-29 16:03:24 +00001098 }
sewardj46c59b12005-11-01 02:20:19 +00001099 if (w == 0) w = 1;
njn607adfc2003-09-30 14:15:44 +00001100 return w + (w-1)/3; // add space for commas
njn4f9c9342002-04-29 16:03:24 +00001101}
1102
njn51d827b2005-05-09 01:02:08 +00001103static void cg_fini(Int exitcode)
njn4f9c9342002-04-29 16:03:24 +00001104{
njn0103de52005-10-10 16:49:01 +00001105 static Char buf1[128], buf2[128], buf3[128], fmt [128];
njn607adfc2003-09-30 14:15:44 +00001106
njn4f9c9342002-04-29 16:03:24 +00001107 CC D_total;
njn1d021fa2002-05-02 13:56:34 +00001108 ULong L2_total_m, L2_total_mr, L2_total_mw,
1109 L2_total, L2_total_r, L2_total_w;
njn4f9c9342002-04-29 16:03:24 +00001110 Int l1, l2, l3;
1111 Int p;
1112
nethercote9313ac42004-07-06 21:54:20 +00001113 fprint_CC_table_and_calc_totals();
njn4f9c9342002-04-29 16:03:24 +00001114
njn7cf0bd32002-06-08 13:36:03 +00001115 if (VG_(clo_verbosity) == 0)
1116 return;
1117
njn4f9c9342002-04-29 16:03:24 +00001118 /* I cache results. Use the I_refs value to determine the first column
1119 * width. */
njn607adfc2003-09-30 14:15:44 +00001120 l1 = ULong_width(Ir_total.a);
1121 l2 = ULong_width(Dr_total.a);
1122 l3 = ULong_width(Dw_total.a);
njn4f9c9342002-04-29 16:03:24 +00001123
njn607adfc2003-09-30 14:15:44 +00001124 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001125 VG_(sprintf)(fmt, "%%s %%,%dllu", l1);
njnd3bef4f2005-10-15 17:46:18 +00001126
njn607adfc2003-09-30 14:15:44 +00001127 VG_(message)(Vg_UserMsg, fmt, "I refs: ", Ir_total.a);
1128 VG_(message)(Vg_UserMsg, fmt, "I1 misses: ", Ir_total.m1);
1129 VG_(message)(Vg_UserMsg, fmt, "L2i misses: ", Ir_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001130
1131 p = 100;
1132
njn25e49d8e72002-09-23 09:36:25 +00001133 if (0 == Ir_total.a) Ir_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001134 VG_(percentify)(Ir_total.m1, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001135 VG_(message)(Vg_UserMsg, "I1 miss rate: %s", buf1);
njnd3bef4f2005-10-15 17:46:18 +00001136
njn856c54e2005-06-26 18:43:40 +00001137 VG_(percentify)(Ir_total.m2, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001138 VG_(message)(Vg_UserMsg, "L2i miss rate: %s", buf1);
1139 VG_(message)(Vg_UserMsg, "");
1140
1141 /* D cache results. Use the D_refs.rd and D_refs.wr values to determine the
1142 * width of columns 2 & 3. */
1143 D_total.a = Dr_total.a + Dw_total.a;
1144 D_total.m1 = Dr_total.m1 + Dw_total.m1;
1145 D_total.m2 = Dr_total.m2 + Dw_total.m2;
njnd3bef4f2005-10-15 17:46:18 +00001146
njn607adfc2003-09-30 14:15:44 +00001147 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001148 VG_(sprintf)(fmt, "%%s %%,%dllu (%%,%dllu rd + %%,%dllu wr)", l1, l2, l3);
njn4f9c9342002-04-29 16:03:24 +00001149
njn607adfc2003-09-30 14:15:44 +00001150 VG_(message)(Vg_UserMsg, fmt, "D refs: ",
1151 D_total.a, Dr_total.a, Dw_total.a);
1152 VG_(message)(Vg_UserMsg, fmt, "D1 misses: ",
1153 D_total.m1, Dr_total.m1, Dw_total.m1);
1154 VG_(message)(Vg_UserMsg, fmt, "L2d misses: ",
1155 D_total.m2, Dr_total.m2, Dw_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001156
1157 p = 10;
njnd3bef4f2005-10-15 17:46:18 +00001158
njn25e49d8e72002-09-23 09:36:25 +00001159 if (0 == D_total.a) D_total.a = 1;
1160 if (0 == Dr_total.a) Dr_total.a = 1;
1161 if (0 == Dw_total.a) Dw_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001162 VG_(percentify)( D_total.m1, D_total.a, 1, l1+1, buf1);
1163 VG_(percentify)(Dr_total.m1, Dr_total.a, 1, l2+1, buf2);
1164 VG_(percentify)(Dw_total.m1, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001165 VG_(message)(Vg_UserMsg, "D1 miss rate: %s (%s + %s )", buf1, buf2,buf3);
1166
njn856c54e2005-06-26 18:43:40 +00001167 VG_(percentify)( D_total.m2, D_total.a, 1, l1+1, buf1);
1168 VG_(percentify)(Dr_total.m2, Dr_total.a, 1, l2+1, buf2);
1169 VG_(percentify)(Dw_total.m2, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001170 VG_(message)(Vg_UserMsg, "L2d miss rate: %s (%s + %s )", buf1, buf2,buf3);
1171 VG_(message)(Vg_UserMsg, "");
1172
1173 /* L2 overall results */
njn1d021fa2002-05-02 13:56:34 +00001174
1175 L2_total = Dr_total.m1 + Dw_total.m1 + Ir_total.m1;
1176 L2_total_r = Dr_total.m1 + Ir_total.m1;
1177 L2_total_w = Dw_total.m1;
njn607adfc2003-09-30 14:15:44 +00001178 VG_(message)(Vg_UserMsg, fmt, "L2 refs: ",
1179 L2_total, L2_total_r, L2_total_w);
njn1d021fa2002-05-02 13:56:34 +00001180
njn4f9c9342002-04-29 16:03:24 +00001181 L2_total_m = Dr_total.m2 + Dw_total.m2 + Ir_total.m2;
1182 L2_total_mr = Dr_total.m2 + Ir_total.m2;
1183 L2_total_mw = Dw_total.m2;
njn607adfc2003-09-30 14:15:44 +00001184 VG_(message)(Vg_UserMsg, fmt, "L2 misses: ",
1185 L2_total_m, L2_total_mr, L2_total_mw);
njn4f9c9342002-04-29 16:03:24 +00001186
njn856c54e2005-06-26 18:43:40 +00001187 VG_(percentify)(L2_total_m, (Ir_total.a + D_total.a), 1, l1+1, buf1);
1188 VG_(percentify)(L2_total_mr, (Ir_total.a + Dr_total.a), 1, l2+1, buf2);
1189 VG_(percentify)(L2_total_mw, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001190 VG_(message)(Vg_UserMsg, "L2 miss rate: %s (%s + %s )", buf1, buf2,buf3);
njnd3bef4f2005-10-15 17:46:18 +00001191
njn4f9c9342002-04-29 16:03:24 +00001192
nethercote9313ac42004-07-06 21:54:20 +00001193 // Various stats
njn4f9c9342002-04-29 16:03:24 +00001194 if (VG_(clo_verbosity) > 1) {
njnd3bef4f2005-10-15 17:46:18 +00001195 Int debug_lookups = full_debugs + fn_debugs +
1196 file_line_debugs + no_debugs;
1197
njn4f9c9342002-04-29 16:03:24 +00001198 VG_(message)(Vg_DebugMsg, "");
njnd3bef4f2005-10-15 17:46:18 +00001199 VG_(message)(Vg_DebugMsg, "cachegrind: distinct files: %d", distinct_files);
1200 VG_(message)(Vg_DebugMsg, "cachegrind: distinct fns: %d", distinct_fns);
1201 VG_(message)(Vg_DebugMsg, "cachegrind: distinct lines: %d", distinct_lines);
1202 VG_(message)(Vg_DebugMsg, "cachegrind: distinct instrs:%d", distinct_instrs);
1203 VG_(message)(Vg_DebugMsg, "cachegrind: debug lookups : %d", debug_lookups);
1204 VG_(message)(Vg_DebugMsg, "cachegrind: with full info:%3d%% (%d)",
1205 full_debugs * 100 / debug_lookups, full_debugs);
1206 VG_(message)(Vg_DebugMsg, "cachegrind: with file/line info:%3d%% (%d)",
1207 file_line_debugs * 100 / debug_lookups, file_line_debugs);
1208 VG_(message)(Vg_DebugMsg, "cachegrind: with fn name info:%3d%% (%d)",
1209 fn_debugs * 100 / debug_lookups, fn_debugs);
1210 VG_(message)(Vg_DebugMsg, "cachegrind: with zero info:%3d%% (%d)",
1211 no_debugs * 100 / debug_lookups, no_debugs);
njnd3bef4f2005-10-15 17:46:18 +00001212 VG_(message)(Vg_DebugMsg, "cachegrind: string table size: %u",
1213 VG_(OSet_Size)(stringTable));
1214 VG_(message)(Vg_DebugMsg, "cachegrind: CC table size: %u",
1215 VG_(OSet_Size)(CC_table));
1216 VG_(message)(Vg_DebugMsg, "cachegrind: InstrInfo table size: %u",
1217 VG_(OSet_Size)(instrInfoTable));
njn4f9c9342002-04-29 16:03:24 +00001218 }
njn4f9c9342002-04-29 16:03:24 +00001219}
1220
nethercote9313ac42004-07-06 21:54:20 +00001221/*--------------------------------------------------------------------*/
1222/*--- Discarding BB info ---*/
1223/*--------------------------------------------------------------------*/
sewardj18d75132002-05-16 11:06:21 +00001224
sewardja3a29a52005-10-12 16:16:03 +00001225// Called when a translation is removed from the translation cache for
1226// any reason at all: to free up space, because the guest code was
1227// unmapped or modified, or for any arbitrary reason.
sewardj4ba057c2005-10-18 12:04:18 +00001228static
1229void cg_discard_basic_block_info ( Addr64 orig_addr64, VexGuestExtents vge )
sewardj18d75132002-05-16 11:06:21 +00001230{
njnd3bef4f2005-10-15 17:46:18 +00001231 BB_info* bbInfo;
sewardj4ba057c2005-10-18 12:04:18 +00001232 Addr orig_addr = (Addr)orig_addr64;
njn4294fd42002-06-05 14:41:10 +00001233
sewardj5155dec2005-10-12 10:09:23 +00001234 tl_assert(vge.n_used > 0);
1235
1236 if (DEBUG_CG)
sewardj4ba057c2005-10-18 12:04:18 +00001237 VG_(printf)( "discard_basic_block_info: %p, %p, %llu\n",
1238 (void*)(Addr)orig_addr,
sewardj5155dec2005-10-12 10:09:23 +00001239 (void*)(Addr)vge.base[0], (ULong)vge.len[0]);
njn4294fd42002-06-05 14:41:10 +00001240
sewardj4ba057c2005-10-18 12:04:18 +00001241 // Get BB info, remove from table, free BB info. Simple! Note that we
1242 // use orig_addr, not the first instruction address in vge.
1243 bbInfo = VG_(OSet_Remove)(instrInfoTable, &orig_addr);
njn6a3009b2005-03-20 00:20:06 +00001244 tl_assert(NULL != bbInfo);
njnd3bef4f2005-10-15 17:46:18 +00001245 VG_(OSet_FreeNode)(instrInfoTable, bbInfo);
sewardj18d75132002-05-16 11:06:21 +00001246}
1247
1248/*--------------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001249/*--- Command line processing ---*/
1250/*--------------------------------------------------------------------*/
1251
njn0103de52005-10-10 16:49:01 +00001252static void parse_cache_opt ( cache_t* cache, Char* opt )
njn25e49d8e72002-09-23 09:36:25 +00001253{
njn0103de52005-10-10 16:49:01 +00001254 Int i = 0, i2, i3;
njn25e49d8e72002-09-23 09:36:25 +00001255
nethercote9313ac42004-07-06 21:54:20 +00001256 // Option argument looks like "65536,2,64".
1257 // Find commas, replace with NULs to make three independent
1258 // strings, then extract numbers, put NULs back. Yuck.
njn25e49d8e72002-09-23 09:36:25 +00001259 while (VG_(isdigit)(opt[i])) i++;
1260 if (',' == opt[i]) {
1261 opt[i++] = '\0';
1262 i2 = i;
1263 } else goto bad;
1264 while (VG_(isdigit)(opt[i])) i++;
1265 if (',' == opt[i]) {
1266 opt[i++] = '\0';
1267 i3 = i;
1268 } else goto bad;
1269 while (VG_(isdigit)(opt[i])) i++;
1270 if ('\0' != opt[i]) goto bad;
1271
nethercote9313ac42004-07-06 21:54:20 +00001272 cache->size = (Int)VG_(atoll)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001273 cache->assoc = (Int)VG_(atoll)(opt + i2);
1274 cache->line_size = (Int)VG_(atoll)(opt + i3);
1275
nethercote9313ac42004-07-06 21:54:20 +00001276 opt[i2-1] = ',';
1277 opt[i3-1] = ',';
njn25e49d8e72002-09-23 09:36:25 +00001278 return;
1279
1280 bad:
nethercote9313ac42004-07-06 21:54:20 +00001281 VG_(bad_option)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001282}
1283
njn51d827b2005-05-09 01:02:08 +00001284static Bool cg_process_cmd_line_option(Char* arg)
njn25e49d8e72002-09-23 09:36:25 +00001285{
nethercote9313ac42004-07-06 21:54:20 +00001286 // 5 is length of "--I1="
njn39c86652003-05-21 10:13:39 +00001287 if (VG_CLO_STREQN(5, arg, "--I1="))
nethercote9313ac42004-07-06 21:54:20 +00001288 parse_cache_opt(&clo_I1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001289 else if (VG_CLO_STREQN(5, arg, "--D1="))
nethercote9313ac42004-07-06 21:54:20 +00001290 parse_cache_opt(&clo_D1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001291 else if (VG_CLO_STREQN(5, arg, "--L2="))
nethercote9313ac42004-07-06 21:54:20 +00001292 parse_cache_opt(&clo_L2_cache, &arg[5]);
njn25e49d8e72002-09-23 09:36:25 +00001293 else
1294 return False;
1295
1296 return True;
1297}
1298
njn51d827b2005-05-09 01:02:08 +00001299static void cg_print_usage(void)
njn25e49d8e72002-09-23 09:36:25 +00001300{
njn3e884182003-04-15 13:03:23 +00001301 VG_(printf)(
njn25e49d8e72002-09-23 09:36:25 +00001302" --I1=<size>,<assoc>,<line_size> set I1 cache manually\n"
1303" --D1=<size>,<assoc>,<line_size> set D1 cache manually\n"
njn3e884182003-04-15 13:03:23 +00001304" --L2=<size>,<assoc>,<line_size> set L2 cache manually\n"
1305 );
1306}
1307
njn51d827b2005-05-09 01:02:08 +00001308static void cg_print_debug_usage(void)
njn3e884182003-04-15 13:03:23 +00001309{
1310 VG_(printf)(
1311" (none)\n"
1312 );
njn25e49d8e72002-09-23 09:36:25 +00001313}
1314
1315/*--------------------------------------------------------------------*/
1316/*--- Setup ---*/
1317/*--------------------------------------------------------------------*/
1318
njn51d827b2005-05-09 01:02:08 +00001319static void cg_post_clo_init(void)
njn25e49d8e72002-09-23 09:36:25 +00001320{
1321 cache_t I1c, D1c, L2c;
njn25e49d8e72002-09-23 09:36:25 +00001322
nethercoteb35a8b92004-09-11 16:45:27 +00001323 configure_caches(&I1c, &D1c, &L2c);
njn25e49d8e72002-09-23 09:36:25 +00001324
1325 cachesim_I1_initcache(I1c);
1326 cachesim_D1_initcache(D1c);
1327 cachesim_L2_initcache(L2c);
njn25e49d8e72002-09-23 09:36:25 +00001328}
1329
njn57ca7ab2005-06-21 23:44:58 +00001330static Char base_dir[VKI_PATH_MAX];
1331
njn51d827b2005-05-09 01:02:08 +00001332static void cg_pre_clo_init(void)
1333{
njn51d827b2005-05-09 01:02:08 +00001334 VG_(details_name) ("Cachegrind");
1335 VG_(details_version) (NULL);
1336 VG_(details_description) ("an I1/D1/L2 cache profiler");
1337 VG_(details_copyright_author)(
1338 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote et al.");
1339 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj5155dec2005-10-12 10:09:23 +00001340 VG_(details_avg_translation_sizeB) ( 245 );
njn51d827b2005-05-09 01:02:08 +00001341
1342 VG_(basic_tool_funcs) (cg_post_clo_init,
1343 cg_instrument,
1344 cg_fini);
1345
1346 VG_(needs_basic_block_discards)(cg_discard_basic_block_info);
1347 VG_(needs_command_line_options)(cg_process_cmd_line_option,
1348 cg_print_usage,
1349 cg_print_debug_usage);
1350
1351 /* Get working directory */
njn57ca7ab2005-06-21 23:44:58 +00001352 tl_assert( VG_(getcwd)(base_dir, VKI_PATH_MAX) );
njn51d827b2005-05-09 01:02:08 +00001353
1354 /* Block is big enough for dir name + cachegrind.out.<pid> */
1355 cachegrind_out_file = VG_(malloc)((VG_(strlen)(base_dir) + 32)*sizeof(Char));
1356 VG_(sprintf)(cachegrind_out_file, "%s/cachegrind.out.%d",
1357 base_dir, VG_(getpid)());
njn51d827b2005-05-09 01:02:08 +00001358
njnd3bef4f2005-10-15 17:46:18 +00001359 CC_table = VG_(OSet_Create)(offsetof(LineCC, loc),
1360 cmp_CodeLoc_LineCC,
1361 VG_(malloc), VG_(free));
sewardj4ba057c2005-10-18 12:04:18 +00001362 instrInfoTable = VG_(OSet_Create)(/*keyOff*/0,
njnd3bef4f2005-10-15 17:46:18 +00001363 NULL,
1364 VG_(malloc), VG_(free));
1365 stringTable = VG_(OSet_Create)(/*keyOff*/0,
1366 stringCmp,
1367 VG_(malloc), VG_(free));
njn51d827b2005-05-09 01:02:08 +00001368}
1369
sewardj45f4e7c2005-09-27 19:20:21 +00001370VG_DETERMINE_INTERFACE_VERSION(cg_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00001371
njn25e49d8e72002-09-23 09:36:25 +00001372/*--------------------------------------------------------------------*/
njnf69f9452005-07-03 17:53:11 +00001373/*--- end ---*/
sewardj18d75132002-05-16 11:06:21 +00001374/*--------------------------------------------------------------------*/
njnd3bef4f2005-10-15 17:46:18 +00001375