blob: e1ccc41e6d9d0c75d43cbbbad34455573bcde5c0 [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
sewardje4b0bf02006-06-05 23:21:15 +000011 Copyright (C) 2002-2006 Nicholas Nethercote
njn2bc10122005-05-08 02:10:27 +000012 njn@valgrind.org
njn4f9c9342002-04-29 16:03:24 +000013
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
njn25e49d8e72002-09-23 09:36:25 +000029 The GNU General Public License is contained in the file COPYING.
njn4f9c9342002-04-29 16:03:24 +000030*/
31
njnc7561b92005-06-19 01:24:32 +000032#include "pub_tool_basics.h"
sewardj4cfea4f2006-10-14 19:26:10 +000033#include "pub_tool_vki.h"
njnea27e462005-05-31 02:38:09 +000034#include "pub_tool_debuginfo.h"
njn97405b22005-06-02 03:39:33 +000035#include "pub_tool_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000036#include "pub_tool_libcassert.h"
njneb8896b2005-06-04 20:03:55 +000037#include "pub_tool_libcfile.h"
njn36a20fa2005-06-03 03:08:39 +000038#include "pub_tool_libcprint.h"
njnf39e9a32005-06-12 02:43:17 +000039#include "pub_tool_libcproc.h"
njnf536bbb2005-06-13 04:21:38 +000040#include "pub_tool_machine.h"
njn717cde52005-05-10 02:47:21 +000041#include "pub_tool_mallocfree.h"
njn20242342005-05-16 23:31:24 +000042#include "pub_tool_options.h"
njnd3bef4f2005-10-15 17:46:18 +000043#include "pub_tool_oset.h"
njn43b9a8a2005-05-10 04:37:01 +000044#include "pub_tool_tooliface.h"
sewardj45f4e7c2005-09-27 19:20:21 +000045#include "pub_tool_clientstate.h"
sewardj5bb86822005-12-23 12:47:42 +000046#include "pub_tool_machine.h" // VG_(fnptr_to_fnentry)
njn25e49d8e72002-09-23 09:36:25 +000047
nethercoteb35a8b92004-09-11 16:45:27 +000048#include "cg_arch.h"
nethercote27fc1da2004-01-04 16:56:57 +000049#include "cg_sim.c"
njn4f9c9342002-04-29 16:03:24 +000050
njn25e49d8e72002-09-23 09:36:25 +000051/*------------------------------------------------------------*/
52/*--- Constants ---*/
53/*------------------------------------------------------------*/
njn4f9c9342002-04-29 16:03:24 +000054
sewardj5155dec2005-10-12 10:09:23 +000055/* Set to 1 for very verbose debugging */
56#define DEBUG_CG 0
57
nethercote9313ac42004-07-06 21:54:20 +000058#define MIN_LINE_SIZE 16
njnd3bef4f2005-10-15 17:46:18 +000059#define FILE_LEN VKI_PATH_MAX
nethercote9313ac42004-07-06 21:54:20 +000060#define FN_LEN 256
njn7cf0bd32002-06-08 13:36:03 +000061
62/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +000063/*--- Types and Data Structures ---*/
njn4f9c9342002-04-29 16:03:24 +000064/*------------------------------------------------------------*/
65
66typedef struct _CC CC;
67struct _CC {
68 ULong a;
69 ULong m1;
70 ULong m2;
71};
72
nethercote9313ac42004-07-06 21:54:20 +000073//------------------------------------------------------------
74// Primary data structure #1: CC table
75// - Holds the per-source-line hit/miss stats, grouped by file/function/line.
njnd3bef4f2005-10-15 17:46:18 +000076// - an ordered set of CCs. CC indexing done by file/function/line (as
77// determined from the instrAddr).
nethercote9313ac42004-07-06 21:54:20 +000078// - Traversed for dumping stats at end in file/func/line hierarchy.
njn4f9c9342002-04-29 16:03:24 +000079
njnd3bef4f2005-10-15 17:46:18 +000080typedef struct {
81 Char* file;
82 Char* fn;
83 Int line;
84}
85CodeLoc;
njn4f9c9342002-04-29 16:03:24 +000086
njnd3bef4f2005-10-15 17:46:18 +000087typedef struct _LineCC LineCC;
88struct _LineCC {
89 CodeLoc loc;
90 CC Ir;
91 CC Dr;
92 CC Dw;
njn4f9c9342002-04-29 16:03:24 +000093};
94
njnd3bef4f2005-10-15 17:46:18 +000095// First compare file, then fn, then line.
njnafa12262005-12-24 03:10:56 +000096static Word cmp_CodeLoc_LineCC(void *vloc, void *vcc)
njnd3bef4f2005-10-15 17:46:18 +000097{
njnafa12262005-12-24 03:10:56 +000098 Word res;
njnd3bef4f2005-10-15 17:46:18 +000099 CodeLoc* a = (CodeLoc*)vloc;
100 CodeLoc* b = &(((LineCC*)vcc)->loc);
njn4f9c9342002-04-29 16:03:24 +0000101
njnd3bef4f2005-10-15 17:46:18 +0000102 res = VG_(strcmp)(a->file, b->file);
103 if (0 != res)
104 return res;
njn4f9c9342002-04-29 16:03:24 +0000105
njnd3bef4f2005-10-15 17:46:18 +0000106 res = VG_(strcmp)(a->fn, b->fn);
107 if (0 != res)
108 return res;
109
110 return a->line - b->line;
111}
112
113static OSet* CC_table;
njn4f9c9342002-04-29 16:03:24 +0000114
nethercote9313ac42004-07-06 21:54:20 +0000115//------------------------------------------------------------
njnd3bef4f2005-10-15 17:46:18 +0000116// Primary data structure #2: InstrInfo table
nethercote9313ac42004-07-06 21:54:20 +0000117// - Holds the cached info about each instr that is used for simulation.
njnd3bef4f2005-10-15 17:46:18 +0000118// - table(BB_start_addr, list(InstrInfo))
119// - For each BB, each InstrInfo in the list holds info about the
120// instruction (instrLen, instrAddr, etc), plus a pointer to its line
nethercote9313ac42004-07-06 21:54:20 +0000121// CC. This node is what's passed to the simulation function.
122// - When BBs are discarded the relevant list(instr_details) is freed.
123
njnd3bef4f2005-10-15 17:46:18 +0000124typedef struct _InstrInfo InstrInfo;
125struct _InstrInfo {
nethercoteca1f2dc2004-07-21 08:49:02 +0000126 Addr instr_addr;
njn6a3009b2005-03-20 00:20:06 +0000127 UChar instr_len;
njnd3bef4f2005-10-15 17:46:18 +0000128 LineCC* parent; // parent line-CC
nethercote9313ac42004-07-06 21:54:20 +0000129};
130
131typedef struct _BB_info BB_info;
132struct _BB_info {
sewardj4ba057c2005-10-18 12:04:18 +0000133 Addr BB_addr; // key; MUST BE FIRST
njnd3bef4f2005-10-15 17:46:18 +0000134 Int n_instrs;
135 InstrInfo instrs[0];
nethercote9313ac42004-07-06 21:54:20 +0000136};
137
njnd3bef4f2005-10-15 17:46:18 +0000138static OSet* instrInfoTable;
139
140//------------------------------------------------------------
141// Secondary data structure: string table
142// - holds strings, avoiding dups
143// - used for filenames and function names, each of which will be
144// pointed to by one or more CCs.
145// - it also allows equality checks just by pointer comparison, which
146// is good when printing the output file at the end.
147
148static OSet* stringTable;
nethercote9313ac42004-07-06 21:54:20 +0000149
150//------------------------------------------------------------
151// Stats
sewardj4f29ddf2002-05-03 22:29:04 +0000152static Int distinct_files = 0;
153static Int distinct_fns = 0;
nethercote9313ac42004-07-06 21:54:20 +0000154static Int distinct_lines = 0;
sewardj4f29ddf2002-05-03 22:29:04 +0000155static Int distinct_instrs = 0;
nethercote9313ac42004-07-06 21:54:20 +0000156
njnd3bef4f2005-10-15 17:46:18 +0000157static Int full_debugs = 0;
158static Int file_line_debugs = 0;
159static Int fn_debugs = 0;
160static Int no_debugs = 0;
njn4f9c9342002-04-29 16:03:24 +0000161
nethercote9313ac42004-07-06 21:54:20 +0000162/*------------------------------------------------------------*/
njnd3bef4f2005-10-15 17:46:18 +0000163/*--- String table operations ---*/
164/*------------------------------------------------------------*/
165
njnafa12262005-12-24 03:10:56 +0000166static Word stringCmp( void* key, void* elem )
njnd3bef4f2005-10-15 17:46:18 +0000167{
168 return VG_(strcmp)(*(Char**)key, *(Char**)elem);
169}
170
171// Get a permanent string; either pull it out of the string table if it's
172// been encountered before, or dup it and put it into the string table.
173static Char* get_perm_string(Char* s)
174{
175 Char** s_ptr = VG_(OSet_Lookup)(stringTable, &s);
176 if (s_ptr) {
177 return *s_ptr;
178 } else {
179 Char** s_node = VG_(OSet_AllocNode)(stringTable, sizeof(Char*));
180 *s_node = VG_(strdup)(s);
181 VG_(OSet_Insert)(stringTable, s_node);
182 return *s_node;
183 }
184}
185
186/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +0000187/*--- CC table operations ---*/
188/*------------------------------------------------------------*/
njn4294fd42002-06-05 14:41:10 +0000189
nethercote9313ac42004-07-06 21:54:20 +0000190static void get_debug_info(Addr instr_addr, Char file[FILE_LEN],
191 Char fn[FN_LEN], Int* line)
njn4f9c9342002-04-29 16:03:24 +0000192{
sewardj7cee6f92005-06-13 17:39:06 +0000193 Bool found_file_line = VG_(get_filename_linenum)(
194 instr_addr,
195 file, FILE_LEN,
196 NULL, 0, NULL,
197 line
198 );
nethercote9313ac42004-07-06 21:54:20 +0000199 Bool found_fn = VG_(get_fnname)(instr_addr, fn, FN_LEN);
njn4f9c9342002-04-29 16:03:24 +0000200
nethercote9313ac42004-07-06 21:54:20 +0000201 if (!found_file_line) {
202 VG_(strcpy)(file, "???");
203 *line = 0;
204 }
205 if (!found_fn) {
206 VG_(strcpy)(fn, "???");
207 }
208 if (found_file_line) {
njnd3bef4f2005-10-15 17:46:18 +0000209 if (found_fn) full_debugs++;
210 else file_line_debugs++;
nethercote9313ac42004-07-06 21:54:20 +0000211 } else {
njnd3bef4f2005-10-15 17:46:18 +0000212 if (found_fn) fn_debugs++;
213 else no_debugs++;
njn4f9c9342002-04-29 16:03:24 +0000214 }
215}
216
nethercote9313ac42004-07-06 21:54:20 +0000217// Do a three step traversal: by file, then fn, then line.
njnd3bef4f2005-10-15 17:46:18 +0000218// Returns a pointer to the line CC, creates a new one if necessary.
219static LineCC* get_lineCC(Addr origAddr)
nethercote9313ac42004-07-06 21:54:20 +0000220{
nethercote9313ac42004-07-06 21:54:20 +0000221 Char file[FILE_LEN], fn[FN_LEN];
222 Int line;
njnd3bef4f2005-10-15 17:46:18 +0000223 CodeLoc loc;
224 LineCC* lineCC;
nethercote9313ac42004-07-06 21:54:20 +0000225
njn6a3009b2005-03-20 00:20:06 +0000226 get_debug_info(origAddr, file, fn, &line);
nethercote9313ac42004-07-06 21:54:20 +0000227
njnd3bef4f2005-10-15 17:46:18 +0000228 loc.file = file;
229 loc.fn = fn;
230 loc.line = line;
njn4f9c9342002-04-29 16:03:24 +0000231
njnd3bef4f2005-10-15 17:46:18 +0000232 lineCC = VG_(OSet_Lookup)(CC_table, &loc);
233 if (!lineCC) {
234 // Allocate and zero a new node.
235 lineCC = VG_(OSet_AllocNode)(CC_table, sizeof(LineCC));
236 lineCC->loc.file = get_perm_string(loc.file);
237 lineCC->loc.fn = get_perm_string(loc.fn);
238 lineCC->loc.line = loc.line;
239 VG_(OSet_Insert)(CC_table, lineCC);
njn4f9c9342002-04-29 16:03:24 +0000240 }
nethercote9313ac42004-07-06 21:54:20 +0000241
njnd3bef4f2005-10-15 17:46:18 +0000242 return lineCC;
njn4f9c9342002-04-29 16:03:24 +0000243}
244
245/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +0000246/*--- Cache simulation functions ---*/
njn4f9c9342002-04-29 16:03:24 +0000247/*------------------------------------------------------------*/
248
njnaf839f52005-06-23 03:27:57 +0000249static VG_REGPARM(1)
njnd3bef4f2005-10-15 17:46:18 +0000250void log_1I_0D_cache_access(InstrInfo* n)
njn25e49d8e72002-09-23 09:36:25 +0000251{
sewardj5155dec2005-10-12 10:09:23 +0000252 //VG_(printf)("1I_0D : CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n",
253 // n, n->instr_addr, n->instr_len);
njn6a3009b2005-03-20 00:20:06 +0000254 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000255 &n->parent->Ir.m1, &n->parent->Ir.m2);
256 n->parent->Ir.a++;
njn25e49d8e72002-09-23 09:36:25 +0000257}
258
njnaf839f52005-06-23 03:27:57 +0000259static VG_REGPARM(2)
njnd3bef4f2005-10-15 17:46:18 +0000260void log_2I_0D_cache_access(InstrInfo* n, InstrInfo* n2)
njn25e49d8e72002-09-23 09:36:25 +0000261{
sewardj5155dec2005-10-12 10:09:23 +0000262 //VG_(printf)("2I_0D : CC1addr=0x%010lx, i1addr=0x%010lx, i1size=%lu\n"
263 // " CC2addr=0x%010lx, i2addr=0x%010lx, i2size=%lu\n",
264 // n, n->instr_addr, n->instr_len,
265 // n2, n2->instr_addr, n2->instr_len);
sewardj5155dec2005-10-12 10:09:23 +0000266 cachesim_I1_doref(n->instr_addr, n->instr_len,
267 &n->parent->Ir.m1, &n->parent->Ir.m2);
268 n->parent->Ir.a++;
269 cachesim_I1_doref(n2->instr_addr, n2->instr_len,
270 &n2->parent->Ir.m1, &n2->parent->Ir.m2);
271 n2->parent->Ir.a++;
sewardj5155dec2005-10-12 10:09:23 +0000272}
273
274static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000275void log_3I_0D_cache_access(InstrInfo* n, InstrInfo* n2, InstrInfo* n3)
sewardj5155dec2005-10-12 10:09:23 +0000276{
277 //VG_(printf)("3I_0D : CC1addr=0x%010lx, i1addr=0x%010lx, i1size=%lu\n"
278 // " CC2addr=0x%010lx, i2addr=0x%010lx, i2size=%lu\n"
279 // " CC3addr=0x%010lx, i3addr=0x%010lx, i3size=%lu\n",
280 // n, n->instr_addr, n->instr_len,
281 // n2, n2->instr_addr, n2->instr_len,
282 // n3, n3->instr_addr, n3->instr_len);
sewardj5155dec2005-10-12 10:09:23 +0000283 cachesim_I1_doref(n->instr_addr, n->instr_len,
284 &n->parent->Ir.m1, &n->parent->Ir.m2);
285 n->parent->Ir.a++;
286 cachesim_I1_doref(n2->instr_addr, n2->instr_len,
287 &n2->parent->Ir.m1, &n2->parent->Ir.m2);
288 n2->parent->Ir.a++;
289 cachesim_I1_doref(n3->instr_addr, n3->instr_len,
290 &n3->parent->Ir.m1, &n3->parent->Ir.m2);
291 n3->parent->Ir.a++;
sewardj5155dec2005-10-12 10:09:23 +0000292}
293
294static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000295void log_1I_1Dr_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
sewardj5155dec2005-10-12 10:09:23 +0000296{
297 //VG_(printf)("1I_1Dr: CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n"
298 // " daddr=0x%010lx, dsize=%lu\n",
299 // n, n->instr_addr, n->instr_len, data_addr, data_size);
njn6a3009b2005-03-20 00:20:06 +0000300 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000301 &n->parent->Ir.m1, &n->parent->Ir.m2);
302 n->parent->Ir.a++;
njn25e49d8e72002-09-23 09:36:25 +0000303
sewardj5155dec2005-10-12 10:09:23 +0000304 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000305 &n->parent->Dr.m1, &n->parent->Dr.m2);
306 n->parent->Dr.a++;
njn25e49d8e72002-09-23 09:36:25 +0000307}
308
sewardj5155dec2005-10-12 10:09:23 +0000309static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000310void log_1I_1Dw_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
njn25e49d8e72002-09-23 09:36:25 +0000311{
sewardj5155dec2005-10-12 10:09:23 +0000312 //VG_(printf)("1I_1Dw: CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n"
313 // " daddr=0x%010lx, dsize=%lu\n",
314 // n, n->instr_addr, n->instr_len, data_addr, data_size);
njn6a3009b2005-03-20 00:20:06 +0000315 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000316 &n->parent->Ir.m1, &n->parent->Ir.m2);
317 n->parent->Ir.a++;
318
sewardj5155dec2005-10-12 10:09:23 +0000319 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000320 &n->parent->Dw.m1, &n->parent->Dw.m2);
321 n->parent->Dw.a++;
njn25e49d8e72002-09-23 09:36:25 +0000322}
323
njnaf839f52005-06-23 03:27:57 +0000324static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000325void log_0I_1Dr_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
njn25e49d8e72002-09-23 09:36:25 +0000326{
sewardj5155dec2005-10-12 10:09:23 +0000327 //VG_(printf)("0I_1Dr: CCaddr=0x%010lx, daddr=0x%010lx, dsize=%lu\n",
328 // n, data_addr, data_size);
sewardj5155dec2005-10-12 10:09:23 +0000329 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000330 &n->parent->Dr.m1, &n->parent->Dr.m2);
331 n->parent->Dr.a++;
sewardj5155dec2005-10-12 10:09:23 +0000332}
333
334static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000335void log_0I_1Dw_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
sewardj5155dec2005-10-12 10:09:23 +0000336{
337 //VG_(printf)("0I_1Dw: CCaddr=0x%010lx, daddr=0x%010lx, dsize=%lu\n",
338 // n, data_addr, data_size);
sewardj5155dec2005-10-12 10:09:23 +0000339 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000340 &n->parent->Dw.m1, &n->parent->Dw.m2);
341 n->parent->Dw.a++;
njn25e49d8e72002-09-23 09:36:25 +0000342}
343
nethercote9313ac42004-07-06 21:54:20 +0000344/*------------------------------------------------------------*/
sewardj5155dec2005-10-12 10:09:23 +0000345/*--- Instrumentation types and structures ---*/
346/*------------------------------------------------------------*/
347
348/* Maintain an ordered list of memory events which are outstanding, in
349 the sense that no IR has yet been generated to do the relevant
350 helper calls. The BB is scanned top to bottom and memory events
351 are added to the end of the list, merging with the most recent
352 notified event where possible (Dw immediately following Dr and
353 having the same size and EA can be merged).
354
355 This merging is done so that for architectures which have
356 load-op-store instructions (x86, amd64), the insn is treated as if
357 it makes just one memory reference (a modify), rather than two (a
358 read followed by a write at the same address).
359
360 At various points the list will need to be flushed, that is, IR
361 generated from it. That must happen before any possible exit from
362 the block (the end, or an IRStmt_Exit). Flushing also takes place
363 when there is no space to add a new event.
364
365 If we require the simulation statistics to be up to date with
366 respect to possible memory exceptions, then the list would have to
367 be flushed before each memory reference. That would however lose
368 performance by inhibiting event-merging during flushing.
369
370 Flushing the list consists of walking it start to end and emitting
371 instrumentation IR for each event, in the order in which they
372 appear. It may be possible to emit a single call for two adjacent
373 events in order to reduce the number of helper function calls made.
374 For example, it could well be profitable to handle two adjacent Ir
375 events with a single helper call. */
376
377typedef
378 IRExpr
379 IRAtom;
380
381typedef
sewardj20edebf2005-10-12 10:29:40 +0000382 enum { Event_Ir, Event_Dr, Event_Dw, Event_Dm }
sewardj5155dec2005-10-12 10:09:23 +0000383 EventKind;
384
385typedef
386 struct {
njnfd9f6222005-10-16 00:17:37 +0000387 EventKind ekind; // All
388 InstrInfo* inode; // All; inode for this event's instruction
389 Int datasize; // Dr/Dw/Dm only
390 IRAtom* dataEA; // Dr/Dw/Dm only; IR ATOM ONLY
sewardj5155dec2005-10-12 10:09:23 +0000391 }
392 Event;
393
394/* Up to this many unnotified events are allowed. Number is
395 arbitrary. Larger numbers allow more event merging to occur, but
396 potentially induce more spilling due to extending live ranges of
397 address temporaries. */
398#define N_EVENTS 16
399
400
401/* A struct which holds all the running state during instrumentation.
402 Mostly to avoid passing loads of parameters everywhere. */
403typedef
404 struct {
405 /* The current outstanding-memory-event list. */
406 Event events[N_EVENTS];
407 Int events_used;
408
njnd3bef4f2005-10-15 17:46:18 +0000409 /* The array of InstrInfo bins for the BB. */
sewardj5155dec2005-10-12 10:09:23 +0000410 BB_info* bbInfo;
411
njnd3bef4f2005-10-15 17:46:18 +0000412 /* Number InstrInfo bins 'used' so far. */
sewardj5155dec2005-10-12 10:09:23 +0000413 Int bbInfo_i;
414
sewardj5155dec2005-10-12 10:09:23 +0000415 /* The output BB being constructed. */
416 IRBB* bbOut;
417 }
418 CgState;
419
420
sewardj5155dec2005-10-12 10:09:23 +0000421/*------------------------------------------------------------*/
422/*--- Instrumentation main ---*/
nethercote9313ac42004-07-06 21:54:20 +0000423/*------------------------------------------------------------*/
424
sewardj4ba057c2005-10-18 12:04:18 +0000425// Note that origAddr is the real origAddr, not the address of the first
426// instruction in the block (they can be different due to redirection).
nethercote564b2b02004-08-07 15:54:53 +0000427static
sewardja3a29a52005-10-12 16:16:03 +0000428BB_info* get_BB_info(IRBB* bbIn, Addr origAddr)
nethercote9313ac42004-07-06 21:54:20 +0000429{
njn4bd67b52005-08-11 00:47:10 +0000430 Int i, n_instrs;
431 IRStmt* st;
432 BB_info* bbInfo;
njnd3bef4f2005-10-15 17:46:18 +0000433
njn6a3009b2005-03-20 00:20:06 +0000434 // Count number of original instrs in BB
435 n_instrs = 0;
436 for (i = 0; i < bbIn->stmts_used; i++) {
437 st = bbIn->stmts[i];
438 if (Ist_IMark == st->tag) n_instrs++;
nethercote9313ac42004-07-06 21:54:20 +0000439 }
440
njnf7d26092005-10-12 16:45:17 +0000441 // Check that we don't have an entry for this BB in the instr-info table.
442 // If this assertion fails, there has been some screwup: some
443 // translations must have been discarded but Cachegrind hasn't discarded
444 // the corresponding entries in the instr-info table.
njnd3bef4f2005-10-15 17:46:18 +0000445 bbInfo = VG_(OSet_Lookup)(instrInfoTable, &origAddr);
sewardja3a29a52005-10-12 16:16:03 +0000446 tl_assert(NULL == bbInfo);
447
njnd3bef4f2005-10-15 17:46:18 +0000448 // BB never translated before (at this address, at least; could have
449 // been unloaded and then reloaded elsewhere in memory)
450 bbInfo = VG_(OSet_AllocNode)(instrInfoTable,
451 sizeof(BB_info) + n_instrs*sizeof(InstrInfo));
452 bbInfo->BB_addr = origAddr;
sewardja3a29a52005-10-12 16:16:03 +0000453 bbInfo->n_instrs = n_instrs;
njnd3bef4f2005-10-15 17:46:18 +0000454 VG_(OSet_Insert)( instrInfoTable, bbInfo );
sewardja3a29a52005-10-12 16:16:03 +0000455 distinct_instrs++;
456
njn6a3009b2005-03-20 00:20:06 +0000457 return bbInfo;
nethercote9313ac42004-07-06 21:54:20 +0000458}
njn6a3009b2005-03-20 00:20:06 +0000459
nethercote9313ac42004-07-06 21:54:20 +0000460
sewardj5155dec2005-10-12 10:09:23 +0000461static void showEvent ( Event* ev )
nethercote9313ac42004-07-06 21:54:20 +0000462{
sewardj5155dec2005-10-12 10:09:23 +0000463 switch (ev->ekind) {
464 case Event_Ir:
njnfd9f6222005-10-16 00:17:37 +0000465 VG_(printf)("Ir %p\n", ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000466 break;
467 case Event_Dr:
njnfd9f6222005-10-16 00:17:37 +0000468 VG_(printf)("Dr %p %d EA=", ev->inode, ev->datasize);
sewardj5155dec2005-10-12 10:09:23 +0000469 ppIRExpr(ev->dataEA);
470 VG_(printf)("\n");
471 break;
472 case Event_Dw:
njnfd9f6222005-10-16 00:17:37 +0000473 VG_(printf)("Dw %p %d EA=", ev->inode, ev->datasize);
sewardj5155dec2005-10-12 10:09:23 +0000474 ppIRExpr(ev->dataEA);
475 VG_(printf)("\n");
476 break;
477 case Event_Dm:
njnfd9f6222005-10-16 00:17:37 +0000478 VG_(printf)("Dm %p %d EA=", ev->inode, ev->datasize);
sewardj5155dec2005-10-12 10:09:23 +0000479 ppIRExpr(ev->dataEA);
480 VG_(printf)("\n");
481 break;
482 default:
483 tl_assert(0);
484 break;
485 }
njn6a3009b2005-03-20 00:20:06 +0000486}
487
njnfd9f6222005-10-16 00:17:37 +0000488// Reserve and initialise an InstrInfo for the first mention of a new insn.
489static
490InstrInfo* setup_InstrInfo ( CgState* cgs, Addr instr_addr, UInt instr_len )
njn6a3009b2005-03-20 00:20:06 +0000491{
njnd3bef4f2005-10-15 17:46:18 +0000492 InstrInfo* i_node;
sewardj5155dec2005-10-12 10:09:23 +0000493 tl_assert(cgs->bbInfo_i >= 0);
494 tl_assert(cgs->bbInfo_i < cgs->bbInfo->n_instrs);
495 i_node = &cgs->bbInfo->instrs[ cgs->bbInfo_i ];
njnfd9f6222005-10-16 00:17:37 +0000496 i_node->instr_addr = instr_addr;
497 i_node->instr_len = instr_len;
498 i_node->parent = get_lineCC(instr_addr);
sewardj5155dec2005-10-12 10:09:23 +0000499 cgs->bbInfo_i++;
500 return i_node;
501}
sewardj17a56bf2005-03-21 01:35:02 +0000502
sewardj17a56bf2005-03-21 01:35:02 +0000503
sewardj5155dec2005-10-12 10:09:23 +0000504/* Generate code for all outstanding memory events, and mark the queue
505 empty. Code is generated into cgs->bbOut, and this activity
506 'consumes' slots in cgs->bbInfo. */
njn6a3009b2005-03-20 00:20:06 +0000507
sewardj5155dec2005-10-12 10:09:23 +0000508static void flushEvents ( CgState* cgs )
509{
njnd3bef4f2005-10-15 17:46:18 +0000510 Int i, regparms;
511 Char* helperName;
512 void* helperAddr;
513 IRExpr** argv;
514 IRExpr* i_node_expr;
njnd3bef4f2005-10-15 17:46:18 +0000515 IRDirty* di;
njnc285dca2005-10-15 22:07:28 +0000516 Event* ev;
517 Event* ev2;
518 Event* ev3;
njn6a3009b2005-03-20 00:20:06 +0000519
sewardj5155dec2005-10-12 10:09:23 +0000520 i = 0;
521 while (i < cgs->events_used) {
njn6a3009b2005-03-20 00:20:06 +0000522
sewardj5155dec2005-10-12 10:09:23 +0000523 helperName = NULL;
524 helperAddr = NULL;
525 argv = NULL;
526 regparms = 0;
527
528 /* generate IR to notify event i and possibly the ones
529 immediately following it. */
530 tl_assert(i >= 0 && i < cgs->events_used);
njnc285dca2005-10-15 22:07:28 +0000531
532 ev = &cgs->events[i];
533 ev2 = ( i < cgs->events_used-1 ? &cgs->events[i+1] : NULL );
534 ev3 = ( i < cgs->events_used-2 ? &cgs->events[i+2] : NULL );
535
sewardj5155dec2005-10-12 10:09:23 +0000536 if (DEBUG_CG) {
537 VG_(printf)(" flush ");
njnc285dca2005-10-15 22:07:28 +0000538 showEvent( ev );
njn4f9c9342002-04-29 16:03:24 +0000539 }
sewardj5155dec2005-10-12 10:09:23 +0000540
njnfd9f6222005-10-16 00:17:37 +0000541 i_node_expr = mkIRExpr_HWord( (HWord)ev->inode );
sewardj5155dec2005-10-12 10:09:23 +0000542
543 /* Decide on helper fn to call and args to pass it, and advance
544 i appropriately. */
njnc285dca2005-10-15 22:07:28 +0000545 switch (ev->ekind) {
sewardj5155dec2005-10-12 10:09:23 +0000546 case Event_Ir:
547 /* Merge with a following Dr/Dm if it is from this insn. */
njnc285dca2005-10-15 22:07:28 +0000548 if (ev2 && (ev2->ekind == Event_Dr || ev2->ekind == Event_Dm)) {
njnfd9f6222005-10-16 00:17:37 +0000549 tl_assert(ev2->inode == ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000550 helperName = "log_1I_1Dr_cache_access";
551 helperAddr = &log_1I_1Dr_cache_access;
552 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000553 ev2->dataEA,
njnfd9f6222005-10-16 00:17:37 +0000554 mkIRExpr_HWord( ev2->datasize ) );
sewardj5155dec2005-10-12 10:09:23 +0000555 regparms = 3;
556 i += 2;
557 }
558 /* Merge with a following Dw if it is from this insn. */
559 else
njnc285dca2005-10-15 22:07:28 +0000560 if (ev2 && ev2->ekind == Event_Dw) {
njnfd9f6222005-10-16 00:17:37 +0000561 tl_assert(ev2->inode == ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000562 helperName = "log_1I_1Dw_cache_access";
563 helperAddr = &log_1I_1Dw_cache_access;
564 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000565 ev2->dataEA,
njnfd9f6222005-10-16 00:17:37 +0000566 mkIRExpr_HWord( ev2->datasize ) );
sewardj5155dec2005-10-12 10:09:23 +0000567 regparms = 3;
568 i += 2;
569 }
570 /* Merge with two following Irs if possible. */
571 else
njnc285dca2005-10-15 22:07:28 +0000572 if (ev2 && ev3 && ev2->ekind == Event_Ir && ev3->ekind == Event_Ir)
573 {
sewardj5155dec2005-10-12 10:09:23 +0000574 helperName = "log_3I_0D_cache_access";
575 helperAddr = &log_3I_0D_cache_access;
njnfd9f6222005-10-16 00:17:37 +0000576 argv = mkIRExprVec_3( i_node_expr,
577 mkIRExpr_HWord( (HWord)ev2->inode ),
578 mkIRExpr_HWord( (HWord)ev3->inode ) );
sewardj5155dec2005-10-12 10:09:23 +0000579 regparms = 3;
580 i += 3;
581 }
582 /* Merge with a following Ir if possible. */
583 else
njnc285dca2005-10-15 22:07:28 +0000584 if (ev2 && ev2->ekind == Event_Ir) {
sewardj5155dec2005-10-12 10:09:23 +0000585 helperName = "log_2I_0D_cache_access";
586 helperAddr = &log_2I_0D_cache_access;
njnfd9f6222005-10-16 00:17:37 +0000587 argv = mkIRExprVec_2( i_node_expr,
588 mkIRExpr_HWord( (HWord)ev2->inode ) );
sewardj5155dec2005-10-12 10:09:23 +0000589 regparms = 2;
590 i += 2;
591 }
592 /* No merging possible; emit as-is. */
593 else {
njnc285dca2005-10-15 22:07:28 +0000594 // Assertion: this Event_Ir must be the last one in the
595 // events buffer, otherwise it would have been merged with a
596 // following event.
597 tl_assert(!ev2 && !ev3);
sewardj5155dec2005-10-12 10:09:23 +0000598 helperName = "log_1I_0D_cache_access";
599 helperAddr = &log_1I_0D_cache_access;
600 argv = mkIRExprVec_1( i_node_expr );
601 regparms = 1;
602 i++;
603 }
604 break;
605 case Event_Dr:
606 case Event_Dm:
607 helperName = "log_0I_1Dr_cache_access";
608 helperAddr = &log_0I_1Dr_cache_access;
609 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000610 ev->dataEA,
njnfd9f6222005-10-16 00:17:37 +0000611 mkIRExpr_HWord( ev->datasize ) );
sewardj5155dec2005-10-12 10:09:23 +0000612 regparms = 3;
613 i++;
614 break;
615 case Event_Dw:
616 helperName = "log_0I_1Dw_cache_access";
617 helperAddr = &log_0I_1Dw_cache_access;
618 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000619 ev->dataEA,
njnfd9f6222005-10-16 00:17:37 +0000620 mkIRExpr_HWord( ev->datasize ) );
sewardj5155dec2005-10-12 10:09:23 +0000621 regparms = 3;
622 i++;
623 break;
624 default:
625 tl_assert(0);
626 }
627
628 /* Add the helper. */
629 tl_assert(helperName);
630 tl_assert(helperAddr);
631 tl_assert(argv);
sewardj5bb86822005-12-23 12:47:42 +0000632 di = unsafeIRDirty_0_N( regparms,
633 helperName, VG_(fnptr_to_fnentry)( helperAddr ),
634 argv );
sewardj5155dec2005-10-12 10:09:23 +0000635 addStmtToIRBB( cgs->bbOut, IRStmt_Dirty(di) );
njn4f9c9342002-04-29 16:03:24 +0000636 }
637
sewardj5155dec2005-10-12 10:09:23 +0000638 cgs->events_used = 0;
njn4f9c9342002-04-29 16:03:24 +0000639}
njn14d01ce2004-11-26 11:30:14 +0000640
njnfd9f6222005-10-16 00:17:37 +0000641static void addEvent_Ir ( CgState* cgs, InstrInfo* inode )
sewardj5155dec2005-10-12 10:09:23 +0000642{
643 Event* evt;
sewardj5155dec2005-10-12 10:09:23 +0000644 if (cgs->events_used == N_EVENTS)
645 flushEvents(cgs);
646 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
647 evt = &cgs->events[cgs->events_used];
njnfd9f6222005-10-16 00:17:37 +0000648 evt->ekind = Event_Ir;
649 evt->inode = inode;
650 evt->datasize = 0;
651 evt->dataEA = NULL; /*paranoia*/
sewardj5155dec2005-10-12 10:09:23 +0000652 cgs->events_used++;
653}
654
njnfd9f6222005-10-16 00:17:37 +0000655static
656void addEvent_Dr ( CgState* cgs, InstrInfo* inode, Int datasize, IRAtom* ea )
sewardj5155dec2005-10-12 10:09:23 +0000657{
njnfd9f6222005-10-16 00:17:37 +0000658 Event* evt;
sewardj5155dec2005-10-12 10:09:23 +0000659 tl_assert(isIRAtom(ea));
njnfd9f6222005-10-16 00:17:37 +0000660 tl_assert(datasize >= 1 && datasize <= MIN_LINE_SIZE);
661 if (cgs->events_used == N_EVENTS)
662 flushEvents(cgs);
663 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
664 evt = &cgs->events[cgs->events_used];
665 evt->ekind = Event_Dr;
666 evt->inode = inode;
667 evt->datasize = datasize;
668 evt->dataEA = ea;
669 cgs->events_used++;
670}
sewardj5155dec2005-10-12 10:09:23 +0000671
njnfd9f6222005-10-16 00:17:37 +0000672static
673void addEvent_Dw ( CgState* cgs, InstrInfo* inode, Int datasize, IRAtom* ea )
674{
675 Event* lastEvt;
676 Event* evt;
677
678 tl_assert(isIRAtom(ea));
679 tl_assert(datasize >= 1 && datasize <= MIN_LINE_SIZE);
680
681 /* Is it possible to merge this write with the preceding read? */
682 lastEvt = &cgs->events[cgs->events_used-1];
sewardj5155dec2005-10-12 10:09:23 +0000683 if (cgs->events_used > 0
njnfd9f6222005-10-16 00:17:37 +0000684 && lastEvt->ekind == Event_Dr
685 && lastEvt->datasize == datasize
686 && lastEvt->inode == inode
687 && eqIRAtom(lastEvt->dataEA, ea))
688 {
689 lastEvt->ekind = Event_Dm;
sewardj5155dec2005-10-12 10:09:23 +0000690 return;
691 }
692
693 /* No. Add as normal. */
694 if (cgs->events_used == N_EVENTS)
695 flushEvents(cgs);
696 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
njnfd9f6222005-10-16 00:17:37 +0000697 evt = &cgs->events[cgs->events_used];
698 evt->ekind = Event_Dw;
699 evt->inode = inode;
700 evt->datasize = datasize;
701 evt->dataEA = ea;
sewardj5155dec2005-10-12 10:09:23 +0000702 cgs->events_used++;
703}
704
705////////////////////////////////////////////////////////////
706
707
sewardj4ba057c2005-10-18 12:04:18 +0000708static
sewardj461df9c2006-01-17 02:06:39 +0000709IRBB* cg_instrument ( VgCallbackClosure* closure,
710 IRBB* bbIn,
711 VexGuestLayout* layout,
712 VexGuestExtents* vge,
sewardj4ba057c2005-10-18 12:04:18 +0000713 IRType gWordTy, IRType hWordTy )
njn14d01ce2004-11-26 11:30:14 +0000714{
njnfd9f6222005-10-16 00:17:37 +0000715 Int i, isize;
sewardj5155dec2005-10-12 10:09:23 +0000716 IRStmt* st;
717 Addr64 cia; /* address of current insn */
718 CgState cgs;
719 IRTypeEnv* tyenv = bbIn->tyenv;
njnfd9f6222005-10-16 00:17:37 +0000720 InstrInfo* curr_inode = NULL;
sewardj5155dec2005-10-12 10:09:23 +0000721
sewardjd54babf2005-03-21 00:55:49 +0000722 if (gWordTy != hWordTy) {
723 /* We don't currently support this case. */
724 VG_(tool_panic)("host/guest word size mismatch");
725 }
726
njnfd9f6222005-10-16 00:17:37 +0000727 /* Set up BB, including copying of the where-next stuff. */
728 cgs.bbOut = emptyIRBB();
729 cgs.bbOut->tyenv = dopyIRTypeEnv(tyenv);
730 tl_assert( isIRAtom(bbIn->next) );
731 cgs.bbOut->next = dopyIRExpr(bbIn->next);
732 cgs.bbOut->jumpkind = bbIn->jumpkind;
njn6a3009b2005-03-20 00:20:06 +0000733
sewardja9f538c2005-10-23 12:06:55 +0000734 // Copy verbatim any IR preamble preceding the first IMark
njn6a3009b2005-03-20 00:20:06 +0000735 i = 0;
sewardja9f538c2005-10-23 12:06:55 +0000736 while (i < bbIn->stmts_used && bbIn->stmts[i]->tag != Ist_IMark) {
737 addStmtToIRBB( cgs.bbOut, bbIn->stmts[i] );
738 i++;
739 }
740
741 // Get the first statement, and initial cia from it
njn6a3009b2005-03-20 00:20:06 +0000742 tl_assert(bbIn->stmts_used > 0);
sewardja9f538c2005-10-23 12:06:55 +0000743 tl_assert(i < bbIn->stmts_used);
744 st = bbIn->stmts[i];
njn6a3009b2005-03-20 00:20:06 +0000745 tl_assert(Ist_IMark == st->tag);
sewardj5155dec2005-10-12 10:09:23 +0000746 cia = st->Ist.IMark.addr;
njn6a3009b2005-03-20 00:20:06 +0000747
sewardj5155dec2005-10-12 10:09:23 +0000748 // Set up running state and get block info
sewardj3a384b32006-01-22 01:12:51 +0000749 tl_assert(closure->readdr == vge->base[0]);
sewardj5155dec2005-10-12 10:09:23 +0000750 cgs.events_used = 0;
sewardj3a384b32006-01-22 01:12:51 +0000751 cgs.bbInfo = get_BB_info(bbIn, (Addr)closure->readdr);
sewardj5155dec2005-10-12 10:09:23 +0000752 cgs.bbInfo_i = 0;
njn6a3009b2005-03-20 00:20:06 +0000753
sewardj5155dec2005-10-12 10:09:23 +0000754 if (DEBUG_CG)
755 VG_(printf)("\n\n---------- cg_instrument ----------\n");
njn6a3009b2005-03-20 00:20:06 +0000756
njnfd9f6222005-10-16 00:17:37 +0000757 // Traverse the block, initialising inodes, adding events and flushing as
758 // necessary.
sewardja9f538c2005-10-23 12:06:55 +0000759 for (/*use current i*/; i < bbIn->stmts_used; i++) {
njn6a3009b2005-03-20 00:20:06 +0000760
sewardj5155dec2005-10-12 10:09:23 +0000761 st = bbIn->stmts[i];
762 tl_assert(isFlatIRStmt(st));
njnb3507ea2005-08-02 23:07:02 +0000763
sewardj5155dec2005-10-12 10:09:23 +0000764 switch (st->tag) {
765 case Ist_NoOp:
766 case Ist_AbiHint:
767 case Ist_Put:
768 case Ist_PutI:
769 case Ist_MFence:
770 break;
njn20677cc2005-08-12 23:47:51 +0000771
sewardj5155dec2005-10-12 10:09:23 +0000772 case Ist_IMark:
njnfd9f6222005-10-16 00:17:37 +0000773 cia = st->Ist.IMark.addr;
774 isize = st->Ist.IMark.len;
775
776 // If Vex fails to decode an instruction, the size will be zero.
777 // Pretend otherwise.
778 if (isize == 0) isize = VG_MIN_INSTR_SZB;
779
njna5ad9ba2005-11-10 15:20:37 +0000780 // Sanity-check size.
781 tl_assert( (VG_MIN_INSTR_SZB <= isize && isize <= VG_MAX_INSTR_SZB)
782 || VG_CLREQ_SZB == isize );
njnfd9f6222005-10-16 00:17:37 +0000783
784 // Get space for and init the inode, record it as the current one.
785 // Subsequent Dr/Dw/Dm events from the same instruction will
786 // also use it.
787 curr_inode = setup_InstrInfo(&cgs, cia, isize);
788
789 addEvent_Ir( &cgs, curr_inode );
sewardj5155dec2005-10-12 10:09:23 +0000790 break;
791
792 case Ist_Tmp: {
793 IRExpr* data = st->Ist.Tmp.data;
794 if (data->tag == Iex_Load) {
795 IRExpr* aexpr = data->Iex.Load.addr;
sewardj5155dec2005-10-12 10:09:23 +0000796 // Note also, endianness info is ignored. I guess
797 // that's not interesting.
njnfd9f6222005-10-16 00:17:37 +0000798 addEvent_Dr( &cgs, curr_inode, sizeofIRType(data->Iex.Load.ty),
799 aexpr );
sewardj5155dec2005-10-12 10:09:23 +0000800 }
801 break;
njnb3507ea2005-08-02 23:07:02 +0000802 }
803
sewardj5155dec2005-10-12 10:09:23 +0000804 case Ist_Store: {
805 IRExpr* data = st->Ist.Store.data;
806 IRExpr* aexpr = st->Ist.Store.addr;
njnfd9f6222005-10-16 00:17:37 +0000807 addEvent_Dw( &cgs, curr_inode,
808 sizeofIRType(typeOfIRExpr(tyenv, data)), aexpr );
sewardj5155dec2005-10-12 10:09:23 +0000809 break;
810 }
njnb3507ea2005-08-02 23:07:02 +0000811
sewardj5155dec2005-10-12 10:09:23 +0000812 case Ist_Dirty: {
813 Int dataSize;
814 IRDirty* d = st->Ist.Dirty.details;
815 if (d->mFx != Ifx_None) {
njnfd9f6222005-10-16 00:17:37 +0000816 /* This dirty helper accesses memory. Collect the details. */
sewardj5155dec2005-10-12 10:09:23 +0000817 tl_assert(d->mAddr != NULL);
818 tl_assert(d->mSize != 0);
819 dataSize = d->mSize;
820 // Large (eg. 28B, 108B, 512B on x86) data-sized
821 // instructions will be done inaccurately, but they're
822 // very rare and this avoids errors from hitting more
823 // than two cache lines in the simulation.
824 if (dataSize > MIN_LINE_SIZE)
825 dataSize = MIN_LINE_SIZE;
826 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
njnfd9f6222005-10-16 00:17:37 +0000827 addEvent_Dr( &cgs, curr_inode, dataSize, d->mAddr );
sewardj5155dec2005-10-12 10:09:23 +0000828 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
njnfd9f6222005-10-16 00:17:37 +0000829 addEvent_Dw( &cgs, curr_inode, dataSize, d->mAddr );
sewardj5155dec2005-10-12 10:09:23 +0000830 } else {
831 tl_assert(d->mAddr == NULL);
832 tl_assert(d->mSize == 0);
833 }
834 break;
835 }
njn6a3009b2005-03-20 00:20:06 +0000836
sewardj5155dec2005-10-12 10:09:23 +0000837 case Ist_Exit:
838 /* We may never reach the next statement, so need to flush
839 all outstanding transactions now. */
840 flushEvents( &cgs );
841 break;
842
843 default:
844 tl_assert(0);
845 break;
njnb3507ea2005-08-02 23:07:02 +0000846 }
njn6a3009b2005-03-20 00:20:06 +0000847
sewardj5155dec2005-10-12 10:09:23 +0000848 /* Copy the original statement */
849 addStmtToIRBB( cgs.bbOut, st );
njn6a3009b2005-03-20 00:20:06 +0000850
sewardj5155dec2005-10-12 10:09:23 +0000851 if (DEBUG_CG) {
852 ppIRStmt(st);
853 VG_(printf)("\n");
854 }
855 }
856
857 /* At the end of the bb. Flush outstandings. */
sewardj5155dec2005-10-12 10:09:23 +0000858 flushEvents( &cgs );
859
sewardj5155dec2005-10-12 10:09:23 +0000860 /* done. stay sane ... */
861 tl_assert(cgs.bbInfo_i == cgs.bbInfo->n_instrs);
862
863 if (DEBUG_CG) {
864 VG_(printf)( "goto {");
865 ppIRJumpKind(bbIn->jumpkind);
866 VG_(printf)( "} ");
867 ppIRExpr( bbIn->next );
868 VG_(printf)( "}\n");
869 }
870
871 return cgs.bbOut;
njn14d01ce2004-11-26 11:30:14 +0000872}
njn4f9c9342002-04-29 16:03:24 +0000873
874/*------------------------------------------------------------*/
nethercoteb35a8b92004-09-11 16:45:27 +0000875/*--- Cache configuration ---*/
njn4f9c9342002-04-29 16:03:24 +0000876/*------------------------------------------------------------*/
877
sewardjb5f6f512005-03-10 23:59:00 +0000878#define UNDEFINED_CACHE { -1, -1, -1 }
njn25e49d8e72002-09-23 09:36:25 +0000879
880static cache_t clo_I1_cache = UNDEFINED_CACHE;
881static cache_t clo_D1_cache = UNDEFINED_CACHE;
882static cache_t clo_L2_cache = UNDEFINED_CACHE;
883
njn7cf0bd32002-06-08 13:36:03 +0000884/* Checks cache config is ok; makes it so if not. */
sewardj07133bf2002-06-13 10:25:56 +0000885static
njna1d1a642004-11-26 18:36:02 +0000886void check_cache(cache_t* cache, Char *name)
njn7cf0bd32002-06-08 13:36:03 +0000887{
888 /* First check they're all powers of two */
sewardj07133bf2002-06-13 10:25:56 +0000889 if (-1 == VG_(log2)(cache->size)) {
njn7cf0bd32002-06-08 13:36:03 +0000890 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000891 "error: %s size of %dB not a power of two; aborting.",
892 name, cache->size);
893 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000894 }
895
sewardj07133bf2002-06-13 10:25:56 +0000896 if (-1 == VG_(log2)(cache->assoc)) {
njn7cf0bd32002-06-08 13:36:03 +0000897 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000898 "error: %s associativity of %d not a power of two; aborting.",
899 name, cache->assoc);
900 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000901 }
902
sewardj07133bf2002-06-13 10:25:56 +0000903 if (-1 == VG_(log2)(cache->line_size)) {
njn7cf0bd32002-06-08 13:36:03 +0000904 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000905 "error: %s line size of %dB not a power of two; aborting.",
906 name, cache->line_size);
907 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000908 }
909
njn6a3009b2005-03-20 00:20:06 +0000910 // Then check line size >= 16 -- any smaller and a single instruction could
911 // straddle three cache lines, which breaks a simulation assertion and is
912 // stupid anyway.
njn7cf0bd32002-06-08 13:36:03 +0000913 if (cache->line_size < MIN_LINE_SIZE) {
914 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000915 "error: %s line size of %dB too small; aborting.",
916 name, cache->line_size);
917 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000918 }
919
920 /* Then check cache size > line size (causes seg faults if not). */
921 if (cache->size <= cache->line_size) {
922 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000923 "error: %s cache size of %dB <= line size of %dB; aborting.",
924 name, cache->size, cache->line_size);
925 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000926 }
927
928 /* Then check assoc <= (size / line size) (seg faults otherwise). */
929 if (cache->assoc > (cache->size / cache->line_size)) {
930 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000931 "warning: %s associativity > (size / line size); aborting.", name);
932 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000933 }
934}
935
sewardj07133bf2002-06-13 10:25:56 +0000936static
nethercoteb35a8b92004-09-11 16:45:27 +0000937void configure_caches(cache_t* I1c, cache_t* D1c, cache_t* L2c)
njn7cf0bd32002-06-08 13:36:03 +0000938{
nethercote9313ac42004-07-06 21:54:20 +0000939#define DEFINED(L) (-1 != L.size || -1 != L.assoc || -1 != L.line_size)
940
nethercoteb35a8b92004-09-11 16:45:27 +0000941 Int n_clos = 0;
nethercote9313ac42004-07-06 21:54:20 +0000942
nethercoteb35a8b92004-09-11 16:45:27 +0000943 // Count how many were defined on the command line.
944 if (DEFINED(clo_I1_cache)) { n_clos++; }
945 if (DEFINED(clo_D1_cache)) { n_clos++; }
946 if (DEFINED(clo_L2_cache)) { n_clos++; }
njn7cf0bd32002-06-08 13:36:03 +0000947
njna1d1a642004-11-26 18:36:02 +0000948 // Set the cache config (using auto-detection, if supported by the
949 // architecture)
njnaf839f52005-06-23 03:27:57 +0000950 VG_(configure_caches)( I1c, D1c, L2c, (3 == n_clos) );
sewardjb1a77a42002-07-13 13:31:20 +0000951
nethercote9313ac42004-07-06 21:54:20 +0000952 // Then replace with any defined on the command line.
nethercoteb35a8b92004-09-11 16:45:27 +0000953 if (DEFINED(clo_I1_cache)) { *I1c = clo_I1_cache; }
954 if (DEFINED(clo_D1_cache)) { *D1c = clo_D1_cache; }
955 if (DEFINED(clo_L2_cache)) { *L2c = clo_L2_cache; }
njn7cf0bd32002-06-08 13:36:03 +0000956
nethercote9313ac42004-07-06 21:54:20 +0000957 // Then check values and fix if not acceptable.
njna1d1a642004-11-26 18:36:02 +0000958 check_cache(I1c, "I1");
959 check_cache(D1c, "D1");
960 check_cache(L2c, "L2");
njn7cf0bd32002-06-08 13:36:03 +0000961
962 if (VG_(clo_verbosity) > 1) {
963 VG_(message)(Vg_UserMsg, "Cache configuration used:");
964 VG_(message)(Vg_UserMsg, " I1: %dB, %d-way, %dB lines",
965 I1c->size, I1c->assoc, I1c->line_size);
966 VG_(message)(Vg_UserMsg, " D1: %dB, %d-way, %dB lines",
967 D1c->size, D1c->assoc, D1c->line_size);
968 VG_(message)(Vg_UserMsg, " L2: %dB, %d-way, %dB lines",
969 L2c->size, L2c->assoc, L2c->line_size);
970 }
nethercote9313ac42004-07-06 21:54:20 +0000971#undef CMD_LINE_DEFINED
njn7cf0bd32002-06-08 13:36:03 +0000972}
973
njn4f9c9342002-04-29 16:03:24 +0000974/*------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +0000975/*--- cg_fini() and related function ---*/
njn4f9c9342002-04-29 16:03:24 +0000976/*------------------------------------------------------------*/
977
nethercote9313ac42004-07-06 21:54:20 +0000978// Total reads/writes/misses. Calculated during CC traversal at the end.
979// All auto-zeroed.
980static CC Ir_total;
981static CC Dr_total;
982static CC Dw_total;
983
984static Char* cachegrind_out_file;
985
nethercote9313ac42004-07-06 21:54:20 +0000986static void fprint_CC_table_and_calc_totals(void)
987{
njnd3bef4f2005-10-15 17:46:18 +0000988 Int i, fd;
sewardj92645592005-07-23 09:18:34 +0000989 SysRes sres;
njnd3bef4f2005-10-15 17:46:18 +0000990 Char buf[512], *currFile = NULL, *currFn = NULL;
991 LineCC* lineCC;
njn4f9c9342002-04-29 16:03:24 +0000992
sewardj92645592005-07-23 09:18:34 +0000993 sres = VG_(open)(cachegrind_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
994 VKI_S_IRUSR|VKI_S_IWUSR);
995 if (sres.isError) {
nethercote9313ac42004-07-06 21:54:20 +0000996 // If the file can't be opened for whatever reason (conflict
997 // between multiple cachegrinded processes?), give up now.
njnee0e6a32005-04-24 00:21:01 +0000998 VG_(message)(Vg_UserMsg,
njn02bc4b82005-05-15 17:28:26 +0000999 "error: can't open cache simulation output file '%s'",
njnee0e6a32005-04-24 00:21:01 +00001000 cachegrind_out_file );
1001 VG_(message)(Vg_UserMsg,
1002 " ... so simulation results will be missing.");
sewardj0744b6c2002-12-11 00:45:42 +00001003 return;
sewardj92645592005-07-23 09:18:34 +00001004 } else {
sewardje8089302006-10-17 02:15:17 +00001005 fd = sres.res;
sewardj0744b6c2002-12-11 00:45:42 +00001006 }
njn4f9c9342002-04-29 16:03:24 +00001007
nethercote9313ac42004-07-06 21:54:20 +00001008 // "desc:" lines (giving I1/D1/L2 cache configuration). The spaces after
1009 // the 2nd colon makes cg_annotate's output look nicer.
1010 VG_(sprintf)(buf, "desc: I1 cache: %s\n"
1011 "desc: D1 cache: %s\n"
1012 "desc: L2 cache: %s\n",
1013 I1.desc_line, D1.desc_line, L2.desc_line);
njn7cf0bd32002-06-08 13:36:03 +00001014 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njn4f9c9342002-04-29 16:03:24 +00001015
nethercote9313ac42004-07-06 21:54:20 +00001016 // "cmd:" line
njn4f9c9342002-04-29 16:03:24 +00001017 VG_(strcpy)(buf, "cmd:");
1018 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
sewardj45f4e7c2005-09-27 19:20:21 +00001019 if (VG_(args_the_exename)) {
1020 VG_(write)(fd, " ", 1);
1021 VG_(write)(fd, VG_(args_the_exename),
1022 VG_(strlen)( VG_(args_the_exename) ));
1023 }
1024 for (i = 0; i < VG_(args_for_client).used; i++) {
1025 if (VG_(args_for_client).strs[i]) {
1026 VG_(write)(fd, " ", 1);
1027 VG_(write)(fd, VG_(args_for_client).strs[i],
1028 VG_(strlen)(VG_(args_for_client).strs[i]));
1029 }
njn4f9c9342002-04-29 16:03:24 +00001030 }
nethercote9313ac42004-07-06 21:54:20 +00001031 // "events:" line
njn4f9c9342002-04-29 16:03:24 +00001032 VG_(sprintf)(buf, "\nevents: Ir I1mr I2mr Dr D1mr D2mr Dw D1mw D2mw\n");
1033 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1034
njnd3bef4f2005-10-15 17:46:18 +00001035 // Traverse every lineCC
1036 VG_(OSet_ResetIter)(CC_table);
1037 while ( (lineCC = VG_(OSet_Next)(CC_table)) ) {
njn4311fe62005-12-08 23:18:50 +00001038 Bool just_hit_a_new_file = False;
njnd3bef4f2005-10-15 17:46:18 +00001039 // If we've hit a new file, print a "fl=" line. Note that because
1040 // each string is stored exactly once in the string table, we can use
1041 // pointer comparison rather than strcmp() to test for equality, which
1042 // is good because most of the time the comparisons are equal and so
njn4311fe62005-12-08 23:18:50 +00001043 // the whole strings would have to be checked.
njnd3bef4f2005-10-15 17:46:18 +00001044 if ( lineCC->loc.file != currFile ) {
1045 currFile = lineCC->loc.file;
1046 VG_(sprintf)(buf, "fl=%s\n", currFile);
njn4f9c9342002-04-29 16:03:24 +00001047 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njnd3bef4f2005-10-15 17:46:18 +00001048 distinct_files++;
njn4311fe62005-12-08 23:18:50 +00001049 just_hit_a_new_file = True;
njn4f9c9342002-04-29 16:03:24 +00001050 }
njn4311fe62005-12-08 23:18:50 +00001051 // If we've hit a new function, print a "fn=" line. We know to do
1052 // this when the function name changes, and also every time we hit a
1053 // new file (in which case the new function name might be the same as
1054 // in the old file, hence the just_hit_a_new_file test).
1055 if ( just_hit_a_new_file || lineCC->loc.fn != currFn ) {
njnd3bef4f2005-10-15 17:46:18 +00001056 currFn = lineCC->loc.fn;
1057 VG_(sprintf)(buf, "fn=%s\n", currFn);
1058 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1059 distinct_fns++;
njn4311fe62005-12-08 23:18:50 +00001060 just_hit_a_new_file = False;
njnd3bef4f2005-10-15 17:46:18 +00001061 }
1062
1063 // Print the LineCC
1064 VG_(sprintf)(buf, "%u %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
1065 lineCC->loc.line,
1066 lineCC->Ir.a, lineCC->Ir.m1, lineCC->Ir.m2,
1067 lineCC->Dr.a, lineCC->Dr.m1, lineCC->Dr.m2,
1068 lineCC->Dw.a, lineCC->Dw.m1, lineCC->Dw.m2);
1069 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1070
1071 // Update summary stats
1072 Ir_total.a += lineCC->Ir.a;
1073 Ir_total.m1 += lineCC->Ir.m1;
1074 Ir_total.m2 += lineCC->Ir.m2;
1075 Dr_total.a += lineCC->Dr.a;
1076 Dr_total.m1 += lineCC->Dr.m1;
1077 Dr_total.m2 += lineCC->Dr.m2;
1078 Dw_total.a += lineCC->Dw.a;
1079 Dw_total.m1 += lineCC->Dw.m1;
1080 Dw_total.m2 += lineCC->Dw.m2;
1081
1082 distinct_lines++;
njn4f9c9342002-04-29 16:03:24 +00001083 }
1084
nethercote9313ac42004-07-06 21:54:20 +00001085 // Summary stats must come after rest of table, since we calculate them
1086 // during traversal. */
njn4f9c9342002-04-29 16:03:24 +00001087 VG_(sprintf)(buf, "summary: "
nethercote9313ac42004-07-06 21:54:20 +00001088 "%llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
njn4f9c9342002-04-29 16:03:24 +00001089 Ir_total.a, Ir_total.m1, Ir_total.m2,
1090 Dr_total.a, Dr_total.m1, Dr_total.m2,
1091 Dw_total.a, Dw_total.m1, Dw_total.m2);
1092 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1093 VG_(close)(fd);
1094}
1095
njn607adfc2003-09-30 14:15:44 +00001096static UInt ULong_width(ULong n)
njn4f9c9342002-04-29 16:03:24 +00001097{
njn607adfc2003-09-30 14:15:44 +00001098 UInt w = 0;
1099 while (n > 0) {
1100 n = n / 10;
1101 w++;
njn4f9c9342002-04-29 16:03:24 +00001102 }
sewardj46c59b12005-11-01 02:20:19 +00001103 if (w == 0) w = 1;
njn607adfc2003-09-30 14:15:44 +00001104 return w + (w-1)/3; // add space for commas
njn4f9c9342002-04-29 16:03:24 +00001105}
1106
njn51d827b2005-05-09 01:02:08 +00001107static void cg_fini(Int exitcode)
njn4f9c9342002-04-29 16:03:24 +00001108{
njn1baf7db2006-04-18 22:34:48 +00001109 static Char buf1[128], buf2[128], buf3[128], buf4[123], fmt[128];
njn607adfc2003-09-30 14:15:44 +00001110
njn4f9c9342002-04-29 16:03:24 +00001111 CC D_total;
njn1d021fa2002-05-02 13:56:34 +00001112 ULong L2_total_m, L2_total_mr, L2_total_mw,
1113 L2_total, L2_total_r, L2_total_w;
njn4f9c9342002-04-29 16:03:24 +00001114 Int l1, l2, l3;
1115 Int p;
1116
nethercote9313ac42004-07-06 21:54:20 +00001117 fprint_CC_table_and_calc_totals();
njn4f9c9342002-04-29 16:03:24 +00001118
njn7cf0bd32002-06-08 13:36:03 +00001119 if (VG_(clo_verbosity) == 0)
1120 return;
1121
njn4f9c9342002-04-29 16:03:24 +00001122 /* I cache results. Use the I_refs value to determine the first column
1123 * width. */
njn607adfc2003-09-30 14:15:44 +00001124 l1 = ULong_width(Ir_total.a);
1125 l2 = ULong_width(Dr_total.a);
1126 l3 = ULong_width(Dw_total.a);
njn4f9c9342002-04-29 16:03:24 +00001127
njn607adfc2003-09-30 14:15:44 +00001128 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001129 VG_(sprintf)(fmt, "%%s %%,%dllu", l1);
njnd3bef4f2005-10-15 17:46:18 +00001130
njn607adfc2003-09-30 14:15:44 +00001131 VG_(message)(Vg_UserMsg, fmt, "I refs: ", Ir_total.a);
1132 VG_(message)(Vg_UserMsg, fmt, "I1 misses: ", Ir_total.m1);
1133 VG_(message)(Vg_UserMsg, fmt, "L2i misses: ", Ir_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001134
1135 p = 100;
1136
njn25e49d8e72002-09-23 09:36:25 +00001137 if (0 == Ir_total.a) Ir_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001138 VG_(percentify)(Ir_total.m1, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001139 VG_(message)(Vg_UserMsg, "I1 miss rate: %s", buf1);
njnd3bef4f2005-10-15 17:46:18 +00001140
njn856c54e2005-06-26 18:43:40 +00001141 VG_(percentify)(Ir_total.m2, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001142 VG_(message)(Vg_UserMsg, "L2i miss rate: %s", buf1);
1143 VG_(message)(Vg_UserMsg, "");
1144
1145 /* D cache results. Use the D_refs.rd and D_refs.wr values to determine the
1146 * width of columns 2 & 3. */
1147 D_total.a = Dr_total.a + Dw_total.a;
1148 D_total.m1 = Dr_total.m1 + Dw_total.m1;
1149 D_total.m2 = Dr_total.m2 + Dw_total.m2;
njnd3bef4f2005-10-15 17:46:18 +00001150
njn607adfc2003-09-30 14:15:44 +00001151 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001152 VG_(sprintf)(fmt, "%%s %%,%dllu (%%,%dllu rd + %%,%dllu wr)", l1, l2, l3);
njn4f9c9342002-04-29 16:03:24 +00001153
njn607adfc2003-09-30 14:15:44 +00001154 VG_(message)(Vg_UserMsg, fmt, "D refs: ",
1155 D_total.a, Dr_total.a, Dw_total.a);
1156 VG_(message)(Vg_UserMsg, fmt, "D1 misses: ",
1157 D_total.m1, Dr_total.m1, Dw_total.m1);
1158 VG_(message)(Vg_UserMsg, fmt, "L2d misses: ",
1159 D_total.m2, Dr_total.m2, Dw_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001160
1161 p = 10;
njnd3bef4f2005-10-15 17:46:18 +00001162
njn25e49d8e72002-09-23 09:36:25 +00001163 if (0 == D_total.a) D_total.a = 1;
1164 if (0 == Dr_total.a) Dr_total.a = 1;
1165 if (0 == Dw_total.a) Dw_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001166 VG_(percentify)( D_total.m1, D_total.a, 1, l1+1, buf1);
1167 VG_(percentify)(Dr_total.m1, Dr_total.a, 1, l2+1, buf2);
1168 VG_(percentify)(Dw_total.m1, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001169 VG_(message)(Vg_UserMsg, "D1 miss rate: %s (%s + %s )", buf1, buf2,buf3);
1170
njn856c54e2005-06-26 18:43:40 +00001171 VG_(percentify)( D_total.m2, D_total.a, 1, l1+1, buf1);
1172 VG_(percentify)(Dr_total.m2, Dr_total.a, 1, l2+1, buf2);
1173 VG_(percentify)(Dw_total.m2, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001174 VG_(message)(Vg_UserMsg, "L2d miss rate: %s (%s + %s )", buf1, buf2,buf3);
1175 VG_(message)(Vg_UserMsg, "");
1176
1177 /* L2 overall results */
njn1d021fa2002-05-02 13:56:34 +00001178
1179 L2_total = Dr_total.m1 + Dw_total.m1 + Ir_total.m1;
1180 L2_total_r = Dr_total.m1 + Ir_total.m1;
1181 L2_total_w = Dw_total.m1;
njn607adfc2003-09-30 14:15:44 +00001182 VG_(message)(Vg_UserMsg, fmt, "L2 refs: ",
1183 L2_total, L2_total_r, L2_total_w);
njn1d021fa2002-05-02 13:56:34 +00001184
njn4f9c9342002-04-29 16:03:24 +00001185 L2_total_m = Dr_total.m2 + Dw_total.m2 + Ir_total.m2;
1186 L2_total_mr = Dr_total.m2 + Ir_total.m2;
1187 L2_total_mw = Dw_total.m2;
njn607adfc2003-09-30 14:15:44 +00001188 VG_(message)(Vg_UserMsg, fmt, "L2 misses: ",
1189 L2_total_m, L2_total_mr, L2_total_mw);
njn4f9c9342002-04-29 16:03:24 +00001190
njn856c54e2005-06-26 18:43:40 +00001191 VG_(percentify)(L2_total_m, (Ir_total.a + D_total.a), 1, l1+1, buf1);
1192 VG_(percentify)(L2_total_mr, (Ir_total.a + Dr_total.a), 1, l2+1, buf2);
1193 VG_(percentify)(L2_total_mw, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001194 VG_(message)(Vg_UserMsg, "L2 miss rate: %s (%s + %s )", buf1, buf2,buf3);
njnd3bef4f2005-10-15 17:46:18 +00001195
njn4f9c9342002-04-29 16:03:24 +00001196
nethercote9313ac42004-07-06 21:54:20 +00001197 // Various stats
njn4f9c9342002-04-29 16:03:24 +00001198 if (VG_(clo_verbosity) > 1) {
njn1baf7db2006-04-18 22:34:48 +00001199 Int debug_lookups = full_debugs + fn_debugs +
1200 file_line_debugs + no_debugs;
njnd3bef4f2005-10-15 17:46:18 +00001201
njn1baf7db2006-04-18 22:34:48 +00001202 VG_(message)(Vg_DebugMsg, "");
1203 VG_(message)(Vg_DebugMsg, "cachegrind: distinct files: %d", distinct_files);
1204 VG_(message)(Vg_DebugMsg, "cachegrind: distinct fns: %d", distinct_fns);
1205 VG_(message)(Vg_DebugMsg, "cachegrind: distinct lines: %d", distinct_lines);
1206 VG_(message)(Vg_DebugMsg, "cachegrind: distinct instrs:%d", distinct_instrs);
1207 VG_(message)(Vg_DebugMsg, "cachegrind: debug lookups : %d", debug_lookups);
1208
1209 VG_(percentify)(full_debugs, debug_lookups, 1, 6, buf1);
1210 VG_(percentify)(file_line_debugs, debug_lookups, 1, 6, buf2);
1211 VG_(percentify)(fn_debugs, debug_lookups, 1, 6, buf3);
1212 VG_(percentify)(no_debugs, debug_lookups, 1, 6, buf4);
1213 VG_(message)(Vg_DebugMsg, "cachegrind: with full info:%s (%d)",
1214 buf1, full_debugs);
1215 VG_(message)(Vg_DebugMsg, "cachegrind: with file/line info:%s (%d)",
1216 buf2, file_line_debugs);
1217 VG_(message)(Vg_DebugMsg, "cachegrind: with fn name info:%s (%d)",
1218 buf3, fn_debugs);
1219 VG_(message)(Vg_DebugMsg, "cachegrind: with zero info:%s (%d)",
1220 buf4, no_debugs);
1221
1222 VG_(message)(Vg_DebugMsg, "cachegrind: string table size: %u",
1223 VG_(OSet_Size)(stringTable));
1224 VG_(message)(Vg_DebugMsg, "cachegrind: CC table size: %u",
1225 VG_(OSet_Size)(CC_table));
1226 VG_(message)(Vg_DebugMsg, "cachegrind: InstrInfo table size: %u",
1227 VG_(OSet_Size)(instrInfoTable));
njn4f9c9342002-04-29 16:03:24 +00001228 }
njn4f9c9342002-04-29 16:03:24 +00001229}
1230
nethercote9313ac42004-07-06 21:54:20 +00001231/*--------------------------------------------------------------------*/
1232/*--- Discarding BB info ---*/
1233/*--------------------------------------------------------------------*/
sewardj18d75132002-05-16 11:06:21 +00001234
sewardja3a29a52005-10-12 16:16:03 +00001235// Called when a translation is removed from the translation cache for
1236// any reason at all: to free up space, because the guest code was
1237// unmapped or modified, or for any arbitrary reason.
sewardj4ba057c2005-10-18 12:04:18 +00001238static
1239void cg_discard_basic_block_info ( Addr64 orig_addr64, VexGuestExtents vge )
sewardj18d75132002-05-16 11:06:21 +00001240{
njnd3bef4f2005-10-15 17:46:18 +00001241 BB_info* bbInfo;
sewardj3a384b32006-01-22 01:12:51 +00001242 Addr orig_addr = (Addr)vge.base[0];
njn4294fd42002-06-05 14:41:10 +00001243
sewardj5155dec2005-10-12 10:09:23 +00001244 tl_assert(vge.n_used > 0);
1245
1246 if (DEBUG_CG)
sewardj4ba057c2005-10-18 12:04:18 +00001247 VG_(printf)( "discard_basic_block_info: %p, %p, %llu\n",
1248 (void*)(Addr)orig_addr,
sewardj5155dec2005-10-12 10:09:23 +00001249 (void*)(Addr)vge.base[0], (ULong)vge.len[0]);
njn4294fd42002-06-05 14:41:10 +00001250
sewardj4ba057c2005-10-18 12:04:18 +00001251 // Get BB info, remove from table, free BB info. Simple! Note that we
1252 // use orig_addr, not the first instruction address in vge.
1253 bbInfo = VG_(OSet_Remove)(instrInfoTable, &orig_addr);
njn6a3009b2005-03-20 00:20:06 +00001254 tl_assert(NULL != bbInfo);
njnd3bef4f2005-10-15 17:46:18 +00001255 VG_(OSet_FreeNode)(instrInfoTable, bbInfo);
sewardj18d75132002-05-16 11:06:21 +00001256}
1257
1258/*--------------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001259/*--- Command line processing ---*/
1260/*--------------------------------------------------------------------*/
1261
njn0103de52005-10-10 16:49:01 +00001262static void parse_cache_opt ( cache_t* cache, Char* opt )
njn25e49d8e72002-09-23 09:36:25 +00001263{
njn0103de52005-10-10 16:49:01 +00001264 Int i = 0, i2, i3;
njn25e49d8e72002-09-23 09:36:25 +00001265
nethercote9313ac42004-07-06 21:54:20 +00001266 // Option argument looks like "65536,2,64".
1267 // Find commas, replace with NULs to make three independent
1268 // strings, then extract numbers, put NULs back. Yuck.
njn25e49d8e72002-09-23 09:36:25 +00001269 while (VG_(isdigit)(opt[i])) i++;
1270 if (',' == opt[i]) {
1271 opt[i++] = '\0';
1272 i2 = i;
1273 } else goto bad;
1274 while (VG_(isdigit)(opt[i])) i++;
1275 if (',' == opt[i]) {
1276 opt[i++] = '\0';
1277 i3 = i;
1278 } else goto bad;
1279 while (VG_(isdigit)(opt[i])) i++;
1280 if ('\0' != opt[i]) goto bad;
1281
nethercote9313ac42004-07-06 21:54:20 +00001282 cache->size = (Int)VG_(atoll)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001283 cache->assoc = (Int)VG_(atoll)(opt + i2);
1284 cache->line_size = (Int)VG_(atoll)(opt + i3);
1285
nethercote9313ac42004-07-06 21:54:20 +00001286 opt[i2-1] = ',';
1287 opt[i3-1] = ',';
njn25e49d8e72002-09-23 09:36:25 +00001288 return;
1289
1290 bad:
sewardj6893d652006-10-15 01:25:13 +00001291 VG_(err_bad_option)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001292}
1293
njn51d827b2005-05-09 01:02:08 +00001294static Bool cg_process_cmd_line_option(Char* arg)
njn25e49d8e72002-09-23 09:36:25 +00001295{
nethercote9313ac42004-07-06 21:54:20 +00001296 // 5 is length of "--I1="
njn39c86652003-05-21 10:13:39 +00001297 if (VG_CLO_STREQN(5, arg, "--I1="))
nethercote9313ac42004-07-06 21:54:20 +00001298 parse_cache_opt(&clo_I1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001299 else if (VG_CLO_STREQN(5, arg, "--D1="))
nethercote9313ac42004-07-06 21:54:20 +00001300 parse_cache_opt(&clo_D1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001301 else if (VG_CLO_STREQN(5, arg, "--L2="))
nethercote9313ac42004-07-06 21:54:20 +00001302 parse_cache_opt(&clo_L2_cache, &arg[5]);
njn25e49d8e72002-09-23 09:36:25 +00001303 else
1304 return False;
1305
1306 return True;
1307}
1308
njn51d827b2005-05-09 01:02:08 +00001309static void cg_print_usage(void)
njn25e49d8e72002-09-23 09:36:25 +00001310{
njn3e884182003-04-15 13:03:23 +00001311 VG_(printf)(
njn25e49d8e72002-09-23 09:36:25 +00001312" --I1=<size>,<assoc>,<line_size> set I1 cache manually\n"
1313" --D1=<size>,<assoc>,<line_size> set D1 cache manually\n"
njn3e884182003-04-15 13:03:23 +00001314" --L2=<size>,<assoc>,<line_size> set L2 cache manually\n"
1315 );
1316}
1317
njn51d827b2005-05-09 01:02:08 +00001318static void cg_print_debug_usage(void)
njn3e884182003-04-15 13:03:23 +00001319{
1320 VG_(printf)(
1321" (none)\n"
1322 );
njn25e49d8e72002-09-23 09:36:25 +00001323}
1324
1325/*--------------------------------------------------------------------*/
1326/*--- Setup ---*/
1327/*--------------------------------------------------------------------*/
1328
njn51d827b2005-05-09 01:02:08 +00001329static void cg_post_clo_init(void)
njn25e49d8e72002-09-23 09:36:25 +00001330{
1331 cache_t I1c, D1c, L2c;
njn25e49d8e72002-09-23 09:36:25 +00001332
nethercoteb35a8b92004-09-11 16:45:27 +00001333 configure_caches(&I1c, &D1c, &L2c);
njn25e49d8e72002-09-23 09:36:25 +00001334
1335 cachesim_I1_initcache(I1c);
1336 cachesim_D1_initcache(D1c);
1337 cachesim_L2_initcache(L2c);
njn25e49d8e72002-09-23 09:36:25 +00001338}
1339
njn57ca7ab2005-06-21 23:44:58 +00001340static Char base_dir[VKI_PATH_MAX];
1341
njn51d827b2005-05-09 01:02:08 +00001342static void cg_pre_clo_init(void)
1343{
njn51d827b2005-05-09 01:02:08 +00001344 VG_(details_name) ("Cachegrind");
1345 VG_(details_version) (NULL);
1346 VG_(details_description) ("an I1/D1/L2 cache profiler");
1347 VG_(details_copyright_author)(
sewardje4b0bf02006-06-05 23:21:15 +00001348 "Copyright (C) 2002-2006, and GNU GPL'd, by Nicholas Nethercote et al.");
njn51d827b2005-05-09 01:02:08 +00001349 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardje8089302006-10-17 02:15:17 +00001350 VG_(details_avg_translation_sizeB) ( 500 );
njn51d827b2005-05-09 01:02:08 +00001351
1352 VG_(basic_tool_funcs) (cg_post_clo_init,
1353 cg_instrument,
1354 cg_fini);
1355
1356 VG_(needs_basic_block_discards)(cg_discard_basic_block_info);
1357 VG_(needs_command_line_options)(cg_process_cmd_line_option,
1358 cg_print_usage,
1359 cg_print_debug_usage);
1360
1361 /* Get working directory */
njn57ca7ab2005-06-21 23:44:58 +00001362 tl_assert( VG_(getcwd)(base_dir, VKI_PATH_MAX) );
njn51d827b2005-05-09 01:02:08 +00001363
1364 /* Block is big enough for dir name + cachegrind.out.<pid> */
1365 cachegrind_out_file = VG_(malloc)((VG_(strlen)(base_dir) + 32)*sizeof(Char));
1366 VG_(sprintf)(cachegrind_out_file, "%s/cachegrind.out.%d",
1367 base_dir, VG_(getpid)());
njn51d827b2005-05-09 01:02:08 +00001368
njnd3bef4f2005-10-15 17:46:18 +00001369 CC_table = VG_(OSet_Create)(offsetof(LineCC, loc),
1370 cmp_CodeLoc_LineCC,
1371 VG_(malloc), VG_(free));
sewardj4ba057c2005-10-18 12:04:18 +00001372 instrInfoTable = VG_(OSet_Create)(/*keyOff*/0,
njnd3bef4f2005-10-15 17:46:18 +00001373 NULL,
1374 VG_(malloc), VG_(free));
1375 stringTable = VG_(OSet_Create)(/*keyOff*/0,
1376 stringCmp,
1377 VG_(malloc), VG_(free));
njn51d827b2005-05-09 01:02:08 +00001378}
1379
sewardj45f4e7c2005-09-27 19:20:21 +00001380VG_DETERMINE_INTERFACE_VERSION(cg_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00001381
njn25e49d8e72002-09-23 09:36:25 +00001382/*--------------------------------------------------------------------*/
njnf69f9452005-07-03 17:53:11 +00001383/*--- end ---*/
sewardj18d75132002-05-16 11:06:21 +00001384/*--------------------------------------------------------------------*/
njnd3bef4f2005-10-15 17:46:18 +00001385