blob: 5f713e055439265e3ada3508176c0f922c06eacd [file] [log] [blame]
sewardj07133bf2002-06-13 10:25:56 +00001
njn4f9c9342002-04-29 16:03:24 +00002/*--------------------------------------------------------------------*/
njn101e5722005-04-21 02:37:54 +00003/*--- Cachegrind: everything but the simulation itself. ---*/
njn25cac76cb2002-09-23 11:21:57 +00004/*--- cg_main.c ---*/
njn4f9c9342002-04-29 16:03:24 +00005/*--------------------------------------------------------------------*/
6
7/*
nethercote137bc552003-11-14 17:47:54 +00008 This file is part of Cachegrind, a Valgrind tool for cache
njnc9539842002-10-02 13:26:35 +00009 profiling programs.
njn4f9c9342002-04-29 16:03:24 +000010
sewardj9ebd6e02007-01-08 06:01:59 +000011 Copyright (C) 2002-2007 Nicholas Nethercote
njn2bc10122005-05-08 02:10:27 +000012 njn@valgrind.org
njn4f9c9342002-04-29 16:03:24 +000013
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
njn25e49d8e72002-09-23 09:36:25 +000029 The GNU General Public License is contained in the file COPYING.
njn4f9c9342002-04-29 16:03:24 +000030*/
31
njnc7561b92005-06-19 01:24:32 +000032#include "pub_tool_basics.h"
sewardj4cfea4f2006-10-14 19:26:10 +000033#include "pub_tool_vki.h"
njnea27e462005-05-31 02:38:09 +000034#include "pub_tool_debuginfo.h"
njn97405b22005-06-02 03:39:33 +000035#include "pub_tool_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000036#include "pub_tool_libcassert.h"
njneb8896b2005-06-04 20:03:55 +000037#include "pub_tool_libcfile.h"
njn36a20fa2005-06-03 03:08:39 +000038#include "pub_tool_libcprint.h"
njnf39e9a32005-06-12 02:43:17 +000039#include "pub_tool_libcproc.h"
njnf536bbb2005-06-13 04:21:38 +000040#include "pub_tool_machine.h"
njn717cde52005-05-10 02:47:21 +000041#include "pub_tool_mallocfree.h"
njn20242342005-05-16 23:31:24 +000042#include "pub_tool_options.h"
njnd3bef4f2005-10-15 17:46:18 +000043#include "pub_tool_oset.h"
njn43b9a8a2005-05-10 04:37:01 +000044#include "pub_tool_tooliface.h"
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
sewardje1216cb2007-02-07 19:55:30 +0000980// The output file base name specified by the user using the
981// --cachegrind-out-file switch. This is combined with the
982// process ID and optional user-supplied qualifier (from
983// --log-file-qualifier) to produce the name stored in
984// cachegrind_out_file.
985static Char* cachegrind_out_file_basename = "cachegrind.out";
986
987// The final, completed name for the output file.
988static Char* cachegrind_out_file = NULL;
989
nethercote9313ac42004-07-06 21:54:20 +0000990
nethercote9313ac42004-07-06 21:54:20 +0000991static void fprint_CC_table_and_calc_totals(void)
992{
njnd3bef4f2005-10-15 17:46:18 +0000993 Int i, fd;
sewardj92645592005-07-23 09:18:34 +0000994 SysRes sres;
njnd3bef4f2005-10-15 17:46:18 +0000995 Char buf[512], *currFile = NULL, *currFn = NULL;
996 LineCC* lineCC;
njn4f9c9342002-04-29 16:03:24 +0000997
sewardj92645592005-07-23 09:18:34 +0000998 sres = VG_(open)(cachegrind_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
999 VKI_S_IRUSR|VKI_S_IWUSR);
1000 if (sres.isError) {
nethercote9313ac42004-07-06 21:54:20 +00001001 // If the file can't be opened for whatever reason (conflict
1002 // between multiple cachegrinded processes?), give up now.
njnee0e6a32005-04-24 00:21:01 +00001003 VG_(message)(Vg_UserMsg,
njn02bc4b82005-05-15 17:28:26 +00001004 "error: can't open cache simulation output file '%s'",
njnee0e6a32005-04-24 00:21:01 +00001005 cachegrind_out_file );
1006 VG_(message)(Vg_UserMsg,
1007 " ... so simulation results will be missing.");
sewardj0744b6c2002-12-11 00:45:42 +00001008 return;
sewardj92645592005-07-23 09:18:34 +00001009 } else {
sewardje8089302006-10-17 02:15:17 +00001010 fd = sres.res;
sewardj0744b6c2002-12-11 00:45:42 +00001011 }
njn4f9c9342002-04-29 16:03:24 +00001012
nethercote9313ac42004-07-06 21:54:20 +00001013 // "desc:" lines (giving I1/D1/L2 cache configuration). The spaces after
1014 // the 2nd colon makes cg_annotate's output look nicer.
1015 VG_(sprintf)(buf, "desc: I1 cache: %s\n"
1016 "desc: D1 cache: %s\n"
1017 "desc: L2 cache: %s\n",
1018 I1.desc_line, D1.desc_line, L2.desc_line);
njn7cf0bd32002-06-08 13:36:03 +00001019 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njn4f9c9342002-04-29 16:03:24 +00001020
nethercote9313ac42004-07-06 21:54:20 +00001021 // "cmd:" line
njn4f9c9342002-04-29 16:03:24 +00001022 VG_(strcpy)(buf, "cmd:");
1023 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
sewardj45f4e7c2005-09-27 19:20:21 +00001024 if (VG_(args_the_exename)) {
1025 VG_(write)(fd, " ", 1);
1026 VG_(write)(fd, VG_(args_the_exename),
1027 VG_(strlen)( VG_(args_the_exename) ));
1028 }
1029 for (i = 0; i < VG_(args_for_client).used; i++) {
1030 if (VG_(args_for_client).strs[i]) {
1031 VG_(write)(fd, " ", 1);
1032 VG_(write)(fd, VG_(args_for_client).strs[i],
1033 VG_(strlen)(VG_(args_for_client).strs[i]));
1034 }
njn4f9c9342002-04-29 16:03:24 +00001035 }
nethercote9313ac42004-07-06 21:54:20 +00001036 // "events:" line
njn4f9c9342002-04-29 16:03:24 +00001037 VG_(sprintf)(buf, "\nevents: Ir I1mr I2mr Dr D1mr D2mr Dw D1mw D2mw\n");
1038 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1039
njnd3bef4f2005-10-15 17:46:18 +00001040 // Traverse every lineCC
1041 VG_(OSet_ResetIter)(CC_table);
1042 while ( (lineCC = VG_(OSet_Next)(CC_table)) ) {
njn4311fe62005-12-08 23:18:50 +00001043 Bool just_hit_a_new_file = False;
njnd3bef4f2005-10-15 17:46:18 +00001044 // If we've hit a new file, print a "fl=" line. Note that because
1045 // each string is stored exactly once in the string table, we can use
1046 // pointer comparison rather than strcmp() to test for equality, which
1047 // is good because most of the time the comparisons are equal and so
njn4311fe62005-12-08 23:18:50 +00001048 // the whole strings would have to be checked.
njnd3bef4f2005-10-15 17:46:18 +00001049 if ( lineCC->loc.file != currFile ) {
1050 currFile = lineCC->loc.file;
1051 VG_(sprintf)(buf, "fl=%s\n", currFile);
njn4f9c9342002-04-29 16:03:24 +00001052 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njnd3bef4f2005-10-15 17:46:18 +00001053 distinct_files++;
njn4311fe62005-12-08 23:18:50 +00001054 just_hit_a_new_file = True;
njn4f9c9342002-04-29 16:03:24 +00001055 }
njn4311fe62005-12-08 23:18:50 +00001056 // If we've hit a new function, print a "fn=" line. We know to do
1057 // this when the function name changes, and also every time we hit a
1058 // new file (in which case the new function name might be the same as
1059 // in the old file, hence the just_hit_a_new_file test).
1060 if ( just_hit_a_new_file || lineCC->loc.fn != currFn ) {
njnd3bef4f2005-10-15 17:46:18 +00001061 currFn = lineCC->loc.fn;
1062 VG_(sprintf)(buf, "fn=%s\n", currFn);
1063 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1064 distinct_fns++;
njn4311fe62005-12-08 23:18:50 +00001065 just_hit_a_new_file = False;
njnd3bef4f2005-10-15 17:46:18 +00001066 }
1067
1068 // Print the LineCC
1069 VG_(sprintf)(buf, "%u %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
1070 lineCC->loc.line,
1071 lineCC->Ir.a, lineCC->Ir.m1, lineCC->Ir.m2,
1072 lineCC->Dr.a, lineCC->Dr.m1, lineCC->Dr.m2,
1073 lineCC->Dw.a, lineCC->Dw.m1, lineCC->Dw.m2);
1074 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1075
1076 // Update summary stats
1077 Ir_total.a += lineCC->Ir.a;
1078 Ir_total.m1 += lineCC->Ir.m1;
1079 Ir_total.m2 += lineCC->Ir.m2;
1080 Dr_total.a += lineCC->Dr.a;
1081 Dr_total.m1 += lineCC->Dr.m1;
1082 Dr_total.m2 += lineCC->Dr.m2;
1083 Dw_total.a += lineCC->Dw.a;
1084 Dw_total.m1 += lineCC->Dw.m1;
1085 Dw_total.m2 += lineCC->Dw.m2;
1086
1087 distinct_lines++;
njn4f9c9342002-04-29 16:03:24 +00001088 }
1089
nethercote9313ac42004-07-06 21:54:20 +00001090 // Summary stats must come after rest of table, since we calculate them
1091 // during traversal. */
njn4f9c9342002-04-29 16:03:24 +00001092 VG_(sprintf)(buf, "summary: "
nethercote9313ac42004-07-06 21:54:20 +00001093 "%llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
njn4f9c9342002-04-29 16:03:24 +00001094 Ir_total.a, Ir_total.m1, Ir_total.m2,
1095 Dr_total.a, Dr_total.m1, Dr_total.m2,
1096 Dw_total.a, Dw_total.m1, Dw_total.m2);
1097 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1098 VG_(close)(fd);
1099}
1100
njn607adfc2003-09-30 14:15:44 +00001101static UInt ULong_width(ULong n)
njn4f9c9342002-04-29 16:03:24 +00001102{
njn607adfc2003-09-30 14:15:44 +00001103 UInt w = 0;
1104 while (n > 0) {
1105 n = n / 10;
1106 w++;
njn4f9c9342002-04-29 16:03:24 +00001107 }
sewardj46c59b12005-11-01 02:20:19 +00001108 if (w == 0) w = 1;
njn607adfc2003-09-30 14:15:44 +00001109 return w + (w-1)/3; // add space for commas
njn4f9c9342002-04-29 16:03:24 +00001110}
1111
njn51d827b2005-05-09 01:02:08 +00001112static void cg_fini(Int exitcode)
njn4f9c9342002-04-29 16:03:24 +00001113{
njn1baf7db2006-04-18 22:34:48 +00001114 static Char buf1[128], buf2[128], buf3[128], buf4[123], fmt[128];
njn607adfc2003-09-30 14:15:44 +00001115
njn4f9c9342002-04-29 16:03:24 +00001116 CC D_total;
njn1d021fa2002-05-02 13:56:34 +00001117 ULong L2_total_m, L2_total_mr, L2_total_mw,
1118 L2_total, L2_total_r, L2_total_w;
njn4f9c9342002-04-29 16:03:24 +00001119 Int l1, l2, l3;
1120 Int p;
1121
nethercote9313ac42004-07-06 21:54:20 +00001122 fprint_CC_table_and_calc_totals();
njn4f9c9342002-04-29 16:03:24 +00001123
njn7cf0bd32002-06-08 13:36:03 +00001124 if (VG_(clo_verbosity) == 0)
1125 return;
1126
njn4f9c9342002-04-29 16:03:24 +00001127 /* I cache results. Use the I_refs value to determine the first column
1128 * width. */
njn607adfc2003-09-30 14:15:44 +00001129 l1 = ULong_width(Ir_total.a);
1130 l2 = ULong_width(Dr_total.a);
1131 l3 = ULong_width(Dw_total.a);
njn4f9c9342002-04-29 16:03:24 +00001132
njn607adfc2003-09-30 14:15:44 +00001133 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001134 VG_(sprintf)(fmt, "%%s %%,%dllu", l1);
njnd3bef4f2005-10-15 17:46:18 +00001135
njn607adfc2003-09-30 14:15:44 +00001136 VG_(message)(Vg_UserMsg, fmt, "I refs: ", Ir_total.a);
1137 VG_(message)(Vg_UserMsg, fmt, "I1 misses: ", Ir_total.m1);
1138 VG_(message)(Vg_UserMsg, fmt, "L2i misses: ", Ir_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001139
1140 p = 100;
1141
njn25e49d8e72002-09-23 09:36:25 +00001142 if (0 == Ir_total.a) Ir_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001143 VG_(percentify)(Ir_total.m1, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001144 VG_(message)(Vg_UserMsg, "I1 miss rate: %s", buf1);
njnd3bef4f2005-10-15 17:46:18 +00001145
njn856c54e2005-06-26 18:43:40 +00001146 VG_(percentify)(Ir_total.m2, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001147 VG_(message)(Vg_UserMsg, "L2i miss rate: %s", buf1);
1148 VG_(message)(Vg_UserMsg, "");
1149
1150 /* D cache results. Use the D_refs.rd and D_refs.wr values to determine the
1151 * width of columns 2 & 3. */
1152 D_total.a = Dr_total.a + Dw_total.a;
1153 D_total.m1 = Dr_total.m1 + Dw_total.m1;
1154 D_total.m2 = Dr_total.m2 + Dw_total.m2;
njnd3bef4f2005-10-15 17:46:18 +00001155
njn607adfc2003-09-30 14:15:44 +00001156 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001157 VG_(sprintf)(fmt, "%%s %%,%dllu (%%,%dllu rd + %%,%dllu wr)", l1, l2, l3);
njn4f9c9342002-04-29 16:03:24 +00001158
njn607adfc2003-09-30 14:15:44 +00001159 VG_(message)(Vg_UserMsg, fmt, "D refs: ",
1160 D_total.a, Dr_total.a, Dw_total.a);
1161 VG_(message)(Vg_UserMsg, fmt, "D1 misses: ",
1162 D_total.m1, Dr_total.m1, Dw_total.m1);
1163 VG_(message)(Vg_UserMsg, fmt, "L2d misses: ",
1164 D_total.m2, Dr_total.m2, Dw_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001165
1166 p = 10;
njnd3bef4f2005-10-15 17:46:18 +00001167
njn25e49d8e72002-09-23 09:36:25 +00001168 if (0 == D_total.a) D_total.a = 1;
1169 if (0 == Dr_total.a) Dr_total.a = 1;
1170 if (0 == Dw_total.a) Dw_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001171 VG_(percentify)( D_total.m1, D_total.a, 1, l1+1, buf1);
1172 VG_(percentify)(Dr_total.m1, Dr_total.a, 1, l2+1, buf2);
1173 VG_(percentify)(Dw_total.m1, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001174 VG_(message)(Vg_UserMsg, "D1 miss rate: %s (%s + %s )", buf1, buf2,buf3);
1175
njn856c54e2005-06-26 18:43:40 +00001176 VG_(percentify)( D_total.m2, D_total.a, 1, l1+1, buf1);
1177 VG_(percentify)(Dr_total.m2, Dr_total.a, 1, l2+1, buf2);
1178 VG_(percentify)(Dw_total.m2, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001179 VG_(message)(Vg_UserMsg, "L2d miss rate: %s (%s + %s )", buf1, buf2,buf3);
1180 VG_(message)(Vg_UserMsg, "");
1181
1182 /* L2 overall results */
njn1d021fa2002-05-02 13:56:34 +00001183
1184 L2_total = Dr_total.m1 + Dw_total.m1 + Ir_total.m1;
1185 L2_total_r = Dr_total.m1 + Ir_total.m1;
1186 L2_total_w = Dw_total.m1;
njn607adfc2003-09-30 14:15:44 +00001187 VG_(message)(Vg_UserMsg, fmt, "L2 refs: ",
1188 L2_total, L2_total_r, L2_total_w);
njn1d021fa2002-05-02 13:56:34 +00001189
njn4f9c9342002-04-29 16:03:24 +00001190 L2_total_m = Dr_total.m2 + Dw_total.m2 + Ir_total.m2;
1191 L2_total_mr = Dr_total.m2 + Ir_total.m2;
1192 L2_total_mw = Dw_total.m2;
njn607adfc2003-09-30 14:15:44 +00001193 VG_(message)(Vg_UserMsg, fmt, "L2 misses: ",
1194 L2_total_m, L2_total_mr, L2_total_mw);
njn4f9c9342002-04-29 16:03:24 +00001195
njn856c54e2005-06-26 18:43:40 +00001196 VG_(percentify)(L2_total_m, (Ir_total.a + D_total.a), 1, l1+1, buf1);
1197 VG_(percentify)(L2_total_mr, (Ir_total.a + Dr_total.a), 1, l2+1, buf2);
1198 VG_(percentify)(L2_total_mw, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001199 VG_(message)(Vg_UserMsg, "L2 miss rate: %s (%s + %s )", buf1, buf2,buf3);
njnd3bef4f2005-10-15 17:46:18 +00001200
njn4f9c9342002-04-29 16:03:24 +00001201
nethercote9313ac42004-07-06 21:54:20 +00001202 // Various stats
njn4f9c9342002-04-29 16:03:24 +00001203 if (VG_(clo_verbosity) > 1) {
njn1baf7db2006-04-18 22:34:48 +00001204 Int debug_lookups = full_debugs + fn_debugs +
1205 file_line_debugs + no_debugs;
njnd3bef4f2005-10-15 17:46:18 +00001206
njn1baf7db2006-04-18 22:34:48 +00001207 VG_(message)(Vg_DebugMsg, "");
1208 VG_(message)(Vg_DebugMsg, "cachegrind: distinct files: %d", distinct_files);
1209 VG_(message)(Vg_DebugMsg, "cachegrind: distinct fns: %d", distinct_fns);
1210 VG_(message)(Vg_DebugMsg, "cachegrind: distinct lines: %d", distinct_lines);
1211 VG_(message)(Vg_DebugMsg, "cachegrind: distinct instrs:%d", distinct_instrs);
1212 VG_(message)(Vg_DebugMsg, "cachegrind: debug lookups : %d", debug_lookups);
1213
1214 VG_(percentify)(full_debugs, debug_lookups, 1, 6, buf1);
1215 VG_(percentify)(file_line_debugs, debug_lookups, 1, 6, buf2);
1216 VG_(percentify)(fn_debugs, debug_lookups, 1, 6, buf3);
1217 VG_(percentify)(no_debugs, debug_lookups, 1, 6, buf4);
1218 VG_(message)(Vg_DebugMsg, "cachegrind: with full info:%s (%d)",
1219 buf1, full_debugs);
1220 VG_(message)(Vg_DebugMsg, "cachegrind: with file/line info:%s (%d)",
1221 buf2, file_line_debugs);
1222 VG_(message)(Vg_DebugMsg, "cachegrind: with fn name info:%s (%d)",
1223 buf3, fn_debugs);
1224 VG_(message)(Vg_DebugMsg, "cachegrind: with zero info:%s (%d)",
1225 buf4, no_debugs);
1226
1227 VG_(message)(Vg_DebugMsg, "cachegrind: string table size: %u",
1228 VG_(OSet_Size)(stringTable));
1229 VG_(message)(Vg_DebugMsg, "cachegrind: CC table size: %u",
1230 VG_(OSet_Size)(CC_table));
1231 VG_(message)(Vg_DebugMsg, "cachegrind: InstrInfo table size: %u",
1232 VG_(OSet_Size)(instrInfoTable));
njn4f9c9342002-04-29 16:03:24 +00001233 }
njn4f9c9342002-04-29 16:03:24 +00001234}
1235
nethercote9313ac42004-07-06 21:54:20 +00001236/*--------------------------------------------------------------------*/
1237/*--- Discarding BB info ---*/
1238/*--------------------------------------------------------------------*/
sewardj18d75132002-05-16 11:06:21 +00001239
sewardja3a29a52005-10-12 16:16:03 +00001240// Called when a translation is removed from the translation cache for
1241// any reason at all: to free up space, because the guest code was
1242// unmapped or modified, or for any arbitrary reason.
sewardj4ba057c2005-10-18 12:04:18 +00001243static
sewardj0b9d74a2006-12-24 02:24:11 +00001244void cg_discard_superblock_info ( Addr64 orig_addr64, VexGuestExtents vge )
sewardj18d75132002-05-16 11:06:21 +00001245{
sewardj0b9d74a2006-12-24 02:24:11 +00001246 SB_info* sbInfo;
sewardj3a384b32006-01-22 01:12:51 +00001247 Addr orig_addr = (Addr)vge.base[0];
njn4294fd42002-06-05 14:41:10 +00001248
sewardj5155dec2005-10-12 10:09:23 +00001249 tl_assert(vge.n_used > 0);
1250
1251 if (DEBUG_CG)
sewardj4ba057c2005-10-18 12:04:18 +00001252 VG_(printf)( "discard_basic_block_info: %p, %p, %llu\n",
1253 (void*)(Addr)orig_addr,
sewardj5155dec2005-10-12 10:09:23 +00001254 (void*)(Addr)vge.base[0], (ULong)vge.len[0]);
njn4294fd42002-06-05 14:41:10 +00001255
sewardj4ba057c2005-10-18 12:04:18 +00001256 // Get BB info, remove from table, free BB info. Simple! Note that we
1257 // use orig_addr, not the first instruction address in vge.
sewardj0b9d74a2006-12-24 02:24:11 +00001258 sbInfo = VG_(OSet_Remove)(instrInfoTable, &orig_addr);
1259 tl_assert(NULL != sbInfo);
1260 VG_(OSet_FreeNode)(instrInfoTable, sbInfo);
sewardj18d75132002-05-16 11:06:21 +00001261}
1262
1263/*--------------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001264/*--- Command line processing ---*/
1265/*--------------------------------------------------------------------*/
1266
njn0103de52005-10-10 16:49:01 +00001267static void parse_cache_opt ( cache_t* cache, Char* opt )
njn25e49d8e72002-09-23 09:36:25 +00001268{
njn0103de52005-10-10 16:49:01 +00001269 Int i = 0, i2, i3;
njn25e49d8e72002-09-23 09:36:25 +00001270
nethercote9313ac42004-07-06 21:54:20 +00001271 // Option argument looks like "65536,2,64".
1272 // Find commas, replace with NULs to make three independent
1273 // strings, then extract numbers, put NULs back. Yuck.
njn25e49d8e72002-09-23 09:36:25 +00001274 while (VG_(isdigit)(opt[i])) i++;
1275 if (',' == opt[i]) {
1276 opt[i++] = '\0';
1277 i2 = i;
1278 } else goto bad;
1279 while (VG_(isdigit)(opt[i])) i++;
1280 if (',' == opt[i]) {
1281 opt[i++] = '\0';
1282 i3 = i;
1283 } else goto bad;
1284 while (VG_(isdigit)(opt[i])) i++;
1285 if ('\0' != opt[i]) goto bad;
1286
nethercote9313ac42004-07-06 21:54:20 +00001287 cache->size = (Int)VG_(atoll)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001288 cache->assoc = (Int)VG_(atoll)(opt + i2);
1289 cache->line_size = (Int)VG_(atoll)(opt + i3);
1290
nethercote9313ac42004-07-06 21:54:20 +00001291 opt[i2-1] = ',';
1292 opt[i3-1] = ',';
njn25e49d8e72002-09-23 09:36:25 +00001293 return;
1294
1295 bad:
sewardj6893d652006-10-15 01:25:13 +00001296 VG_(err_bad_option)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001297}
1298
njn51d827b2005-05-09 01:02:08 +00001299static Bool cg_process_cmd_line_option(Char* arg)
njn25e49d8e72002-09-23 09:36:25 +00001300{
nethercote9313ac42004-07-06 21:54:20 +00001301 // 5 is length of "--I1="
njn39c86652003-05-21 10:13:39 +00001302 if (VG_CLO_STREQN(5, arg, "--I1="))
nethercote9313ac42004-07-06 21:54:20 +00001303 parse_cache_opt(&clo_I1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001304 else if (VG_CLO_STREQN(5, arg, "--D1="))
nethercote9313ac42004-07-06 21:54:20 +00001305 parse_cache_opt(&clo_D1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001306 else if (VG_CLO_STREQN(5, arg, "--L2="))
nethercote9313ac42004-07-06 21:54:20 +00001307 parse_cache_opt(&clo_L2_cache, &arg[5]);
sewardje1216cb2007-02-07 19:55:30 +00001308 else if (VG_CLO_STREQN(22, arg, "--cachegrind-out-file=")) {
1309 cachegrind_out_file_basename = &arg[22];
1310 }
njn25e49d8e72002-09-23 09:36:25 +00001311 else
1312 return False;
1313
1314 return True;
1315}
1316
njn51d827b2005-05-09 01:02:08 +00001317static void cg_print_usage(void)
njn25e49d8e72002-09-23 09:36:25 +00001318{
njn3e884182003-04-15 13:03:23 +00001319 VG_(printf)(
njn25e49d8e72002-09-23 09:36:25 +00001320" --I1=<size>,<assoc>,<line_size> set I1 cache manually\n"
1321" --D1=<size>,<assoc>,<line_size> set D1 cache manually\n"
njn3e884182003-04-15 13:03:23 +00001322" --L2=<size>,<assoc>,<line_size> set L2 cache manually\n"
sewardje1216cb2007-02-07 19:55:30 +00001323" --cachegrind-out-file=<file> write profile data to <file>.<pid>\n"
1324" [cachegrind.out.<pid>]\n"
njn3e884182003-04-15 13:03:23 +00001325 );
1326}
1327
njn51d827b2005-05-09 01:02:08 +00001328static void cg_print_debug_usage(void)
njn3e884182003-04-15 13:03:23 +00001329{
1330 VG_(printf)(
1331" (none)\n"
1332 );
njn25e49d8e72002-09-23 09:36:25 +00001333}
1334
1335/*--------------------------------------------------------------------*/
1336/*--- Setup ---*/
1337/*--------------------------------------------------------------------*/
1338
njn57ca7ab2005-06-21 23:44:58 +00001339static Char base_dir[VKI_PATH_MAX];
1340
sewardje1216cb2007-02-07 19:55:30 +00001341static void cg_post_clo_init(void); /* just below */
1342
njn51d827b2005-05-09 01:02:08 +00001343static void cg_pre_clo_init(void)
1344{
njn51d827b2005-05-09 01:02:08 +00001345 VG_(details_name) ("Cachegrind");
1346 VG_(details_version) (NULL);
1347 VG_(details_description) ("an I1/D1/L2 cache profiler");
1348 VG_(details_copyright_author)(
sewardj9ebd6e02007-01-08 06:01:59 +00001349 "Copyright (C) 2002-2007, and GNU GPL'd, by Nicholas Nethercote et al.");
njn51d827b2005-05-09 01:02:08 +00001350 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardje8089302006-10-17 02:15:17 +00001351 VG_(details_avg_translation_sizeB) ( 500 );
njn51d827b2005-05-09 01:02:08 +00001352
1353 VG_(basic_tool_funcs) (cg_post_clo_init,
1354 cg_instrument,
1355 cg_fini);
1356
sewardj0b9d74a2006-12-24 02:24:11 +00001357 VG_(needs_superblock_discards)(cg_discard_superblock_info);
njn51d827b2005-05-09 01:02:08 +00001358 VG_(needs_command_line_options)(cg_process_cmd_line_option,
1359 cg_print_usage,
1360 cg_print_debug_usage);
sewardje1216cb2007-02-07 19:55:30 +00001361}
1362
1363static void cg_post_clo_init(void)
1364{
1365 HChar* qual = NULL;
1366 cache_t I1c, D1c, L2c;
1367 Int filename_szB;
njn51d827b2005-05-09 01:02:08 +00001368
1369 /* Get working directory */
njn57ca7ab2005-06-21 23:44:58 +00001370 tl_assert( VG_(getcwd)(base_dir, VKI_PATH_MAX) );
njn51d827b2005-05-09 01:02:08 +00001371
sewardje1216cb2007-02-07 19:55:30 +00001372 /* Do we have a --log-file-qualifier= to consider? */
1373 if (VG_(clo_log_file_qualifier)) {
1374 qual = VG_(getenv)(VG_(clo_log_file_qualifier));
1375 }
1376
1377 /* Block is big enough for
1378 dir name ++ cachegrind_out_file_basename
1379 ++ ".<pid>"
1380 ++ the log file qualifier, if in use */
1381 filename_szB
1382 = VG_(strlen)(base_dir)
1383 + 1 /* "/" */
1384 + VG_(strlen)(cachegrind_out_file_basename)
1385 + 11 /* "." <pid>, assuming sizeof(pid) <= 4 */
1386 + (qual ? (10 + VG_(strlen)(qual)) : 0)
1387 + 1; /* to guarantee checkable zero at the end */
1388
1389 tl_assert(filename_szB > 0);
1390 cachegrind_out_file
1391 = VG_(calloc)( sizeof(Char), filename_szB );
1392
1393 if (qual) {
1394 VG_(sprintf)(cachegrind_out_file, "%s/%s.%d.lfq.%s",
1395 base_dir, cachegrind_out_file_basename,
1396 VG_(getpid)(), qual);
1397 } else {
1398 VG_(sprintf)(cachegrind_out_file, "%s/%s.%d",
1399 base_dir, cachegrind_out_file_basename,
1400 VG_(getpid)());
1401 }
1402
1403 tl_assert( cachegrind_out_file[filename_szB-1] == 0 );
njn51d827b2005-05-09 01:02:08 +00001404
njnd3bef4f2005-10-15 17:46:18 +00001405 CC_table = VG_(OSet_Create)(offsetof(LineCC, loc),
1406 cmp_CodeLoc_LineCC,
1407 VG_(malloc), VG_(free));
sewardj4ba057c2005-10-18 12:04:18 +00001408 instrInfoTable = VG_(OSet_Create)(/*keyOff*/0,
njnd3bef4f2005-10-15 17:46:18 +00001409 NULL,
1410 VG_(malloc), VG_(free));
1411 stringTable = VG_(OSet_Create)(/*keyOff*/0,
1412 stringCmp,
1413 VG_(malloc), VG_(free));
sewardje1216cb2007-02-07 19:55:30 +00001414
1415 configure_caches(&I1c, &D1c, &L2c);
1416
1417 cachesim_I1_initcache(I1c);
1418 cachesim_D1_initcache(D1c);
1419 cachesim_L2_initcache(L2c);
njn51d827b2005-05-09 01:02:08 +00001420}
1421
sewardj45f4e7c2005-09-27 19:20:21 +00001422VG_DETERMINE_INTERFACE_VERSION(cg_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00001423
njn25e49d8e72002-09-23 09:36:25 +00001424/*--------------------------------------------------------------------*/
njnf69f9452005-07-03 17:53:11 +00001425/*--- end ---*/
sewardj18d75132002-05-16 11:06:21 +00001426/*--------------------------------------------------------------------*/
njnd3bef4f2005-10-15 17:46:18 +00001427