blob: a9d92a5c12fb16659d75667a1888d254be3d7c31 [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.
sewardj0b9d74a2006-12-24 02:24:11 +0000118// - table(SB_start_addr, list(InstrInfo))
119// - For each SB, each InstrInfo in the list holds info about the
njnd3bef4f2005-10-15 17:46:18 +0000120// 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.
sewardj0b9d74a2006-12-24 02:24:11 +0000122// - When SBs are discarded the relevant list(instr_details) is freed.
nethercote9313ac42004-07-06 21:54:20 +0000123
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
sewardj0b9d74a2006-12-24 02:24:11 +0000131typedef struct _SB_info SB_info;
132struct _SB_info {
133 Addr SB_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. */
sewardj0b9d74a2006-12-24 02:24:11 +0000410 SB_info* sbInfo;
sewardj5155dec2005-10-12 10:09:23 +0000411
njnd3bef4f2005-10-15 17:46:18 +0000412 /* Number InstrInfo bins 'used' so far. */
sewardj0b9d74a2006-12-24 02:24:11 +0000413 Int sbInfo_i;
sewardj5155dec2005-10-12 10:09:23 +0000414
sewardj0b9d74a2006-12-24 02:24:11 +0000415 /* The output SB being constructed. */
416 IRSB* sbOut;
sewardj5155dec2005-10-12 10:09:23 +0000417 }
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
sewardj0b9d74a2006-12-24 02:24:11 +0000428SB_info* get_SB_info(IRSB* sbIn, Addr origAddr)
nethercote9313ac42004-07-06 21:54:20 +0000429{
njn4bd67b52005-08-11 00:47:10 +0000430 Int i, n_instrs;
431 IRStmt* st;
sewardj0b9d74a2006-12-24 02:24:11 +0000432 SB_info* sbInfo;
njnd3bef4f2005-10-15 17:46:18 +0000433
sewardj0b9d74a2006-12-24 02:24:11 +0000434 // Count number of original instrs in SB
njn6a3009b2005-03-20 00:20:06 +0000435 n_instrs = 0;
sewardj0b9d74a2006-12-24 02:24:11 +0000436 for (i = 0; i < sbIn->stmts_used; i++) {
437 st = sbIn->stmts[i];
njn6a3009b2005-03-20 00:20:06 +0000438 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.
sewardj0b9d74a2006-12-24 02:24:11 +0000445 sbInfo = VG_(OSet_Lookup)(instrInfoTable, &origAddr);
446 tl_assert(NULL == sbInfo);
sewardja3a29a52005-10-12 16:16:03 +0000447
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)
sewardj0b9d74a2006-12-24 02:24:11 +0000450 sbInfo = VG_(OSet_AllocNode)(instrInfoTable,
451 sizeof(SB_info) + n_instrs*sizeof(InstrInfo));
452 sbInfo->SB_addr = origAddr;
453 sbInfo->n_instrs = n_instrs;
454 VG_(OSet_Insert)( instrInfoTable, sbInfo );
sewardja3a29a52005-10-12 16:16:03 +0000455 distinct_instrs++;
456
sewardj0b9d74a2006-12-24 02:24:11 +0000457 return sbInfo;
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;
sewardj0b9d74a2006-12-24 02:24:11 +0000493 tl_assert(cgs->sbInfo_i >= 0);
494 tl_assert(cgs->sbInfo_i < cgs->sbInfo->n_instrs);
495 i_node = &cgs->sbInfo->instrs[ cgs->sbInfo_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);
sewardj0b9d74a2006-12-24 02:24:11 +0000499 cgs->sbInfo_i++;
sewardj5155dec2005-10-12 10:09:23 +0000500 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
sewardj0b9d74a2006-12-24 02:24:11 +0000506 'consumes' slots in cgs->sbInfo. */
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 );
sewardj0b9d74a2006-12-24 02:24:11 +0000635 addStmtToIRSB( cgs->sbOut, 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
sewardj0b9d74a2006-12-24 02:24:11 +0000709IRSB* cg_instrument ( VgCallbackClosure* closure,
710 IRSB* sbIn,
sewardj461df9c2006-01-17 02:06:39 +0000711 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;
sewardj0b9d74a2006-12-24 02:24:11 +0000719 IRTypeEnv* tyenv = sbIn->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
sewardj0b9d74a2006-12-24 02:24:11 +0000727 // Set up new SB
728 cgs.sbOut = deepCopyIRSBExceptStmts(sbIn);
njn6a3009b2005-03-20 00:20:06 +0000729
sewardja9f538c2005-10-23 12:06:55 +0000730 // Copy verbatim any IR preamble preceding the first IMark
njn6a3009b2005-03-20 00:20:06 +0000731 i = 0;
sewardj0b9d74a2006-12-24 02:24:11 +0000732 while (i < sbIn->stmts_used && sbIn->stmts[i]->tag != Ist_IMark) {
733 addStmtToIRSB( cgs.sbOut, sbIn->stmts[i] );
sewardja9f538c2005-10-23 12:06:55 +0000734 i++;
735 }
736
737 // Get the first statement, and initial cia from it
sewardj0b9d74a2006-12-24 02:24:11 +0000738 tl_assert(sbIn->stmts_used > 0);
739 tl_assert(i < sbIn->stmts_used);
740 st = sbIn->stmts[i];
njn6a3009b2005-03-20 00:20:06 +0000741 tl_assert(Ist_IMark == st->tag);
sewardj5155dec2005-10-12 10:09:23 +0000742 cia = st->Ist.IMark.addr;
njn6a3009b2005-03-20 00:20:06 +0000743
sewardj5155dec2005-10-12 10:09:23 +0000744 // Set up running state and get block info
sewardj3a384b32006-01-22 01:12:51 +0000745 tl_assert(closure->readdr == vge->base[0]);
sewardj5155dec2005-10-12 10:09:23 +0000746 cgs.events_used = 0;
sewardj0b9d74a2006-12-24 02:24:11 +0000747 cgs.sbInfo = get_SB_info(sbIn, (Addr)closure->readdr);
748 cgs.sbInfo_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.
sewardj0b9d74a2006-12-24 02:24:11 +0000755 for (/*use current i*/; i < sbIn->stmts_used; i++) {
njn6a3009b2005-03-20 00:20:06 +0000756
sewardj0b9d74a2006-12-24 02:24:11 +0000757 st = sbIn->stmts[i];
sewardj5155dec2005-10-12 10:09:23 +0000758 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
sewardj0b9d74a2006-12-24 02:24:11 +0000788 case Ist_WrTmp: {
789 IRExpr* data = st->Ist.WrTmp.data;
sewardj5155dec2005-10-12 10:09:23 +0000790 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 */
sewardj0b9d74a2006-12-24 02:24:11 +0000845 addStmtToIRSB( cgs.sbOut, 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 ... */
sewardj0b9d74a2006-12-24 02:24:11 +0000857 tl_assert(cgs.sbInfo_i == cgs.sbInfo->n_instrs);
sewardj5155dec2005-10-12 10:09:23 +0000858
859 if (DEBUG_CG) {
860 VG_(printf)( "goto {");
sewardj0b9d74a2006-12-24 02:24:11 +0000861 ppIRJumpKind(sbIn->jumpkind);
sewardj5155dec2005-10-12 10:09:23 +0000862 VG_(printf)( "} ");
sewardj0b9d74a2006-12-24 02:24:11 +0000863 ppIRExpr( sbIn->next );
sewardj5155dec2005-10-12 10:09:23 +0000864 VG_(printf)( "}\n");
865 }
866
sewardj0b9d74a2006-12-24 02:24:11 +0000867 return cgs.sbOut;
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 {
sewardje8089302006-10-17 02:15:17 +00001001 fd = sres.res;
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{
njn1baf7db2006-04-18 22:34:48 +00001105 static Char buf1[128], buf2[128], buf3[128], buf4[123], 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) {
njn1baf7db2006-04-18 22:34:48 +00001195 Int debug_lookups = full_debugs + fn_debugs +
1196 file_line_debugs + no_debugs;
njnd3bef4f2005-10-15 17:46:18 +00001197
njn1baf7db2006-04-18 22:34:48 +00001198 VG_(message)(Vg_DebugMsg, "");
1199 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
1205 VG_(percentify)(full_debugs, debug_lookups, 1, 6, buf1);
1206 VG_(percentify)(file_line_debugs, debug_lookups, 1, 6, buf2);
1207 VG_(percentify)(fn_debugs, debug_lookups, 1, 6, buf3);
1208 VG_(percentify)(no_debugs, debug_lookups, 1, 6, buf4);
1209 VG_(message)(Vg_DebugMsg, "cachegrind: with full info:%s (%d)",
1210 buf1, full_debugs);
1211 VG_(message)(Vg_DebugMsg, "cachegrind: with file/line info:%s (%d)",
1212 buf2, file_line_debugs);
1213 VG_(message)(Vg_DebugMsg, "cachegrind: with fn name info:%s (%d)",
1214 buf3, fn_debugs);
1215 VG_(message)(Vg_DebugMsg, "cachegrind: with zero info:%s (%d)",
1216 buf4, no_debugs);
1217
1218 VG_(message)(Vg_DebugMsg, "cachegrind: string table size: %u",
1219 VG_(OSet_Size)(stringTable));
1220 VG_(message)(Vg_DebugMsg, "cachegrind: CC table size: %u",
1221 VG_(OSet_Size)(CC_table));
1222 VG_(message)(Vg_DebugMsg, "cachegrind: InstrInfo table size: %u",
1223 VG_(OSet_Size)(instrInfoTable));
njn4f9c9342002-04-29 16:03:24 +00001224 }
njn4f9c9342002-04-29 16:03:24 +00001225}
1226
nethercote9313ac42004-07-06 21:54:20 +00001227/*--------------------------------------------------------------------*/
1228/*--- Discarding BB info ---*/
1229/*--------------------------------------------------------------------*/
sewardj18d75132002-05-16 11:06:21 +00001230
sewardja3a29a52005-10-12 16:16:03 +00001231// Called when a translation is removed from the translation cache for
1232// any reason at all: to free up space, because the guest code was
1233// unmapped or modified, or for any arbitrary reason.
sewardj4ba057c2005-10-18 12:04:18 +00001234static
sewardj0b9d74a2006-12-24 02:24:11 +00001235void cg_discard_superblock_info ( Addr64 orig_addr64, VexGuestExtents vge )
sewardj18d75132002-05-16 11:06:21 +00001236{
sewardj0b9d74a2006-12-24 02:24:11 +00001237 SB_info* sbInfo;
sewardj3a384b32006-01-22 01:12:51 +00001238 Addr orig_addr = (Addr)vge.base[0];
njn4294fd42002-06-05 14:41:10 +00001239
sewardj5155dec2005-10-12 10:09:23 +00001240 tl_assert(vge.n_used > 0);
1241
1242 if (DEBUG_CG)
sewardj4ba057c2005-10-18 12:04:18 +00001243 VG_(printf)( "discard_basic_block_info: %p, %p, %llu\n",
1244 (void*)(Addr)orig_addr,
sewardj5155dec2005-10-12 10:09:23 +00001245 (void*)(Addr)vge.base[0], (ULong)vge.len[0]);
njn4294fd42002-06-05 14:41:10 +00001246
sewardj4ba057c2005-10-18 12:04:18 +00001247 // Get BB info, remove from table, free BB info. Simple! Note that we
1248 // use orig_addr, not the first instruction address in vge.
sewardj0b9d74a2006-12-24 02:24:11 +00001249 sbInfo = VG_(OSet_Remove)(instrInfoTable, &orig_addr);
1250 tl_assert(NULL != sbInfo);
1251 VG_(OSet_FreeNode)(instrInfoTable, sbInfo);
sewardj18d75132002-05-16 11:06:21 +00001252}
1253
1254/*--------------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001255/*--- Command line processing ---*/
1256/*--------------------------------------------------------------------*/
1257
njn0103de52005-10-10 16:49:01 +00001258static void parse_cache_opt ( cache_t* cache, Char* opt )
njn25e49d8e72002-09-23 09:36:25 +00001259{
njn0103de52005-10-10 16:49:01 +00001260 Int i = 0, i2, i3;
njn25e49d8e72002-09-23 09:36:25 +00001261
nethercote9313ac42004-07-06 21:54:20 +00001262 // Option argument looks like "65536,2,64".
1263 // Find commas, replace with NULs to make three independent
1264 // strings, then extract numbers, put NULs back. Yuck.
njn25e49d8e72002-09-23 09:36:25 +00001265 while (VG_(isdigit)(opt[i])) i++;
1266 if (',' == opt[i]) {
1267 opt[i++] = '\0';
1268 i2 = i;
1269 } else goto bad;
1270 while (VG_(isdigit)(opt[i])) i++;
1271 if (',' == opt[i]) {
1272 opt[i++] = '\0';
1273 i3 = i;
1274 } else goto bad;
1275 while (VG_(isdigit)(opt[i])) i++;
1276 if ('\0' != opt[i]) goto bad;
1277
nethercote9313ac42004-07-06 21:54:20 +00001278 cache->size = (Int)VG_(atoll)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001279 cache->assoc = (Int)VG_(atoll)(opt + i2);
1280 cache->line_size = (Int)VG_(atoll)(opt + i3);
1281
nethercote9313ac42004-07-06 21:54:20 +00001282 opt[i2-1] = ',';
1283 opt[i3-1] = ',';
njn25e49d8e72002-09-23 09:36:25 +00001284 return;
1285
1286 bad:
sewardj6893d652006-10-15 01:25:13 +00001287 VG_(err_bad_option)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001288}
1289
njn51d827b2005-05-09 01:02:08 +00001290static Bool cg_process_cmd_line_option(Char* arg)
njn25e49d8e72002-09-23 09:36:25 +00001291{
nethercote9313ac42004-07-06 21:54:20 +00001292 // 5 is length of "--I1="
njn39c86652003-05-21 10:13:39 +00001293 if (VG_CLO_STREQN(5, arg, "--I1="))
nethercote9313ac42004-07-06 21:54:20 +00001294 parse_cache_opt(&clo_I1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001295 else if (VG_CLO_STREQN(5, arg, "--D1="))
nethercote9313ac42004-07-06 21:54:20 +00001296 parse_cache_opt(&clo_D1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001297 else if (VG_CLO_STREQN(5, arg, "--L2="))
nethercote9313ac42004-07-06 21:54:20 +00001298 parse_cache_opt(&clo_L2_cache, &arg[5]);
njn25e49d8e72002-09-23 09:36:25 +00001299 else
1300 return False;
1301
1302 return True;
1303}
1304
njn51d827b2005-05-09 01:02:08 +00001305static void cg_print_usage(void)
njn25e49d8e72002-09-23 09:36:25 +00001306{
njn3e884182003-04-15 13:03:23 +00001307 VG_(printf)(
njn25e49d8e72002-09-23 09:36:25 +00001308" --I1=<size>,<assoc>,<line_size> set I1 cache manually\n"
1309" --D1=<size>,<assoc>,<line_size> set D1 cache manually\n"
njn3e884182003-04-15 13:03:23 +00001310" --L2=<size>,<assoc>,<line_size> set L2 cache manually\n"
1311 );
1312}
1313
njn51d827b2005-05-09 01:02:08 +00001314static void cg_print_debug_usage(void)
njn3e884182003-04-15 13:03:23 +00001315{
1316 VG_(printf)(
1317" (none)\n"
1318 );
njn25e49d8e72002-09-23 09:36:25 +00001319}
1320
1321/*--------------------------------------------------------------------*/
1322/*--- Setup ---*/
1323/*--------------------------------------------------------------------*/
1324
njn51d827b2005-05-09 01:02:08 +00001325static void cg_post_clo_init(void)
njn25e49d8e72002-09-23 09:36:25 +00001326{
1327 cache_t I1c, D1c, L2c;
njn25e49d8e72002-09-23 09:36:25 +00001328
nethercoteb35a8b92004-09-11 16:45:27 +00001329 configure_caches(&I1c, &D1c, &L2c);
njn25e49d8e72002-09-23 09:36:25 +00001330
1331 cachesim_I1_initcache(I1c);
1332 cachesim_D1_initcache(D1c);
1333 cachesim_L2_initcache(L2c);
njn25e49d8e72002-09-23 09:36:25 +00001334}
1335
njn57ca7ab2005-06-21 23:44:58 +00001336static Char base_dir[VKI_PATH_MAX];
1337
njn51d827b2005-05-09 01:02:08 +00001338static void cg_pre_clo_init(void)
1339{
njn51d827b2005-05-09 01:02:08 +00001340 VG_(details_name) ("Cachegrind");
1341 VG_(details_version) (NULL);
1342 VG_(details_description) ("an I1/D1/L2 cache profiler");
1343 VG_(details_copyright_author)(
sewardje4b0bf02006-06-05 23:21:15 +00001344 "Copyright (C) 2002-2006, and GNU GPL'd, by Nicholas Nethercote et al.");
njn51d827b2005-05-09 01:02:08 +00001345 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardje8089302006-10-17 02:15:17 +00001346 VG_(details_avg_translation_sizeB) ( 500 );
njn51d827b2005-05-09 01:02:08 +00001347
1348 VG_(basic_tool_funcs) (cg_post_clo_init,
1349 cg_instrument,
1350 cg_fini);
1351
sewardj0b9d74a2006-12-24 02:24:11 +00001352 VG_(needs_superblock_discards)(cg_discard_superblock_info);
njn51d827b2005-05-09 01:02:08 +00001353 VG_(needs_command_line_options)(cg_process_cmd_line_option,
1354 cg_print_usage,
1355 cg_print_debug_usage);
1356
1357 /* Get working directory */
njn57ca7ab2005-06-21 23:44:58 +00001358 tl_assert( VG_(getcwd)(base_dir, VKI_PATH_MAX) );
njn51d827b2005-05-09 01:02:08 +00001359
1360 /* Block is big enough for dir name + cachegrind.out.<pid> */
1361 cachegrind_out_file = VG_(malloc)((VG_(strlen)(base_dir) + 32)*sizeof(Char));
1362 VG_(sprintf)(cachegrind_out_file, "%s/cachegrind.out.%d",
1363 base_dir, VG_(getpid)());
njn51d827b2005-05-09 01:02:08 +00001364
njnd3bef4f2005-10-15 17:46:18 +00001365 CC_table = VG_(OSet_Create)(offsetof(LineCC, loc),
1366 cmp_CodeLoc_LineCC,
1367 VG_(malloc), VG_(free));
sewardj4ba057c2005-10-18 12:04:18 +00001368 instrInfoTable = VG_(OSet_Create)(/*keyOff*/0,
njnd3bef4f2005-10-15 17:46:18 +00001369 NULL,
1370 VG_(malloc), VG_(free));
1371 stringTable = VG_(OSet_Create)(/*keyOff*/0,
1372 stringCmp,
1373 VG_(malloc), VG_(free));
njn51d827b2005-05-09 01:02:08 +00001374}
1375
sewardj45f4e7c2005-09-27 19:20:21 +00001376VG_DETERMINE_INTERFACE_VERSION(cg_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00001377
njn25e49d8e72002-09-23 09:36:25 +00001378/*--------------------------------------------------------------------*/
njnf69f9452005-07-03 17:53:11 +00001379/*--- end ---*/
sewardj18d75132002-05-16 11:06:21 +00001380/*--------------------------------------------------------------------*/
njnd3bef4f2005-10-15 17:46:18 +00001381