blob: 3c9627e1466bfa380349ca742a566c7b2fcb38a4 [file] [log] [blame]
sewardj07133bf2002-06-13 10:25:56 +00001
njn4f9c9342002-04-29 16:03:24 +00002/*--------------------------------------------------------------------*/
njn101e5722005-04-21 02:37:54 +00003/*--- Cachegrind: everything but the simulation itself. ---*/
njn25cac76cb2002-09-23 11:21:57 +00004/*--- cg_main.c ---*/
njn4f9c9342002-04-29 16:03:24 +00005/*--------------------------------------------------------------------*/
6
7/*
nethercote137bc552003-11-14 17:47:54 +00008 This file is part of Cachegrind, a Valgrind tool for cache
njnc9539842002-10-02 13:26:35 +00009 profiling programs.
njn4f9c9342002-04-29 16:03:24 +000010
njn53612422005-03-12 16:22:54 +000011 Copyright (C) 2002-2005 Nicholas Nethercote
njn2bc10122005-05-08 02:10:27 +000012 njn@valgrind.org
njn4f9c9342002-04-29 16:03:24 +000013
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
njn25e49d8e72002-09-23 09:36:25 +000029 The GNU General Public License is contained in the file COPYING.
njn4f9c9342002-04-29 16:03:24 +000030*/
31
njnc7561b92005-06-19 01:24:32 +000032#include "pub_tool_basics.h"
njnea27e462005-05-31 02:38:09 +000033#include "pub_tool_debuginfo.h"
njn97405b22005-06-02 03:39:33 +000034#include "pub_tool_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000035#include "pub_tool_libcassert.h"
njneb8896b2005-06-04 20:03:55 +000036#include "pub_tool_libcfile.h"
njn36a20fa2005-06-03 03:08:39 +000037#include "pub_tool_libcprint.h"
njnf39e9a32005-06-12 02:43:17 +000038#include "pub_tool_libcproc.h"
njnf536bbb2005-06-13 04:21:38 +000039#include "pub_tool_machine.h"
njn717cde52005-05-10 02:47:21 +000040#include "pub_tool_mallocfree.h"
njn20242342005-05-16 23:31:24 +000041#include "pub_tool_options.h"
njnd3bef4f2005-10-15 17:46:18 +000042#include "pub_tool_oset.h"
njn31513b42005-06-01 03:09:59 +000043#include "pub_tool_profile.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"
njn25e49d8e72002-09-23 09:36:25 +000046
nethercoteb35a8b92004-09-11 16:45:27 +000047#include "cg_arch.h"
nethercote27fc1da2004-01-04 16:56:57 +000048#include "cg_sim.c"
njn4f9c9342002-04-29 16:03:24 +000049
njn25e49d8e72002-09-23 09:36:25 +000050/*------------------------------------------------------------*/
51/*--- Constants ---*/
52/*------------------------------------------------------------*/
njn4f9c9342002-04-29 16:03:24 +000053
sewardj5155dec2005-10-12 10:09:23 +000054/* Set to 1 for very verbose debugging */
55#define DEBUG_CG 0
56
nethercote9313ac42004-07-06 21:54:20 +000057#define MIN_LINE_SIZE 16
njnd3bef4f2005-10-15 17:46:18 +000058#define FILE_LEN VKI_PATH_MAX
nethercote9313ac42004-07-06 21:54:20 +000059#define FN_LEN 256
njn7cf0bd32002-06-08 13:36:03 +000060
61/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +000062/*--- Profiling events ---*/
njn7cf0bd32002-06-08 13:36:03 +000063/*------------------------------------------------------------*/
64
njn25e49d8e72002-09-23 09:36:25 +000065typedef
66 enum {
nethercote9313ac42004-07-06 21:54:20 +000067 VgpGetLineCC = VgpFini+1,
njn25e49d8e72002-09-23 09:36:25 +000068 VgpCacheSimulate,
69 VgpCacheResults
70 }
nethercote7cc9c232004-01-21 15:08:04 +000071 VgpToolCC;
sewardj07133bf2002-06-13 10:25:56 +000072
njn4f9c9342002-04-29 16:03:24 +000073/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +000074/*--- Types and Data Structures ---*/
njn4f9c9342002-04-29 16:03:24 +000075/*------------------------------------------------------------*/
76
77typedef struct _CC CC;
78struct _CC {
79 ULong a;
80 ULong m1;
81 ULong m2;
82};
83
nethercote9313ac42004-07-06 21:54:20 +000084//------------------------------------------------------------
85// Primary data structure #1: CC table
86// - Holds the per-source-line hit/miss stats, grouped by file/function/line.
njnd3bef4f2005-10-15 17:46:18 +000087// - an ordered set of CCs. CC indexing done by file/function/line (as
88// determined from the instrAddr).
nethercote9313ac42004-07-06 21:54:20 +000089// - Traversed for dumping stats at end in file/func/line hierarchy.
njn4f9c9342002-04-29 16:03:24 +000090
njnd3bef4f2005-10-15 17:46:18 +000091typedef struct {
92 Char* file;
93 Char* fn;
94 Int line;
95}
96CodeLoc;
njn4f9c9342002-04-29 16:03:24 +000097
njnd3bef4f2005-10-15 17:46:18 +000098typedef struct _LineCC LineCC;
99struct _LineCC {
100 CodeLoc loc;
101 CC Ir;
102 CC Dr;
103 CC Dw;
njn4f9c9342002-04-29 16:03:24 +0000104};
105
njnd3bef4f2005-10-15 17:46:18 +0000106// First compare file, then fn, then line.
107static Int cmp_CodeLoc_LineCC(void *vloc, void *vcc)
108{
109 Int res;
110 CodeLoc* a = (CodeLoc*)vloc;
111 CodeLoc* b = &(((LineCC*)vcc)->loc);
njn4f9c9342002-04-29 16:03:24 +0000112
njnd3bef4f2005-10-15 17:46:18 +0000113 res = VG_(strcmp)(a->file, b->file);
114 if (0 != res)
115 return res;
njn4f9c9342002-04-29 16:03:24 +0000116
njnd3bef4f2005-10-15 17:46:18 +0000117 res = VG_(strcmp)(a->fn, b->fn);
118 if (0 != res)
119 return res;
120
121 return a->line - b->line;
122}
123
124static OSet* CC_table;
njn4f9c9342002-04-29 16:03:24 +0000125
nethercote9313ac42004-07-06 21:54:20 +0000126//------------------------------------------------------------
njnd3bef4f2005-10-15 17:46:18 +0000127// Primary data structure #2: InstrInfo table
nethercote9313ac42004-07-06 21:54:20 +0000128// - Holds the cached info about each instr that is used for simulation.
njnd3bef4f2005-10-15 17:46:18 +0000129// - table(BB_start_addr, list(InstrInfo))
130// - For each BB, each InstrInfo in the list holds info about the
131// instruction (instrLen, instrAddr, etc), plus a pointer to its line
nethercote9313ac42004-07-06 21:54:20 +0000132// CC. This node is what's passed to the simulation function.
133// - When BBs are discarded the relevant list(instr_details) is freed.
134
njnd3bef4f2005-10-15 17:46:18 +0000135typedef struct _InstrInfo InstrInfo;
136struct _InstrInfo {
nethercoteca1f2dc2004-07-21 08:49:02 +0000137 Addr instr_addr;
njn6a3009b2005-03-20 00:20:06 +0000138 UChar instr_len;
njnd3bef4f2005-10-15 17:46:18 +0000139 LineCC* parent; // parent line-CC
nethercote9313ac42004-07-06 21:54:20 +0000140};
141
142typedef struct _BB_info BB_info;
143struct _BB_info {
sewardj4ba057c2005-10-18 12:04:18 +0000144 Addr BB_addr; // key; MUST BE FIRST
njnd3bef4f2005-10-15 17:46:18 +0000145 Int n_instrs;
146 InstrInfo instrs[0];
nethercote9313ac42004-07-06 21:54:20 +0000147};
148
njnd3bef4f2005-10-15 17:46:18 +0000149static OSet* instrInfoTable;
150
151//------------------------------------------------------------
152// Secondary data structure: string table
153// - holds strings, avoiding dups
154// - used for filenames and function names, each of which will be
155// pointed to by one or more CCs.
156// - it also allows equality checks just by pointer comparison, which
157// is good when printing the output file at the end.
158
159static OSet* stringTable;
nethercote9313ac42004-07-06 21:54:20 +0000160
161//------------------------------------------------------------
162// Stats
sewardj4f29ddf2002-05-03 22:29:04 +0000163static Int distinct_files = 0;
164static Int distinct_fns = 0;
nethercote9313ac42004-07-06 21:54:20 +0000165static Int distinct_lines = 0;
sewardj4f29ddf2002-05-03 22:29:04 +0000166static Int distinct_instrs = 0;
nethercote9313ac42004-07-06 21:54:20 +0000167
njnd3bef4f2005-10-15 17:46:18 +0000168static Int full_debugs = 0;
169static Int file_line_debugs = 0;
170static Int fn_debugs = 0;
171static Int no_debugs = 0;
njn4f9c9342002-04-29 16:03:24 +0000172
nethercote9313ac42004-07-06 21:54:20 +0000173/*------------------------------------------------------------*/
njnd3bef4f2005-10-15 17:46:18 +0000174/*--- String table operations ---*/
175/*------------------------------------------------------------*/
176
177static Int stringCmp( void* key, void* elem )
178{
179 return VG_(strcmp)(*(Char**)key, *(Char**)elem);
180}
181
182// Get a permanent string; either pull it out of the string table if it's
183// been encountered before, or dup it and put it into the string table.
184static Char* get_perm_string(Char* s)
185{
186 Char** s_ptr = VG_(OSet_Lookup)(stringTable, &s);
187 if (s_ptr) {
188 return *s_ptr;
189 } else {
190 Char** s_node = VG_(OSet_AllocNode)(stringTable, sizeof(Char*));
191 *s_node = VG_(strdup)(s);
192 VG_(OSet_Insert)(stringTable, s_node);
193 return *s_node;
194 }
195}
196
197/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +0000198/*--- CC table operations ---*/
199/*------------------------------------------------------------*/
njn4294fd42002-06-05 14:41:10 +0000200
nethercote9313ac42004-07-06 21:54:20 +0000201static void get_debug_info(Addr instr_addr, Char file[FILE_LEN],
202 Char fn[FN_LEN], Int* line)
njn4f9c9342002-04-29 16:03:24 +0000203{
sewardj7cee6f92005-06-13 17:39:06 +0000204 Bool found_file_line = VG_(get_filename_linenum)(
205 instr_addr,
206 file, FILE_LEN,
207 NULL, 0, NULL,
208 line
209 );
nethercote9313ac42004-07-06 21:54:20 +0000210 Bool found_fn = VG_(get_fnname)(instr_addr, fn, FN_LEN);
njn4f9c9342002-04-29 16:03:24 +0000211
nethercote9313ac42004-07-06 21:54:20 +0000212 if (!found_file_line) {
213 VG_(strcpy)(file, "???");
214 *line = 0;
215 }
216 if (!found_fn) {
217 VG_(strcpy)(fn, "???");
218 }
219 if (found_file_line) {
njnd3bef4f2005-10-15 17:46:18 +0000220 if (found_fn) full_debugs++;
221 else file_line_debugs++;
nethercote9313ac42004-07-06 21:54:20 +0000222 } else {
njnd3bef4f2005-10-15 17:46:18 +0000223 if (found_fn) fn_debugs++;
224 else no_debugs++;
njn4f9c9342002-04-29 16:03:24 +0000225 }
226}
227
nethercote9313ac42004-07-06 21:54:20 +0000228// Do a three step traversal: by file, then fn, then line.
njnd3bef4f2005-10-15 17:46:18 +0000229// Returns a pointer to the line CC, creates a new one if necessary.
230static LineCC* get_lineCC(Addr origAddr)
nethercote9313ac42004-07-06 21:54:20 +0000231{
nethercote9313ac42004-07-06 21:54:20 +0000232 Char file[FILE_LEN], fn[FN_LEN];
233 Int line;
njnd3bef4f2005-10-15 17:46:18 +0000234 CodeLoc loc;
235 LineCC* lineCC;
nethercote9313ac42004-07-06 21:54:20 +0000236
njn6a3009b2005-03-20 00:20:06 +0000237 get_debug_info(origAddr, file, fn, &line);
nethercote9313ac42004-07-06 21:54:20 +0000238
239 VGP_PUSHCC(VgpGetLineCC);
240
njnd3bef4f2005-10-15 17:46:18 +0000241 loc.file = file;
242 loc.fn = fn;
243 loc.line = line;
njn4f9c9342002-04-29 16:03:24 +0000244
njnd3bef4f2005-10-15 17:46:18 +0000245 lineCC = VG_(OSet_Lookup)(CC_table, &loc);
246 if (!lineCC) {
247 // Allocate and zero a new node.
248 lineCC = VG_(OSet_AllocNode)(CC_table, sizeof(LineCC));
249 lineCC->loc.file = get_perm_string(loc.file);
250 lineCC->loc.fn = get_perm_string(loc.fn);
251 lineCC->loc.line = loc.line;
252 VG_(OSet_Insert)(CC_table, lineCC);
njn4f9c9342002-04-29 16:03:24 +0000253 }
nethercote9313ac42004-07-06 21:54:20 +0000254
255 VGP_POPCC(VgpGetLineCC);
njnd3bef4f2005-10-15 17:46:18 +0000256 return lineCC;
njn4f9c9342002-04-29 16:03:24 +0000257}
258
259/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +0000260/*--- Cache simulation functions ---*/
njn4f9c9342002-04-29 16:03:24 +0000261/*------------------------------------------------------------*/
262
njnaf839f52005-06-23 03:27:57 +0000263static VG_REGPARM(1)
njnd3bef4f2005-10-15 17:46:18 +0000264void log_1I_0D_cache_access(InstrInfo* n)
njn25e49d8e72002-09-23 09:36:25 +0000265{
sewardj5155dec2005-10-12 10:09:23 +0000266 //VG_(printf)("1I_0D : CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n",
267 // n, n->instr_addr, n->instr_len);
njn25e49d8e72002-09-23 09:36:25 +0000268 VGP_PUSHCC(VgpCacheSimulate);
njn6a3009b2005-03-20 00:20:06 +0000269 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000270 &n->parent->Ir.m1, &n->parent->Ir.m2);
271 n->parent->Ir.a++;
njn25e49d8e72002-09-23 09:36:25 +0000272 VGP_POPCC(VgpCacheSimulate);
273}
274
njnaf839f52005-06-23 03:27:57 +0000275static VG_REGPARM(2)
njnd3bef4f2005-10-15 17:46:18 +0000276void log_2I_0D_cache_access(InstrInfo* n, InstrInfo* n2)
njn25e49d8e72002-09-23 09:36:25 +0000277{
sewardj5155dec2005-10-12 10:09:23 +0000278 //VG_(printf)("2I_0D : CC1addr=0x%010lx, i1addr=0x%010lx, i1size=%lu\n"
279 // " CC2addr=0x%010lx, i2addr=0x%010lx, i2size=%lu\n",
280 // n, n->instr_addr, n->instr_len,
281 // n2, n2->instr_addr, n2->instr_len);
282 VGP_PUSHCC(VgpCacheSimulate);
283 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 VGP_POPCC(VgpCacheSimulate);
290}
291
292static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000293void log_3I_0D_cache_access(InstrInfo* n, InstrInfo* n2, InstrInfo* n3)
sewardj5155dec2005-10-12 10:09:23 +0000294{
295 //VG_(printf)("3I_0D : CC1addr=0x%010lx, i1addr=0x%010lx, i1size=%lu\n"
296 // " CC2addr=0x%010lx, i2addr=0x%010lx, i2size=%lu\n"
297 // " CC3addr=0x%010lx, i3addr=0x%010lx, i3size=%lu\n",
298 // n, n->instr_addr, n->instr_len,
299 // n2, n2->instr_addr, n2->instr_len,
300 // n3, n3->instr_addr, n3->instr_len);
301 VGP_PUSHCC(VgpCacheSimulate);
302 cachesim_I1_doref(n->instr_addr, n->instr_len,
303 &n->parent->Ir.m1, &n->parent->Ir.m2);
304 n->parent->Ir.a++;
305 cachesim_I1_doref(n2->instr_addr, n2->instr_len,
306 &n2->parent->Ir.m1, &n2->parent->Ir.m2);
307 n2->parent->Ir.a++;
308 cachesim_I1_doref(n3->instr_addr, n3->instr_len,
309 &n3->parent->Ir.m1, &n3->parent->Ir.m2);
310 n3->parent->Ir.a++;
311 VGP_POPCC(VgpCacheSimulate);
312}
313
314static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000315void log_1I_1Dr_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
sewardj5155dec2005-10-12 10:09:23 +0000316{
317 //VG_(printf)("1I_1Dr: CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n"
318 // " daddr=0x%010lx, dsize=%lu\n",
319 // n, n->instr_addr, n->instr_len, data_addr, data_size);
njn25e49d8e72002-09-23 09:36:25 +0000320 VGP_PUSHCC(VgpCacheSimulate);
njn6a3009b2005-03-20 00:20:06 +0000321 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000322 &n->parent->Ir.m1, &n->parent->Ir.m2);
323 n->parent->Ir.a++;
njn25e49d8e72002-09-23 09:36:25 +0000324
sewardj5155dec2005-10-12 10:09:23 +0000325 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000326 &n->parent->Dr.m1, &n->parent->Dr.m2);
327 n->parent->Dr.a++;
njn25e49d8e72002-09-23 09:36:25 +0000328 VGP_POPCC(VgpCacheSimulate);
329}
330
sewardj5155dec2005-10-12 10:09:23 +0000331static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000332void log_1I_1Dw_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
njn25e49d8e72002-09-23 09:36:25 +0000333{
sewardj5155dec2005-10-12 10:09:23 +0000334 //VG_(printf)("1I_1Dw: CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n"
335 // " daddr=0x%010lx, dsize=%lu\n",
336 // n, n->instr_addr, n->instr_len, data_addr, data_size);
njn25e49d8e72002-09-23 09:36:25 +0000337 VGP_PUSHCC(VgpCacheSimulate);
njn6a3009b2005-03-20 00:20:06 +0000338 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000339 &n->parent->Ir.m1, &n->parent->Ir.m2);
340 n->parent->Ir.a++;
341
sewardj5155dec2005-10-12 10:09:23 +0000342 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000343 &n->parent->Dw.m1, &n->parent->Dw.m2);
344 n->parent->Dw.a++;
njn25e49d8e72002-09-23 09:36:25 +0000345 VGP_POPCC(VgpCacheSimulate);
346}
347
njnaf839f52005-06-23 03:27:57 +0000348static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000349void log_0I_1Dr_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
njn25e49d8e72002-09-23 09:36:25 +0000350{
sewardj5155dec2005-10-12 10:09:23 +0000351 //VG_(printf)("0I_1Dr: CCaddr=0x%010lx, daddr=0x%010lx, dsize=%lu\n",
352 // n, data_addr, data_size);
njn25e49d8e72002-09-23 09:36:25 +0000353 VGP_PUSHCC(VgpCacheSimulate);
sewardj5155dec2005-10-12 10:09:23 +0000354 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000355 &n->parent->Dr.m1, &n->parent->Dr.m2);
356 n->parent->Dr.a++;
sewardj5155dec2005-10-12 10:09:23 +0000357 VGP_POPCC(VgpCacheSimulate);
358}
359
360static VG_REGPARM(3)
njnd3bef4f2005-10-15 17:46:18 +0000361void log_0I_1Dw_cache_access(InstrInfo* n, Addr data_addr, Word data_size)
sewardj5155dec2005-10-12 10:09:23 +0000362{
363 //VG_(printf)("0I_1Dw: CCaddr=0x%010lx, daddr=0x%010lx, dsize=%lu\n",
364 // n, data_addr, data_size);
365 VGP_PUSHCC(VgpCacheSimulate);
366 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000367 &n->parent->Dw.m1, &n->parent->Dw.m2);
368 n->parent->Dw.a++;
njn25e49d8e72002-09-23 09:36:25 +0000369 VGP_POPCC(VgpCacheSimulate);
370}
371
nethercote9313ac42004-07-06 21:54:20 +0000372/*------------------------------------------------------------*/
sewardj5155dec2005-10-12 10:09:23 +0000373/*--- Instrumentation types and structures ---*/
374/*------------------------------------------------------------*/
375
376/* Maintain an ordered list of memory events which are outstanding, in
377 the sense that no IR has yet been generated to do the relevant
378 helper calls. The BB is scanned top to bottom and memory events
379 are added to the end of the list, merging with the most recent
380 notified event where possible (Dw immediately following Dr and
381 having the same size and EA can be merged).
382
383 This merging is done so that for architectures which have
384 load-op-store instructions (x86, amd64), the insn is treated as if
385 it makes just one memory reference (a modify), rather than two (a
386 read followed by a write at the same address).
387
388 At various points the list will need to be flushed, that is, IR
389 generated from it. That must happen before any possible exit from
390 the block (the end, or an IRStmt_Exit). Flushing also takes place
391 when there is no space to add a new event.
392
393 If we require the simulation statistics to be up to date with
394 respect to possible memory exceptions, then the list would have to
395 be flushed before each memory reference. That would however lose
396 performance by inhibiting event-merging during flushing.
397
398 Flushing the list consists of walking it start to end and emitting
399 instrumentation IR for each event, in the order in which they
400 appear. It may be possible to emit a single call for two adjacent
401 events in order to reduce the number of helper function calls made.
402 For example, it could well be profitable to handle two adjacent Ir
403 events with a single helper call. */
404
405typedef
406 IRExpr
407 IRAtom;
408
409typedef
sewardj20edebf2005-10-12 10:29:40 +0000410 enum { Event_Ir, Event_Dr, Event_Dw, Event_Dm }
sewardj5155dec2005-10-12 10:09:23 +0000411 EventKind;
412
413typedef
414 struct {
njnfd9f6222005-10-16 00:17:37 +0000415 EventKind ekind; // All
416 InstrInfo* inode; // All; inode for this event's instruction
417 Int datasize; // Dr/Dw/Dm only
418 IRAtom* dataEA; // Dr/Dw/Dm only; IR ATOM ONLY
sewardj5155dec2005-10-12 10:09:23 +0000419 }
420 Event;
421
422/* Up to this many unnotified events are allowed. Number is
423 arbitrary. Larger numbers allow more event merging to occur, but
424 potentially induce more spilling due to extending live ranges of
425 address temporaries. */
426#define N_EVENTS 16
427
428
429/* A struct which holds all the running state during instrumentation.
430 Mostly to avoid passing loads of parameters everywhere. */
431typedef
432 struct {
433 /* The current outstanding-memory-event list. */
434 Event events[N_EVENTS];
435 Int events_used;
436
njnd3bef4f2005-10-15 17:46:18 +0000437 /* The array of InstrInfo bins for the BB. */
sewardj5155dec2005-10-12 10:09:23 +0000438 BB_info* bbInfo;
439
njnd3bef4f2005-10-15 17:46:18 +0000440 /* Number InstrInfo bins 'used' so far. */
sewardj5155dec2005-10-12 10:09:23 +0000441 Int bbInfo_i;
442
sewardj5155dec2005-10-12 10:09:23 +0000443 /* The output BB being constructed. */
444 IRBB* bbOut;
445 }
446 CgState;
447
448
sewardj5155dec2005-10-12 10:09:23 +0000449/*------------------------------------------------------------*/
450/*--- Instrumentation main ---*/
nethercote9313ac42004-07-06 21:54:20 +0000451/*------------------------------------------------------------*/
452
sewardj4ba057c2005-10-18 12:04:18 +0000453// Note that origAddr is the real origAddr, not the address of the first
454// instruction in the block (they can be different due to redirection).
nethercote564b2b02004-08-07 15:54:53 +0000455static
sewardja3a29a52005-10-12 16:16:03 +0000456BB_info* get_BB_info(IRBB* bbIn, Addr origAddr)
nethercote9313ac42004-07-06 21:54:20 +0000457{
njn4bd67b52005-08-11 00:47:10 +0000458 Int i, n_instrs;
459 IRStmt* st;
460 BB_info* bbInfo;
njnd3bef4f2005-10-15 17:46:18 +0000461
njn6a3009b2005-03-20 00:20:06 +0000462 // Count number of original instrs in BB
463 n_instrs = 0;
464 for (i = 0; i < bbIn->stmts_used; i++) {
465 st = bbIn->stmts[i];
466 if (Ist_IMark == st->tag) n_instrs++;
nethercote9313ac42004-07-06 21:54:20 +0000467 }
468
njnf7d26092005-10-12 16:45:17 +0000469 // Check that we don't have an entry for this BB in the instr-info table.
470 // If this assertion fails, there has been some screwup: some
471 // translations must have been discarded but Cachegrind hasn't discarded
472 // the corresponding entries in the instr-info table.
njnd3bef4f2005-10-15 17:46:18 +0000473 bbInfo = VG_(OSet_Lookup)(instrInfoTable, &origAddr);
sewardja3a29a52005-10-12 16:16:03 +0000474 tl_assert(NULL == bbInfo);
475
njnd3bef4f2005-10-15 17:46:18 +0000476 // BB never translated before (at this address, at least; could have
477 // been unloaded and then reloaded elsewhere in memory)
478 bbInfo = VG_(OSet_AllocNode)(instrInfoTable,
479 sizeof(BB_info) + n_instrs*sizeof(InstrInfo));
480 bbInfo->BB_addr = origAddr;
sewardja3a29a52005-10-12 16:16:03 +0000481 bbInfo->n_instrs = n_instrs;
njnd3bef4f2005-10-15 17:46:18 +0000482 VG_(OSet_Insert)( instrInfoTable, bbInfo );
sewardja3a29a52005-10-12 16:16:03 +0000483 distinct_instrs++;
484
njn6a3009b2005-03-20 00:20:06 +0000485 return bbInfo;
nethercote9313ac42004-07-06 21:54:20 +0000486}
njn6a3009b2005-03-20 00:20:06 +0000487
nethercote9313ac42004-07-06 21:54:20 +0000488
sewardj5155dec2005-10-12 10:09:23 +0000489static void showEvent ( Event* ev )
nethercote9313ac42004-07-06 21:54:20 +0000490{
sewardj5155dec2005-10-12 10:09:23 +0000491 switch (ev->ekind) {
492 case Event_Ir:
njnfd9f6222005-10-16 00:17:37 +0000493 VG_(printf)("Ir %p\n", ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000494 break;
495 case Event_Dr:
njnfd9f6222005-10-16 00:17:37 +0000496 VG_(printf)("Dr %p %d EA=", ev->inode, ev->datasize);
sewardj5155dec2005-10-12 10:09:23 +0000497 ppIRExpr(ev->dataEA);
498 VG_(printf)("\n");
499 break;
500 case Event_Dw:
njnfd9f6222005-10-16 00:17:37 +0000501 VG_(printf)("Dw %p %d EA=", ev->inode, ev->datasize);
sewardj5155dec2005-10-12 10:09:23 +0000502 ppIRExpr(ev->dataEA);
503 VG_(printf)("\n");
504 break;
505 case Event_Dm:
njnfd9f6222005-10-16 00:17:37 +0000506 VG_(printf)("Dm %p %d EA=", ev->inode, ev->datasize);
sewardj5155dec2005-10-12 10:09:23 +0000507 ppIRExpr(ev->dataEA);
508 VG_(printf)("\n");
509 break;
510 default:
511 tl_assert(0);
512 break;
513 }
njn6a3009b2005-03-20 00:20:06 +0000514}
515
njnfd9f6222005-10-16 00:17:37 +0000516// Reserve and initialise an InstrInfo for the first mention of a new insn.
517static
518InstrInfo* setup_InstrInfo ( CgState* cgs, Addr instr_addr, UInt instr_len )
njn6a3009b2005-03-20 00:20:06 +0000519{
njnd3bef4f2005-10-15 17:46:18 +0000520 InstrInfo* i_node;
sewardj5155dec2005-10-12 10:09:23 +0000521 tl_assert(cgs->bbInfo_i >= 0);
522 tl_assert(cgs->bbInfo_i < cgs->bbInfo->n_instrs);
523 i_node = &cgs->bbInfo->instrs[ cgs->bbInfo_i ];
njnfd9f6222005-10-16 00:17:37 +0000524 i_node->instr_addr = instr_addr;
525 i_node->instr_len = instr_len;
526 i_node->parent = get_lineCC(instr_addr);
sewardj5155dec2005-10-12 10:09:23 +0000527 cgs->bbInfo_i++;
528 return i_node;
529}
sewardj17a56bf2005-03-21 01:35:02 +0000530
sewardj17a56bf2005-03-21 01:35:02 +0000531
sewardj5155dec2005-10-12 10:09:23 +0000532/* Generate code for all outstanding memory events, and mark the queue
533 empty. Code is generated into cgs->bbOut, and this activity
534 'consumes' slots in cgs->bbInfo. */
njn6a3009b2005-03-20 00:20:06 +0000535
sewardj5155dec2005-10-12 10:09:23 +0000536static void flushEvents ( CgState* cgs )
537{
njnd3bef4f2005-10-15 17:46:18 +0000538 Int i, regparms;
539 Char* helperName;
540 void* helperAddr;
541 IRExpr** argv;
542 IRExpr* i_node_expr;
njnd3bef4f2005-10-15 17:46:18 +0000543 IRDirty* di;
njnc285dca2005-10-15 22:07:28 +0000544 Event* ev;
545 Event* ev2;
546 Event* ev3;
njn6a3009b2005-03-20 00:20:06 +0000547
sewardj5155dec2005-10-12 10:09:23 +0000548 i = 0;
549 while (i < cgs->events_used) {
njn6a3009b2005-03-20 00:20:06 +0000550
sewardj5155dec2005-10-12 10:09:23 +0000551 helperName = NULL;
552 helperAddr = NULL;
553 argv = NULL;
554 regparms = 0;
555
556 /* generate IR to notify event i and possibly the ones
557 immediately following it. */
558 tl_assert(i >= 0 && i < cgs->events_used);
njnc285dca2005-10-15 22:07:28 +0000559
560 ev = &cgs->events[i];
561 ev2 = ( i < cgs->events_used-1 ? &cgs->events[i+1] : NULL );
562 ev3 = ( i < cgs->events_used-2 ? &cgs->events[i+2] : NULL );
563
sewardj5155dec2005-10-12 10:09:23 +0000564 if (DEBUG_CG) {
565 VG_(printf)(" flush ");
njnc285dca2005-10-15 22:07:28 +0000566 showEvent( ev );
njn4f9c9342002-04-29 16:03:24 +0000567 }
sewardj5155dec2005-10-12 10:09:23 +0000568
njnfd9f6222005-10-16 00:17:37 +0000569 i_node_expr = mkIRExpr_HWord( (HWord)ev->inode );
sewardj5155dec2005-10-12 10:09:23 +0000570
571 /* Decide on helper fn to call and args to pass it, and advance
572 i appropriately. */
njnc285dca2005-10-15 22:07:28 +0000573 switch (ev->ekind) {
sewardj5155dec2005-10-12 10:09:23 +0000574 case Event_Ir:
575 /* Merge with a following Dr/Dm if it is from this insn. */
njnc285dca2005-10-15 22:07:28 +0000576 if (ev2 && (ev2->ekind == Event_Dr || ev2->ekind == Event_Dm)) {
njnfd9f6222005-10-16 00:17:37 +0000577 tl_assert(ev2->inode == ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000578 helperName = "log_1I_1Dr_cache_access";
579 helperAddr = &log_1I_1Dr_cache_access;
580 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000581 ev2->dataEA,
njnfd9f6222005-10-16 00:17:37 +0000582 mkIRExpr_HWord( ev2->datasize ) );
sewardj5155dec2005-10-12 10:09:23 +0000583 regparms = 3;
584 i += 2;
585 }
586 /* Merge with a following Dw if it is from this insn. */
587 else
njnc285dca2005-10-15 22:07:28 +0000588 if (ev2 && ev2->ekind == Event_Dw) {
njnfd9f6222005-10-16 00:17:37 +0000589 tl_assert(ev2->inode == ev->inode);
sewardj5155dec2005-10-12 10:09:23 +0000590 helperName = "log_1I_1Dw_cache_access";
591 helperAddr = &log_1I_1Dw_cache_access;
592 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000593 ev2->dataEA,
njnfd9f6222005-10-16 00:17:37 +0000594 mkIRExpr_HWord( ev2->datasize ) );
sewardj5155dec2005-10-12 10:09:23 +0000595 regparms = 3;
596 i += 2;
597 }
598 /* Merge with two following Irs if possible. */
599 else
njnc285dca2005-10-15 22:07:28 +0000600 if (ev2 && ev3 && ev2->ekind == Event_Ir && ev3->ekind == Event_Ir)
601 {
sewardj5155dec2005-10-12 10:09:23 +0000602 helperName = "log_3I_0D_cache_access";
603 helperAddr = &log_3I_0D_cache_access;
njnfd9f6222005-10-16 00:17:37 +0000604 argv = mkIRExprVec_3( i_node_expr,
605 mkIRExpr_HWord( (HWord)ev2->inode ),
606 mkIRExpr_HWord( (HWord)ev3->inode ) );
sewardj5155dec2005-10-12 10:09:23 +0000607 regparms = 3;
608 i += 3;
609 }
610 /* Merge with a following Ir if possible. */
611 else
njnc285dca2005-10-15 22:07:28 +0000612 if (ev2 && ev2->ekind == Event_Ir) {
sewardj5155dec2005-10-12 10:09:23 +0000613 helperName = "log_2I_0D_cache_access";
614 helperAddr = &log_2I_0D_cache_access;
njnfd9f6222005-10-16 00:17:37 +0000615 argv = mkIRExprVec_2( i_node_expr,
616 mkIRExpr_HWord( (HWord)ev2->inode ) );
sewardj5155dec2005-10-12 10:09:23 +0000617 regparms = 2;
618 i += 2;
619 }
620 /* No merging possible; emit as-is. */
621 else {
njnc285dca2005-10-15 22:07:28 +0000622 // Assertion: this Event_Ir must be the last one in the
623 // events buffer, otherwise it would have been merged with a
624 // following event.
625 tl_assert(!ev2 && !ev3);
sewardj5155dec2005-10-12 10:09:23 +0000626 helperName = "log_1I_0D_cache_access";
627 helperAddr = &log_1I_0D_cache_access;
628 argv = mkIRExprVec_1( i_node_expr );
629 regparms = 1;
630 i++;
631 }
632 break;
633 case Event_Dr:
634 case Event_Dm:
635 helperName = "log_0I_1Dr_cache_access";
636 helperAddr = &log_0I_1Dr_cache_access;
637 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000638 ev->dataEA,
njnfd9f6222005-10-16 00:17:37 +0000639 mkIRExpr_HWord( ev->datasize ) );
sewardj5155dec2005-10-12 10:09:23 +0000640 regparms = 3;
641 i++;
642 break;
643 case Event_Dw:
644 helperName = "log_0I_1Dw_cache_access";
645 helperAddr = &log_0I_1Dw_cache_access;
646 argv = mkIRExprVec_3( i_node_expr,
njnc285dca2005-10-15 22:07:28 +0000647 ev->dataEA,
njnfd9f6222005-10-16 00:17:37 +0000648 mkIRExpr_HWord( ev->datasize ) );
sewardj5155dec2005-10-12 10:09:23 +0000649 regparms = 3;
650 i++;
651 break;
652 default:
653 tl_assert(0);
654 }
655
656 /* Add the helper. */
657 tl_assert(helperName);
658 tl_assert(helperAddr);
659 tl_assert(argv);
660 di = unsafeIRDirty_0_N( regparms, helperName, helperAddr, argv);
661 addStmtToIRBB( cgs->bbOut, IRStmt_Dirty(di) );
njn4f9c9342002-04-29 16:03:24 +0000662 }
663
sewardj5155dec2005-10-12 10:09:23 +0000664 cgs->events_used = 0;
njn4f9c9342002-04-29 16:03:24 +0000665}
njn14d01ce2004-11-26 11:30:14 +0000666
njnfd9f6222005-10-16 00:17:37 +0000667static void addEvent_Ir ( CgState* cgs, InstrInfo* inode )
sewardj5155dec2005-10-12 10:09:23 +0000668{
669 Event* evt;
sewardj5155dec2005-10-12 10:09:23 +0000670 if (cgs->events_used == N_EVENTS)
671 flushEvents(cgs);
672 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
673 evt = &cgs->events[cgs->events_used];
njnfd9f6222005-10-16 00:17:37 +0000674 evt->ekind = Event_Ir;
675 evt->inode = inode;
676 evt->datasize = 0;
677 evt->dataEA = NULL; /*paranoia*/
sewardj5155dec2005-10-12 10:09:23 +0000678 cgs->events_used++;
679}
680
njnfd9f6222005-10-16 00:17:37 +0000681static
682void addEvent_Dr ( CgState* cgs, InstrInfo* inode, Int datasize, IRAtom* ea )
sewardj5155dec2005-10-12 10:09:23 +0000683{
njnfd9f6222005-10-16 00:17:37 +0000684 Event* evt;
sewardj5155dec2005-10-12 10:09:23 +0000685 tl_assert(isIRAtom(ea));
njnfd9f6222005-10-16 00:17:37 +0000686 tl_assert(datasize >= 1 && datasize <= MIN_LINE_SIZE);
687 if (cgs->events_used == N_EVENTS)
688 flushEvents(cgs);
689 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
690 evt = &cgs->events[cgs->events_used];
691 evt->ekind = Event_Dr;
692 evt->inode = inode;
693 evt->datasize = datasize;
694 evt->dataEA = ea;
695 cgs->events_used++;
696}
sewardj5155dec2005-10-12 10:09:23 +0000697
njnfd9f6222005-10-16 00:17:37 +0000698static
699void addEvent_Dw ( CgState* cgs, InstrInfo* inode, Int datasize, IRAtom* ea )
700{
701 Event* lastEvt;
702 Event* evt;
703
704 tl_assert(isIRAtom(ea));
705 tl_assert(datasize >= 1 && datasize <= MIN_LINE_SIZE);
706
707 /* Is it possible to merge this write with the preceding read? */
708 lastEvt = &cgs->events[cgs->events_used-1];
sewardj5155dec2005-10-12 10:09:23 +0000709 if (cgs->events_used > 0
njnfd9f6222005-10-16 00:17:37 +0000710 && lastEvt->ekind == Event_Dr
711 && lastEvt->datasize == datasize
712 && lastEvt->inode == inode
713 && eqIRAtom(lastEvt->dataEA, ea))
714 {
715 lastEvt->ekind = Event_Dm;
sewardj5155dec2005-10-12 10:09:23 +0000716 return;
717 }
718
719 /* No. Add as normal. */
720 if (cgs->events_used == N_EVENTS)
721 flushEvents(cgs);
722 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
njnfd9f6222005-10-16 00:17:37 +0000723 evt = &cgs->events[cgs->events_used];
724 evt->ekind = Event_Dw;
725 evt->inode = inode;
726 evt->datasize = datasize;
727 evt->dataEA = ea;
sewardj5155dec2005-10-12 10:09:23 +0000728 cgs->events_used++;
729}
730
731////////////////////////////////////////////////////////////
732
733
sewardj4ba057c2005-10-18 12:04:18 +0000734static
735IRBB* cg_instrument ( IRBB* bbIn, VexGuestLayout* layout,
736 Addr64 orig_addr_noredir, VexGuestExtents* vge,
737 IRType gWordTy, IRType hWordTy )
njn14d01ce2004-11-26 11:30:14 +0000738{
njnfd9f6222005-10-16 00:17:37 +0000739 Int i, isize;
sewardj5155dec2005-10-12 10:09:23 +0000740 IRStmt* st;
741 Addr64 cia; /* address of current insn */
742 CgState cgs;
743 IRTypeEnv* tyenv = bbIn->tyenv;
njnfd9f6222005-10-16 00:17:37 +0000744 InstrInfo* curr_inode = NULL;
sewardj5155dec2005-10-12 10:09:23 +0000745
sewardjd54babf2005-03-21 00:55:49 +0000746 if (gWordTy != hWordTy) {
747 /* We don't currently support this case. */
748 VG_(tool_panic)("host/guest word size mismatch");
749 }
750
njnfd9f6222005-10-16 00:17:37 +0000751 /* Set up BB, including copying of the where-next stuff. */
752 cgs.bbOut = emptyIRBB();
753 cgs.bbOut->tyenv = dopyIRTypeEnv(tyenv);
754 tl_assert( isIRAtom(bbIn->next) );
755 cgs.bbOut->next = dopyIRExpr(bbIn->next);
756 cgs.bbOut->jumpkind = bbIn->jumpkind;
njn6a3009b2005-03-20 00:20:06 +0000757
sewardja9f538c2005-10-23 12:06:55 +0000758 // Copy verbatim any IR preamble preceding the first IMark
njn6a3009b2005-03-20 00:20:06 +0000759 i = 0;
sewardja9f538c2005-10-23 12:06:55 +0000760 while (i < bbIn->stmts_used && bbIn->stmts[i]->tag != Ist_IMark) {
761 addStmtToIRBB( cgs.bbOut, bbIn->stmts[i] );
762 i++;
763 }
764
765 // Get the first statement, and initial cia from it
njn6a3009b2005-03-20 00:20:06 +0000766 tl_assert(bbIn->stmts_used > 0);
sewardja9f538c2005-10-23 12:06:55 +0000767 tl_assert(i < bbIn->stmts_used);
768 st = bbIn->stmts[i];
njn6a3009b2005-03-20 00:20:06 +0000769 tl_assert(Ist_IMark == st->tag);
sewardj5155dec2005-10-12 10:09:23 +0000770 cia = st->Ist.IMark.addr;
njn6a3009b2005-03-20 00:20:06 +0000771
sewardj5155dec2005-10-12 10:09:23 +0000772 // Set up running state and get block info
773 cgs.events_used = 0;
sewardj4ba057c2005-10-18 12:04:18 +0000774 cgs.bbInfo = get_BB_info(bbIn, (Addr)orig_addr_noredir);
sewardj5155dec2005-10-12 10:09:23 +0000775 cgs.bbInfo_i = 0;
njn6a3009b2005-03-20 00:20:06 +0000776
sewardj5155dec2005-10-12 10:09:23 +0000777 if (DEBUG_CG)
778 VG_(printf)("\n\n---------- cg_instrument ----------\n");
njn6a3009b2005-03-20 00:20:06 +0000779
njnfd9f6222005-10-16 00:17:37 +0000780 // Traverse the block, initialising inodes, adding events and flushing as
781 // necessary.
sewardja9f538c2005-10-23 12:06:55 +0000782 for (/*use current i*/; i < bbIn->stmts_used; i++) {
njn6a3009b2005-03-20 00:20:06 +0000783
sewardj5155dec2005-10-12 10:09:23 +0000784 st = bbIn->stmts[i];
785 tl_assert(isFlatIRStmt(st));
njnb3507ea2005-08-02 23:07:02 +0000786
sewardj5155dec2005-10-12 10:09:23 +0000787 switch (st->tag) {
788 case Ist_NoOp:
789 case Ist_AbiHint:
790 case Ist_Put:
791 case Ist_PutI:
792 case Ist_MFence:
793 break;
njn20677cc2005-08-12 23:47:51 +0000794
sewardj5155dec2005-10-12 10:09:23 +0000795 case Ist_IMark:
njnfd9f6222005-10-16 00:17:37 +0000796 cia = st->Ist.IMark.addr;
797 isize = st->Ist.IMark.len;
798
799 // If Vex fails to decode an instruction, the size will be zero.
800 // Pretend otherwise.
801 if (isize == 0) isize = VG_MIN_INSTR_SZB;
802
njna5ad9ba2005-11-10 15:20:37 +0000803 // Sanity-check size.
804 tl_assert( (VG_MIN_INSTR_SZB <= isize && isize <= VG_MAX_INSTR_SZB)
805 || VG_CLREQ_SZB == isize );
njnfd9f6222005-10-16 00:17:37 +0000806
807 // Get space for and init the inode, record it as the current one.
808 // Subsequent Dr/Dw/Dm events from the same instruction will
809 // also use it.
810 curr_inode = setup_InstrInfo(&cgs, cia, isize);
811
812 addEvent_Ir( &cgs, curr_inode );
sewardj5155dec2005-10-12 10:09:23 +0000813 break;
814
815 case Ist_Tmp: {
816 IRExpr* data = st->Ist.Tmp.data;
817 if (data->tag == Iex_Load) {
818 IRExpr* aexpr = data->Iex.Load.addr;
sewardj5155dec2005-10-12 10:09:23 +0000819 // Note also, endianness info is ignored. I guess
820 // that's not interesting.
njnfd9f6222005-10-16 00:17:37 +0000821 addEvent_Dr( &cgs, curr_inode, sizeofIRType(data->Iex.Load.ty),
822 aexpr );
sewardj5155dec2005-10-12 10:09:23 +0000823 }
824 break;
njnb3507ea2005-08-02 23:07:02 +0000825 }
826
sewardj5155dec2005-10-12 10:09:23 +0000827 case Ist_Store: {
828 IRExpr* data = st->Ist.Store.data;
829 IRExpr* aexpr = st->Ist.Store.addr;
njnfd9f6222005-10-16 00:17:37 +0000830 addEvent_Dw( &cgs, curr_inode,
831 sizeofIRType(typeOfIRExpr(tyenv, data)), aexpr );
sewardj5155dec2005-10-12 10:09:23 +0000832 break;
833 }
njnb3507ea2005-08-02 23:07:02 +0000834
sewardj5155dec2005-10-12 10:09:23 +0000835 case Ist_Dirty: {
836 Int dataSize;
837 IRDirty* d = st->Ist.Dirty.details;
838 if (d->mFx != Ifx_None) {
njnfd9f6222005-10-16 00:17:37 +0000839 /* This dirty helper accesses memory. Collect the details. */
sewardj5155dec2005-10-12 10:09:23 +0000840 tl_assert(d->mAddr != NULL);
841 tl_assert(d->mSize != 0);
842 dataSize = d->mSize;
843 // Large (eg. 28B, 108B, 512B on x86) data-sized
844 // instructions will be done inaccurately, but they're
845 // very rare and this avoids errors from hitting more
846 // than two cache lines in the simulation.
847 if (dataSize > MIN_LINE_SIZE)
848 dataSize = MIN_LINE_SIZE;
849 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
njnfd9f6222005-10-16 00:17:37 +0000850 addEvent_Dr( &cgs, curr_inode, dataSize, d->mAddr );
sewardj5155dec2005-10-12 10:09:23 +0000851 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
njnfd9f6222005-10-16 00:17:37 +0000852 addEvent_Dw( &cgs, curr_inode, dataSize, d->mAddr );
sewardj5155dec2005-10-12 10:09:23 +0000853 } else {
854 tl_assert(d->mAddr == NULL);
855 tl_assert(d->mSize == 0);
856 }
857 break;
858 }
njn6a3009b2005-03-20 00:20:06 +0000859
sewardj5155dec2005-10-12 10:09:23 +0000860 case Ist_Exit:
861 /* We may never reach the next statement, so need to flush
862 all outstanding transactions now. */
863 flushEvents( &cgs );
864 break;
865
866 default:
867 tl_assert(0);
868 break;
njnb3507ea2005-08-02 23:07:02 +0000869 }
njn6a3009b2005-03-20 00:20:06 +0000870
sewardj5155dec2005-10-12 10:09:23 +0000871 /* Copy the original statement */
872 addStmtToIRBB( cgs.bbOut, st );
njn6a3009b2005-03-20 00:20:06 +0000873
sewardj5155dec2005-10-12 10:09:23 +0000874 if (DEBUG_CG) {
875 ppIRStmt(st);
876 VG_(printf)("\n");
877 }
878 }
879
880 /* At the end of the bb. Flush outstandings. */
sewardj5155dec2005-10-12 10:09:23 +0000881 flushEvents( &cgs );
882
sewardj5155dec2005-10-12 10:09:23 +0000883 /* done. stay sane ... */
884 tl_assert(cgs.bbInfo_i == cgs.bbInfo->n_instrs);
885
886 if (DEBUG_CG) {
887 VG_(printf)( "goto {");
888 ppIRJumpKind(bbIn->jumpkind);
889 VG_(printf)( "} ");
890 ppIRExpr( bbIn->next );
891 VG_(printf)( "}\n");
892 }
893
894 return cgs.bbOut;
njn14d01ce2004-11-26 11:30:14 +0000895}
njn4f9c9342002-04-29 16:03:24 +0000896
897/*------------------------------------------------------------*/
nethercoteb35a8b92004-09-11 16:45:27 +0000898/*--- Cache configuration ---*/
njn4f9c9342002-04-29 16:03:24 +0000899/*------------------------------------------------------------*/
900
sewardjb5f6f512005-03-10 23:59:00 +0000901#define UNDEFINED_CACHE { -1, -1, -1 }
njn25e49d8e72002-09-23 09:36:25 +0000902
903static cache_t clo_I1_cache = UNDEFINED_CACHE;
904static cache_t clo_D1_cache = UNDEFINED_CACHE;
905static cache_t clo_L2_cache = UNDEFINED_CACHE;
906
njn7cf0bd32002-06-08 13:36:03 +0000907/* Checks cache config is ok; makes it so if not. */
sewardj07133bf2002-06-13 10:25:56 +0000908static
njna1d1a642004-11-26 18:36:02 +0000909void check_cache(cache_t* cache, Char *name)
njn7cf0bd32002-06-08 13:36:03 +0000910{
911 /* First check they're all powers of two */
sewardj07133bf2002-06-13 10:25:56 +0000912 if (-1 == VG_(log2)(cache->size)) {
njn7cf0bd32002-06-08 13:36:03 +0000913 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000914 "error: %s size of %dB not a power of two; aborting.",
915 name, cache->size);
916 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000917 }
918
sewardj07133bf2002-06-13 10:25:56 +0000919 if (-1 == VG_(log2)(cache->assoc)) {
njn7cf0bd32002-06-08 13:36:03 +0000920 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000921 "error: %s associativity of %d not a power of two; aborting.",
922 name, cache->assoc);
923 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000924 }
925
sewardj07133bf2002-06-13 10:25:56 +0000926 if (-1 == VG_(log2)(cache->line_size)) {
njn7cf0bd32002-06-08 13:36:03 +0000927 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000928 "error: %s line size of %dB not a power of two; aborting.",
929 name, cache->line_size);
930 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000931 }
932
njn6a3009b2005-03-20 00:20:06 +0000933 // Then check line size >= 16 -- any smaller and a single instruction could
934 // straddle three cache lines, which breaks a simulation assertion and is
935 // stupid anyway.
njn7cf0bd32002-06-08 13:36:03 +0000936 if (cache->line_size < MIN_LINE_SIZE) {
937 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000938 "error: %s line size of %dB too small; aborting.",
939 name, cache->line_size);
940 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000941 }
942
943 /* Then check cache size > line size (causes seg faults if not). */
944 if (cache->size <= cache->line_size) {
945 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000946 "error: %s cache size of %dB <= line size of %dB; aborting.",
947 name, cache->size, cache->line_size);
948 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000949 }
950
951 /* Then check assoc <= (size / line size) (seg faults otherwise). */
952 if (cache->assoc > (cache->size / cache->line_size)) {
953 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000954 "warning: %s associativity > (size / line size); aborting.", name);
955 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000956 }
957}
958
sewardj07133bf2002-06-13 10:25:56 +0000959static
nethercoteb35a8b92004-09-11 16:45:27 +0000960void configure_caches(cache_t* I1c, cache_t* D1c, cache_t* L2c)
njn7cf0bd32002-06-08 13:36:03 +0000961{
nethercote9313ac42004-07-06 21:54:20 +0000962#define DEFINED(L) (-1 != L.size || -1 != L.assoc || -1 != L.line_size)
963
nethercoteb35a8b92004-09-11 16:45:27 +0000964 Int n_clos = 0;
nethercote9313ac42004-07-06 21:54:20 +0000965
nethercoteb35a8b92004-09-11 16:45:27 +0000966 // Count how many were defined on the command line.
967 if (DEFINED(clo_I1_cache)) { n_clos++; }
968 if (DEFINED(clo_D1_cache)) { n_clos++; }
969 if (DEFINED(clo_L2_cache)) { n_clos++; }
njn7cf0bd32002-06-08 13:36:03 +0000970
njna1d1a642004-11-26 18:36:02 +0000971 // Set the cache config (using auto-detection, if supported by the
972 // architecture)
njnaf839f52005-06-23 03:27:57 +0000973 VG_(configure_caches)( I1c, D1c, L2c, (3 == n_clos) );
sewardjb1a77a42002-07-13 13:31:20 +0000974
nethercote9313ac42004-07-06 21:54:20 +0000975 // Then replace with any defined on the command line.
nethercoteb35a8b92004-09-11 16:45:27 +0000976 if (DEFINED(clo_I1_cache)) { *I1c = clo_I1_cache; }
977 if (DEFINED(clo_D1_cache)) { *D1c = clo_D1_cache; }
978 if (DEFINED(clo_L2_cache)) { *L2c = clo_L2_cache; }
njn7cf0bd32002-06-08 13:36:03 +0000979
nethercote9313ac42004-07-06 21:54:20 +0000980 // Then check values and fix if not acceptable.
njna1d1a642004-11-26 18:36:02 +0000981 check_cache(I1c, "I1");
982 check_cache(D1c, "D1");
983 check_cache(L2c, "L2");
njn7cf0bd32002-06-08 13:36:03 +0000984
985 if (VG_(clo_verbosity) > 1) {
986 VG_(message)(Vg_UserMsg, "Cache configuration used:");
987 VG_(message)(Vg_UserMsg, " I1: %dB, %d-way, %dB lines",
988 I1c->size, I1c->assoc, I1c->line_size);
989 VG_(message)(Vg_UserMsg, " D1: %dB, %d-way, %dB lines",
990 D1c->size, D1c->assoc, D1c->line_size);
991 VG_(message)(Vg_UserMsg, " L2: %dB, %d-way, %dB lines",
992 L2c->size, L2c->assoc, L2c->line_size);
993 }
nethercote9313ac42004-07-06 21:54:20 +0000994#undef CMD_LINE_DEFINED
njn7cf0bd32002-06-08 13:36:03 +0000995}
996
njn4f9c9342002-04-29 16:03:24 +0000997/*------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +0000998/*--- cg_fini() and related function ---*/
njn4f9c9342002-04-29 16:03:24 +0000999/*------------------------------------------------------------*/
1000
nethercote9313ac42004-07-06 21:54:20 +00001001// Total reads/writes/misses. Calculated during CC traversal at the end.
1002// All auto-zeroed.
1003static CC Ir_total;
1004static CC Dr_total;
1005static CC Dw_total;
1006
1007static Char* cachegrind_out_file;
1008
nethercote9313ac42004-07-06 21:54:20 +00001009static void fprint_CC_table_and_calc_totals(void)
1010{
njnd3bef4f2005-10-15 17:46:18 +00001011 Int i, fd;
sewardj92645592005-07-23 09:18:34 +00001012 SysRes sres;
njnd3bef4f2005-10-15 17:46:18 +00001013 Char buf[512], *currFile = NULL, *currFn = NULL;
1014 LineCC* lineCC;
njn4f9c9342002-04-29 16:03:24 +00001015
njn25e49d8e72002-09-23 09:36:25 +00001016 VGP_PUSHCC(VgpCacheResults);
njn13f02932003-04-30 20:23:58 +00001017
sewardj92645592005-07-23 09:18:34 +00001018 sres = VG_(open)(cachegrind_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
1019 VKI_S_IRUSR|VKI_S_IWUSR);
1020 if (sres.isError) {
nethercote9313ac42004-07-06 21:54:20 +00001021 // If the file can't be opened for whatever reason (conflict
1022 // between multiple cachegrinded processes?), give up now.
njnee0e6a32005-04-24 00:21:01 +00001023 VG_(message)(Vg_UserMsg,
njn02bc4b82005-05-15 17:28:26 +00001024 "error: can't open cache simulation output file '%s'",
njnee0e6a32005-04-24 00:21:01 +00001025 cachegrind_out_file );
1026 VG_(message)(Vg_UserMsg,
1027 " ... so simulation results will be missing.");
sewardj0744b6c2002-12-11 00:45:42 +00001028 return;
sewardj92645592005-07-23 09:18:34 +00001029 } else {
1030 fd = sres.val;
sewardj0744b6c2002-12-11 00:45:42 +00001031 }
njn4f9c9342002-04-29 16:03:24 +00001032
nethercote9313ac42004-07-06 21:54:20 +00001033 // "desc:" lines (giving I1/D1/L2 cache configuration). The spaces after
1034 // the 2nd colon makes cg_annotate's output look nicer.
1035 VG_(sprintf)(buf, "desc: I1 cache: %s\n"
1036 "desc: D1 cache: %s\n"
1037 "desc: L2 cache: %s\n",
1038 I1.desc_line, D1.desc_line, L2.desc_line);
njn7cf0bd32002-06-08 13:36:03 +00001039 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njn4f9c9342002-04-29 16:03:24 +00001040
nethercote9313ac42004-07-06 21:54:20 +00001041 // "cmd:" line
njn4f9c9342002-04-29 16:03:24 +00001042 VG_(strcpy)(buf, "cmd:");
1043 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
sewardj45f4e7c2005-09-27 19:20:21 +00001044 if (VG_(args_the_exename)) {
1045 VG_(write)(fd, " ", 1);
1046 VG_(write)(fd, VG_(args_the_exename),
1047 VG_(strlen)( VG_(args_the_exename) ));
1048 }
1049 for (i = 0; i < VG_(args_for_client).used; i++) {
1050 if (VG_(args_for_client).strs[i]) {
1051 VG_(write)(fd, " ", 1);
1052 VG_(write)(fd, VG_(args_for_client).strs[i],
1053 VG_(strlen)(VG_(args_for_client).strs[i]));
1054 }
njn4f9c9342002-04-29 16:03:24 +00001055 }
nethercote9313ac42004-07-06 21:54:20 +00001056 // "events:" line
njn4f9c9342002-04-29 16:03:24 +00001057 VG_(sprintf)(buf, "\nevents: Ir I1mr I2mr Dr D1mr D2mr Dw D1mw D2mw\n");
1058 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1059
njnd3bef4f2005-10-15 17:46:18 +00001060 // Traverse every lineCC
1061 VG_(OSet_ResetIter)(CC_table);
1062 while ( (lineCC = VG_(OSet_Next)(CC_table)) ) {
njn4311fe62005-12-08 23:18:50 +00001063 Bool just_hit_a_new_file = False;
njnd3bef4f2005-10-15 17:46:18 +00001064 // If we've hit a new file, print a "fl=" line. Note that because
1065 // each string is stored exactly once in the string table, we can use
1066 // pointer comparison rather than strcmp() to test for equality, which
1067 // is good because most of the time the comparisons are equal and so
njn4311fe62005-12-08 23:18:50 +00001068 // the whole strings would have to be checked.
njnd3bef4f2005-10-15 17:46:18 +00001069 if ( lineCC->loc.file != currFile ) {
1070 currFile = lineCC->loc.file;
1071 VG_(sprintf)(buf, "fl=%s\n", currFile);
njn4f9c9342002-04-29 16:03:24 +00001072 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njnd3bef4f2005-10-15 17:46:18 +00001073 distinct_files++;
njn4311fe62005-12-08 23:18:50 +00001074 just_hit_a_new_file = True;
njn4f9c9342002-04-29 16:03:24 +00001075 }
njn4311fe62005-12-08 23:18:50 +00001076 // If we've hit a new function, print a "fn=" line. We know to do
1077 // this when the function name changes, and also every time we hit a
1078 // new file (in which case the new function name might be the same as
1079 // in the old file, hence the just_hit_a_new_file test).
1080 if ( just_hit_a_new_file || lineCC->loc.fn != currFn ) {
njnd3bef4f2005-10-15 17:46:18 +00001081 currFn = lineCC->loc.fn;
1082 VG_(sprintf)(buf, "fn=%s\n", currFn);
1083 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1084 distinct_fns++;
njn4311fe62005-12-08 23:18:50 +00001085 just_hit_a_new_file = False;
njnd3bef4f2005-10-15 17:46:18 +00001086 }
1087
1088 // Print the LineCC
1089 VG_(sprintf)(buf, "%u %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
1090 lineCC->loc.line,
1091 lineCC->Ir.a, lineCC->Ir.m1, lineCC->Ir.m2,
1092 lineCC->Dr.a, lineCC->Dr.m1, lineCC->Dr.m2,
1093 lineCC->Dw.a, lineCC->Dw.m1, lineCC->Dw.m2);
1094 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1095
1096 // Update summary stats
1097 Ir_total.a += lineCC->Ir.a;
1098 Ir_total.m1 += lineCC->Ir.m1;
1099 Ir_total.m2 += lineCC->Ir.m2;
1100 Dr_total.a += lineCC->Dr.a;
1101 Dr_total.m1 += lineCC->Dr.m1;
1102 Dr_total.m2 += lineCC->Dr.m2;
1103 Dw_total.a += lineCC->Dw.a;
1104 Dw_total.m1 += lineCC->Dw.m1;
1105 Dw_total.m2 += lineCC->Dw.m2;
1106
1107 distinct_lines++;
njn4f9c9342002-04-29 16:03:24 +00001108 }
1109
nethercote9313ac42004-07-06 21:54:20 +00001110 // Summary stats must come after rest of table, since we calculate them
1111 // during traversal. */
njn4f9c9342002-04-29 16:03:24 +00001112 VG_(sprintf)(buf, "summary: "
nethercote9313ac42004-07-06 21:54:20 +00001113 "%llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
njn4f9c9342002-04-29 16:03:24 +00001114 Ir_total.a, Ir_total.m1, Ir_total.m2,
1115 Dr_total.a, Dr_total.m1, Dr_total.m2,
1116 Dw_total.a, Dw_total.m1, Dw_total.m2);
1117 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1118 VG_(close)(fd);
1119}
1120
njn607adfc2003-09-30 14:15:44 +00001121static UInt ULong_width(ULong n)
njn4f9c9342002-04-29 16:03:24 +00001122{
njn607adfc2003-09-30 14:15:44 +00001123 UInt w = 0;
1124 while (n > 0) {
1125 n = n / 10;
1126 w++;
njn4f9c9342002-04-29 16:03:24 +00001127 }
sewardj46c59b12005-11-01 02:20:19 +00001128 if (w == 0) w = 1;
njn607adfc2003-09-30 14:15:44 +00001129 return w + (w-1)/3; // add space for commas
njn4f9c9342002-04-29 16:03:24 +00001130}
1131
njn51d827b2005-05-09 01:02:08 +00001132static void cg_fini(Int exitcode)
njn4f9c9342002-04-29 16:03:24 +00001133{
njn0103de52005-10-10 16:49:01 +00001134 static Char buf1[128], buf2[128], buf3[128], fmt [128];
njn607adfc2003-09-30 14:15:44 +00001135
njn4f9c9342002-04-29 16:03:24 +00001136 CC D_total;
njn1d021fa2002-05-02 13:56:34 +00001137 ULong L2_total_m, L2_total_mr, L2_total_mw,
1138 L2_total, L2_total_r, L2_total_w;
njn4f9c9342002-04-29 16:03:24 +00001139 Int l1, l2, l3;
1140 Int p;
1141
nethercote9313ac42004-07-06 21:54:20 +00001142 fprint_CC_table_and_calc_totals();
njn4f9c9342002-04-29 16:03:24 +00001143
njn7cf0bd32002-06-08 13:36:03 +00001144 if (VG_(clo_verbosity) == 0)
1145 return;
1146
njn4f9c9342002-04-29 16:03:24 +00001147 /* I cache results. Use the I_refs value to determine the first column
1148 * width. */
njn607adfc2003-09-30 14:15:44 +00001149 l1 = ULong_width(Ir_total.a);
1150 l2 = ULong_width(Dr_total.a);
1151 l3 = ULong_width(Dw_total.a);
njn4f9c9342002-04-29 16:03:24 +00001152
njn607adfc2003-09-30 14:15:44 +00001153 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001154 VG_(sprintf)(fmt, "%%s %%,%dllu", l1);
njnd3bef4f2005-10-15 17:46:18 +00001155
njn607adfc2003-09-30 14:15:44 +00001156 VG_(message)(Vg_UserMsg, fmt, "I refs: ", Ir_total.a);
1157 VG_(message)(Vg_UserMsg, fmt, "I1 misses: ", Ir_total.m1);
1158 VG_(message)(Vg_UserMsg, fmt, "L2i misses: ", Ir_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001159
1160 p = 100;
1161
njn25e49d8e72002-09-23 09:36:25 +00001162 if (0 == Ir_total.a) Ir_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001163 VG_(percentify)(Ir_total.m1, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001164 VG_(message)(Vg_UserMsg, "I1 miss rate: %s", buf1);
njnd3bef4f2005-10-15 17:46:18 +00001165
njn856c54e2005-06-26 18:43:40 +00001166 VG_(percentify)(Ir_total.m2, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001167 VG_(message)(Vg_UserMsg, "L2i miss rate: %s", buf1);
1168 VG_(message)(Vg_UserMsg, "");
1169
1170 /* D cache results. Use the D_refs.rd and D_refs.wr values to determine the
1171 * width of columns 2 & 3. */
1172 D_total.a = Dr_total.a + Dw_total.a;
1173 D_total.m1 = Dr_total.m1 + Dw_total.m1;
1174 D_total.m2 = Dr_total.m2 + Dw_total.m2;
njnd3bef4f2005-10-15 17:46:18 +00001175
njn607adfc2003-09-30 14:15:44 +00001176 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001177 VG_(sprintf)(fmt, "%%s %%,%dllu (%%,%dllu rd + %%,%dllu wr)", l1, l2, l3);
njn4f9c9342002-04-29 16:03:24 +00001178
njn607adfc2003-09-30 14:15:44 +00001179 VG_(message)(Vg_UserMsg, fmt, "D refs: ",
1180 D_total.a, Dr_total.a, Dw_total.a);
1181 VG_(message)(Vg_UserMsg, fmt, "D1 misses: ",
1182 D_total.m1, Dr_total.m1, Dw_total.m1);
1183 VG_(message)(Vg_UserMsg, fmt, "L2d misses: ",
1184 D_total.m2, Dr_total.m2, Dw_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001185
1186 p = 10;
njnd3bef4f2005-10-15 17:46:18 +00001187
njn25e49d8e72002-09-23 09:36:25 +00001188 if (0 == D_total.a) D_total.a = 1;
1189 if (0 == Dr_total.a) Dr_total.a = 1;
1190 if (0 == Dw_total.a) Dw_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001191 VG_(percentify)( D_total.m1, D_total.a, 1, l1+1, buf1);
1192 VG_(percentify)(Dr_total.m1, Dr_total.a, 1, l2+1, buf2);
1193 VG_(percentify)(Dw_total.m1, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001194 VG_(message)(Vg_UserMsg, "D1 miss rate: %s (%s + %s )", buf1, buf2,buf3);
1195
njn856c54e2005-06-26 18:43:40 +00001196 VG_(percentify)( D_total.m2, D_total.a, 1, l1+1, buf1);
1197 VG_(percentify)(Dr_total.m2, Dr_total.a, 1, l2+1, buf2);
1198 VG_(percentify)(Dw_total.m2, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001199 VG_(message)(Vg_UserMsg, "L2d miss rate: %s (%s + %s )", buf1, buf2,buf3);
1200 VG_(message)(Vg_UserMsg, "");
1201
1202 /* L2 overall results */
njn1d021fa2002-05-02 13:56:34 +00001203
1204 L2_total = Dr_total.m1 + Dw_total.m1 + Ir_total.m1;
1205 L2_total_r = Dr_total.m1 + Ir_total.m1;
1206 L2_total_w = Dw_total.m1;
njn607adfc2003-09-30 14:15:44 +00001207 VG_(message)(Vg_UserMsg, fmt, "L2 refs: ",
1208 L2_total, L2_total_r, L2_total_w);
njn1d021fa2002-05-02 13:56:34 +00001209
njn4f9c9342002-04-29 16:03:24 +00001210 L2_total_m = Dr_total.m2 + Dw_total.m2 + Ir_total.m2;
1211 L2_total_mr = Dr_total.m2 + Ir_total.m2;
1212 L2_total_mw = Dw_total.m2;
njn607adfc2003-09-30 14:15:44 +00001213 VG_(message)(Vg_UserMsg, fmt, "L2 misses: ",
1214 L2_total_m, L2_total_mr, L2_total_mw);
njn4f9c9342002-04-29 16:03:24 +00001215
njn856c54e2005-06-26 18:43:40 +00001216 VG_(percentify)(L2_total_m, (Ir_total.a + D_total.a), 1, l1+1, buf1);
1217 VG_(percentify)(L2_total_mr, (Ir_total.a + Dr_total.a), 1, l2+1, buf2);
1218 VG_(percentify)(L2_total_mw, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001219 VG_(message)(Vg_UserMsg, "L2 miss rate: %s (%s + %s )", buf1, buf2,buf3);
njnd3bef4f2005-10-15 17:46:18 +00001220
njn4f9c9342002-04-29 16:03:24 +00001221
nethercote9313ac42004-07-06 21:54:20 +00001222 // Various stats
njn4f9c9342002-04-29 16:03:24 +00001223 if (VG_(clo_verbosity) > 1) {
njnd3bef4f2005-10-15 17:46:18 +00001224 Int debug_lookups = full_debugs + fn_debugs +
1225 file_line_debugs + no_debugs;
1226
njn4f9c9342002-04-29 16:03:24 +00001227 VG_(message)(Vg_DebugMsg, "");
njnd3bef4f2005-10-15 17:46:18 +00001228 VG_(message)(Vg_DebugMsg, "cachegrind: distinct files: %d", distinct_files);
1229 VG_(message)(Vg_DebugMsg, "cachegrind: distinct fns: %d", distinct_fns);
1230 VG_(message)(Vg_DebugMsg, "cachegrind: distinct lines: %d", distinct_lines);
1231 VG_(message)(Vg_DebugMsg, "cachegrind: distinct instrs:%d", distinct_instrs);
1232 VG_(message)(Vg_DebugMsg, "cachegrind: debug lookups : %d", debug_lookups);
1233 VG_(message)(Vg_DebugMsg, "cachegrind: with full info:%3d%% (%d)",
1234 full_debugs * 100 / debug_lookups, full_debugs);
1235 VG_(message)(Vg_DebugMsg, "cachegrind: with file/line info:%3d%% (%d)",
1236 file_line_debugs * 100 / debug_lookups, file_line_debugs);
1237 VG_(message)(Vg_DebugMsg, "cachegrind: with fn name info:%3d%% (%d)",
1238 fn_debugs * 100 / debug_lookups, fn_debugs);
1239 VG_(message)(Vg_DebugMsg, "cachegrind: with zero info:%3d%% (%d)",
1240 no_debugs * 100 / debug_lookups, no_debugs);
njnd3bef4f2005-10-15 17:46:18 +00001241 VG_(message)(Vg_DebugMsg, "cachegrind: string table size: %u",
1242 VG_(OSet_Size)(stringTable));
1243 VG_(message)(Vg_DebugMsg, "cachegrind: CC table size: %u",
1244 VG_(OSet_Size)(CC_table));
1245 VG_(message)(Vg_DebugMsg, "cachegrind: InstrInfo table size: %u",
1246 VG_(OSet_Size)(instrInfoTable));
njn4f9c9342002-04-29 16:03:24 +00001247 }
njn25e49d8e72002-09-23 09:36:25 +00001248 VGP_POPCC(VgpCacheResults);
njn4f9c9342002-04-29 16:03:24 +00001249}
1250
nethercote9313ac42004-07-06 21:54:20 +00001251/*--------------------------------------------------------------------*/
1252/*--- Discarding BB info ---*/
1253/*--------------------------------------------------------------------*/
sewardj18d75132002-05-16 11:06:21 +00001254
sewardja3a29a52005-10-12 16:16:03 +00001255// Called when a translation is removed from the translation cache for
1256// any reason at all: to free up space, because the guest code was
1257// unmapped or modified, or for any arbitrary reason.
sewardj4ba057c2005-10-18 12:04:18 +00001258static
1259void cg_discard_basic_block_info ( Addr64 orig_addr64, VexGuestExtents vge )
sewardj18d75132002-05-16 11:06:21 +00001260{
njnd3bef4f2005-10-15 17:46:18 +00001261 BB_info* bbInfo;
sewardj4ba057c2005-10-18 12:04:18 +00001262 Addr orig_addr = (Addr)orig_addr64;
njn4294fd42002-06-05 14:41:10 +00001263
sewardj5155dec2005-10-12 10:09:23 +00001264 tl_assert(vge.n_used > 0);
1265
1266 if (DEBUG_CG)
sewardj4ba057c2005-10-18 12:04:18 +00001267 VG_(printf)( "discard_basic_block_info: %p, %p, %llu\n",
1268 (void*)(Addr)orig_addr,
sewardj5155dec2005-10-12 10:09:23 +00001269 (void*)(Addr)vge.base[0], (ULong)vge.len[0]);
njn4294fd42002-06-05 14:41:10 +00001270
sewardj4ba057c2005-10-18 12:04:18 +00001271 // Get BB info, remove from table, free BB info. Simple! Note that we
1272 // use orig_addr, not the first instruction address in vge.
1273 bbInfo = VG_(OSet_Remove)(instrInfoTable, &orig_addr);
njn6a3009b2005-03-20 00:20:06 +00001274 tl_assert(NULL != bbInfo);
njnd3bef4f2005-10-15 17:46:18 +00001275 VG_(OSet_FreeNode)(instrInfoTable, bbInfo);
sewardj18d75132002-05-16 11:06:21 +00001276}
1277
1278/*--------------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001279/*--- Command line processing ---*/
1280/*--------------------------------------------------------------------*/
1281
njn0103de52005-10-10 16:49:01 +00001282static void parse_cache_opt ( cache_t* cache, Char* opt )
njn25e49d8e72002-09-23 09:36:25 +00001283{
njn0103de52005-10-10 16:49:01 +00001284 Int i = 0, i2, i3;
njn25e49d8e72002-09-23 09:36:25 +00001285
nethercote9313ac42004-07-06 21:54:20 +00001286 // Option argument looks like "65536,2,64".
1287 // Find commas, replace with NULs to make three independent
1288 // strings, then extract numbers, put NULs back. Yuck.
njn25e49d8e72002-09-23 09:36:25 +00001289 while (VG_(isdigit)(opt[i])) i++;
1290 if (',' == opt[i]) {
1291 opt[i++] = '\0';
1292 i2 = i;
1293 } else goto bad;
1294 while (VG_(isdigit)(opt[i])) i++;
1295 if (',' == opt[i]) {
1296 opt[i++] = '\0';
1297 i3 = i;
1298 } else goto bad;
1299 while (VG_(isdigit)(opt[i])) i++;
1300 if ('\0' != opt[i]) goto bad;
1301
nethercote9313ac42004-07-06 21:54:20 +00001302 cache->size = (Int)VG_(atoll)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001303 cache->assoc = (Int)VG_(atoll)(opt + i2);
1304 cache->line_size = (Int)VG_(atoll)(opt + i3);
1305
nethercote9313ac42004-07-06 21:54:20 +00001306 opt[i2-1] = ',';
1307 opt[i3-1] = ',';
njn25e49d8e72002-09-23 09:36:25 +00001308 return;
1309
1310 bad:
nethercote9313ac42004-07-06 21:54:20 +00001311 VG_(bad_option)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001312}
1313
njn51d827b2005-05-09 01:02:08 +00001314static Bool cg_process_cmd_line_option(Char* arg)
njn25e49d8e72002-09-23 09:36:25 +00001315{
nethercote9313ac42004-07-06 21:54:20 +00001316 // 5 is length of "--I1="
njn39c86652003-05-21 10:13:39 +00001317 if (VG_CLO_STREQN(5, arg, "--I1="))
nethercote9313ac42004-07-06 21:54:20 +00001318 parse_cache_opt(&clo_I1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001319 else if (VG_CLO_STREQN(5, arg, "--D1="))
nethercote9313ac42004-07-06 21:54:20 +00001320 parse_cache_opt(&clo_D1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001321 else if (VG_CLO_STREQN(5, arg, "--L2="))
nethercote9313ac42004-07-06 21:54:20 +00001322 parse_cache_opt(&clo_L2_cache, &arg[5]);
njn25e49d8e72002-09-23 09:36:25 +00001323 else
1324 return False;
1325
1326 return True;
1327}
1328
njn51d827b2005-05-09 01:02:08 +00001329static void cg_print_usage(void)
njn25e49d8e72002-09-23 09:36:25 +00001330{
njn3e884182003-04-15 13:03:23 +00001331 VG_(printf)(
njn25e49d8e72002-09-23 09:36:25 +00001332" --I1=<size>,<assoc>,<line_size> set I1 cache manually\n"
1333" --D1=<size>,<assoc>,<line_size> set D1 cache manually\n"
njn3e884182003-04-15 13:03:23 +00001334" --L2=<size>,<assoc>,<line_size> set L2 cache manually\n"
1335 );
1336}
1337
njn51d827b2005-05-09 01:02:08 +00001338static void cg_print_debug_usage(void)
njn3e884182003-04-15 13:03:23 +00001339{
1340 VG_(printf)(
1341" (none)\n"
1342 );
njn25e49d8e72002-09-23 09:36:25 +00001343}
1344
1345/*--------------------------------------------------------------------*/
1346/*--- Setup ---*/
1347/*--------------------------------------------------------------------*/
1348
njn51d827b2005-05-09 01:02:08 +00001349static void cg_post_clo_init(void)
njn25e49d8e72002-09-23 09:36:25 +00001350{
1351 cache_t I1c, D1c, L2c;
njn25e49d8e72002-09-23 09:36:25 +00001352
nethercoteb35a8b92004-09-11 16:45:27 +00001353 configure_caches(&I1c, &D1c, &L2c);
njn25e49d8e72002-09-23 09:36:25 +00001354
1355 cachesim_I1_initcache(I1c);
1356 cachesim_D1_initcache(D1c);
1357 cachesim_L2_initcache(L2c);
1358
njn31066fd2005-03-26 00:42:02 +00001359 VG_(register_profile_event)(VgpGetLineCC, "get-lineCC");
1360 VG_(register_profile_event)(VgpCacheSimulate, "cache-simulate");
1361 VG_(register_profile_event)(VgpCacheResults, "cache-results");
njn25e49d8e72002-09-23 09:36:25 +00001362}
1363
njn57ca7ab2005-06-21 23:44:58 +00001364static Char base_dir[VKI_PATH_MAX];
1365
njn51d827b2005-05-09 01:02:08 +00001366static void cg_pre_clo_init(void)
1367{
njn51d827b2005-05-09 01:02:08 +00001368 VG_(details_name) ("Cachegrind");
1369 VG_(details_version) (NULL);
1370 VG_(details_description) ("an I1/D1/L2 cache profiler");
1371 VG_(details_copyright_author)(
1372 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote et al.");
1373 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj5155dec2005-10-12 10:09:23 +00001374 VG_(details_avg_translation_sizeB) ( 245 );
njn51d827b2005-05-09 01:02:08 +00001375
1376 VG_(basic_tool_funcs) (cg_post_clo_init,
1377 cg_instrument,
1378 cg_fini);
1379
1380 VG_(needs_basic_block_discards)(cg_discard_basic_block_info);
1381 VG_(needs_command_line_options)(cg_process_cmd_line_option,
1382 cg_print_usage,
1383 cg_print_debug_usage);
1384
1385 /* Get working directory */
njn57ca7ab2005-06-21 23:44:58 +00001386 tl_assert( VG_(getcwd)(base_dir, VKI_PATH_MAX) );
njn51d827b2005-05-09 01:02:08 +00001387
1388 /* Block is big enough for dir name + cachegrind.out.<pid> */
1389 cachegrind_out_file = VG_(malloc)((VG_(strlen)(base_dir) + 32)*sizeof(Char));
1390 VG_(sprintf)(cachegrind_out_file, "%s/cachegrind.out.%d",
1391 base_dir, VG_(getpid)());
njn51d827b2005-05-09 01:02:08 +00001392
njnd3bef4f2005-10-15 17:46:18 +00001393 CC_table = VG_(OSet_Create)(offsetof(LineCC, loc),
1394 cmp_CodeLoc_LineCC,
1395 VG_(malloc), VG_(free));
sewardj4ba057c2005-10-18 12:04:18 +00001396 instrInfoTable = VG_(OSet_Create)(/*keyOff*/0,
njnd3bef4f2005-10-15 17:46:18 +00001397 NULL,
1398 VG_(malloc), VG_(free));
1399 stringTable = VG_(OSet_Create)(/*keyOff*/0,
1400 stringCmp,
1401 VG_(malloc), VG_(free));
njn51d827b2005-05-09 01:02:08 +00001402}
1403
sewardj45f4e7c2005-09-27 19:20:21 +00001404VG_DETERMINE_INTERFACE_VERSION(cg_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00001405
njn25e49d8e72002-09-23 09:36:25 +00001406/*--------------------------------------------------------------------*/
njnf69f9452005-07-03 17:53:11 +00001407/*--- end ---*/
sewardj18d75132002-05-16 11:06:21 +00001408/*--------------------------------------------------------------------*/
njnd3bef4f2005-10-15 17:46:18 +00001409