blob: 99d70696437e68ba4d384d4961f9a4330b308d69 [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)) ) {
1063 // If we've hit a new file, print a "fl=" line. Note that because
1064 // each string is stored exactly once in the string table, we can use
1065 // pointer comparison rather than strcmp() to test for equality, which
1066 // is good because most of the time the comparisons are equal and so
1067 // the whole strings would have to be traversed.
1068 if ( lineCC->loc.file != currFile ) {
1069 currFile = lineCC->loc.file;
1070 VG_(sprintf)(buf, "fl=%s\n", currFile);
njn4f9c9342002-04-29 16:03:24 +00001071 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njnd3bef4f2005-10-15 17:46:18 +00001072 distinct_files++;
njn4f9c9342002-04-29 16:03:24 +00001073 }
njnd3bef4f2005-10-15 17:46:18 +00001074 // If we've hit a new function, print a "fn=" line.
1075 if ( lineCC->loc.fn != currFn ) {
1076 currFn = lineCC->loc.fn;
1077 VG_(sprintf)(buf, "fn=%s\n", currFn);
1078 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1079 distinct_fns++;
1080 }
1081
1082 // Print the LineCC
1083 VG_(sprintf)(buf, "%u %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
1084 lineCC->loc.line,
1085 lineCC->Ir.a, lineCC->Ir.m1, lineCC->Ir.m2,
1086 lineCC->Dr.a, lineCC->Dr.m1, lineCC->Dr.m2,
1087 lineCC->Dw.a, lineCC->Dw.m1, lineCC->Dw.m2);
1088 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1089
1090 // Update summary stats
1091 Ir_total.a += lineCC->Ir.a;
1092 Ir_total.m1 += lineCC->Ir.m1;
1093 Ir_total.m2 += lineCC->Ir.m2;
1094 Dr_total.a += lineCC->Dr.a;
1095 Dr_total.m1 += lineCC->Dr.m1;
1096 Dr_total.m2 += lineCC->Dr.m2;
1097 Dw_total.a += lineCC->Dw.a;
1098 Dw_total.m1 += lineCC->Dw.m1;
1099 Dw_total.m2 += lineCC->Dw.m2;
1100
1101 distinct_lines++;
njn4f9c9342002-04-29 16:03:24 +00001102 }
1103
nethercote9313ac42004-07-06 21:54:20 +00001104 // Summary stats must come after rest of table, since we calculate them
1105 // during traversal. */
njn4f9c9342002-04-29 16:03:24 +00001106 VG_(sprintf)(buf, "summary: "
nethercote9313ac42004-07-06 21:54:20 +00001107 "%llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
njn4f9c9342002-04-29 16:03:24 +00001108 Ir_total.a, Ir_total.m1, Ir_total.m2,
1109 Dr_total.a, Dr_total.m1, Dr_total.m2,
1110 Dw_total.a, Dw_total.m1, Dw_total.m2);
1111 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1112 VG_(close)(fd);
1113}
1114
njn607adfc2003-09-30 14:15:44 +00001115static UInt ULong_width(ULong n)
njn4f9c9342002-04-29 16:03:24 +00001116{
njn607adfc2003-09-30 14:15:44 +00001117 UInt w = 0;
1118 while (n > 0) {
1119 n = n / 10;
1120 w++;
njn4f9c9342002-04-29 16:03:24 +00001121 }
sewardj46c59b12005-11-01 02:20:19 +00001122 if (w == 0) w = 1;
njn607adfc2003-09-30 14:15:44 +00001123 return w + (w-1)/3; // add space for commas
njn4f9c9342002-04-29 16:03:24 +00001124}
1125
njn51d827b2005-05-09 01:02:08 +00001126static void cg_fini(Int exitcode)
njn4f9c9342002-04-29 16:03:24 +00001127{
njn0103de52005-10-10 16:49:01 +00001128 static Char buf1[128], buf2[128], buf3[128], fmt [128];
njn607adfc2003-09-30 14:15:44 +00001129
njn4f9c9342002-04-29 16:03:24 +00001130 CC D_total;
njn1d021fa2002-05-02 13:56:34 +00001131 ULong L2_total_m, L2_total_mr, L2_total_mw,
1132 L2_total, L2_total_r, L2_total_w;
njn4f9c9342002-04-29 16:03:24 +00001133 Int l1, l2, l3;
1134 Int p;
1135
nethercote9313ac42004-07-06 21:54:20 +00001136 fprint_CC_table_and_calc_totals();
njn4f9c9342002-04-29 16:03:24 +00001137
njn7cf0bd32002-06-08 13:36:03 +00001138 if (VG_(clo_verbosity) == 0)
1139 return;
1140
njn4f9c9342002-04-29 16:03:24 +00001141 /* I cache results. Use the I_refs value to determine the first column
1142 * width. */
njn607adfc2003-09-30 14:15:44 +00001143 l1 = ULong_width(Ir_total.a);
1144 l2 = ULong_width(Dr_total.a);
1145 l3 = ULong_width(Dw_total.a);
njn4f9c9342002-04-29 16:03:24 +00001146
njn607adfc2003-09-30 14:15:44 +00001147 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001148 VG_(sprintf)(fmt, "%%s %%,%dllu", l1);
njnd3bef4f2005-10-15 17:46:18 +00001149
njn607adfc2003-09-30 14:15:44 +00001150 VG_(message)(Vg_UserMsg, fmt, "I refs: ", Ir_total.a);
1151 VG_(message)(Vg_UserMsg, fmt, "I1 misses: ", Ir_total.m1);
1152 VG_(message)(Vg_UserMsg, fmt, "L2i misses: ", Ir_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001153
1154 p = 100;
1155
njn25e49d8e72002-09-23 09:36:25 +00001156 if (0 == Ir_total.a) Ir_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001157 VG_(percentify)(Ir_total.m1, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001158 VG_(message)(Vg_UserMsg, "I1 miss rate: %s", buf1);
njnd3bef4f2005-10-15 17:46:18 +00001159
njn856c54e2005-06-26 18:43:40 +00001160 VG_(percentify)(Ir_total.m2, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001161 VG_(message)(Vg_UserMsg, "L2i miss rate: %s", buf1);
1162 VG_(message)(Vg_UserMsg, "");
1163
1164 /* D cache results. Use the D_refs.rd and D_refs.wr values to determine the
1165 * width of columns 2 & 3. */
1166 D_total.a = Dr_total.a + Dw_total.a;
1167 D_total.m1 = Dr_total.m1 + Dw_total.m1;
1168 D_total.m2 = Dr_total.m2 + Dw_total.m2;
njnd3bef4f2005-10-15 17:46:18 +00001169
njn607adfc2003-09-30 14:15:44 +00001170 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001171 VG_(sprintf)(fmt, "%%s %%,%dllu (%%,%dllu rd + %%,%dllu wr)", l1, l2, l3);
njn4f9c9342002-04-29 16:03:24 +00001172
njn607adfc2003-09-30 14:15:44 +00001173 VG_(message)(Vg_UserMsg, fmt, "D refs: ",
1174 D_total.a, Dr_total.a, Dw_total.a);
1175 VG_(message)(Vg_UserMsg, fmt, "D1 misses: ",
1176 D_total.m1, Dr_total.m1, Dw_total.m1);
1177 VG_(message)(Vg_UserMsg, fmt, "L2d misses: ",
1178 D_total.m2, Dr_total.m2, Dw_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001179
1180 p = 10;
njnd3bef4f2005-10-15 17:46:18 +00001181
njn25e49d8e72002-09-23 09:36:25 +00001182 if (0 == D_total.a) D_total.a = 1;
1183 if (0 == Dr_total.a) Dr_total.a = 1;
1184 if (0 == Dw_total.a) Dw_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001185 VG_(percentify)( D_total.m1, D_total.a, 1, l1+1, buf1);
1186 VG_(percentify)(Dr_total.m1, Dr_total.a, 1, l2+1, buf2);
1187 VG_(percentify)(Dw_total.m1, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001188 VG_(message)(Vg_UserMsg, "D1 miss rate: %s (%s + %s )", buf1, buf2,buf3);
1189
njn856c54e2005-06-26 18:43:40 +00001190 VG_(percentify)( D_total.m2, D_total.a, 1, l1+1, buf1);
1191 VG_(percentify)(Dr_total.m2, Dr_total.a, 1, l2+1, buf2);
1192 VG_(percentify)(Dw_total.m2, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001193 VG_(message)(Vg_UserMsg, "L2d miss rate: %s (%s + %s )", buf1, buf2,buf3);
1194 VG_(message)(Vg_UserMsg, "");
1195
1196 /* L2 overall results */
njn1d021fa2002-05-02 13:56:34 +00001197
1198 L2_total = Dr_total.m1 + Dw_total.m1 + Ir_total.m1;
1199 L2_total_r = Dr_total.m1 + Ir_total.m1;
1200 L2_total_w = Dw_total.m1;
njn607adfc2003-09-30 14:15:44 +00001201 VG_(message)(Vg_UserMsg, fmt, "L2 refs: ",
1202 L2_total, L2_total_r, L2_total_w);
njn1d021fa2002-05-02 13:56:34 +00001203
njn4f9c9342002-04-29 16:03:24 +00001204 L2_total_m = Dr_total.m2 + Dw_total.m2 + Ir_total.m2;
1205 L2_total_mr = Dr_total.m2 + Ir_total.m2;
1206 L2_total_mw = Dw_total.m2;
njn607adfc2003-09-30 14:15:44 +00001207 VG_(message)(Vg_UserMsg, fmt, "L2 misses: ",
1208 L2_total_m, L2_total_mr, L2_total_mw);
njn4f9c9342002-04-29 16:03:24 +00001209
njn856c54e2005-06-26 18:43:40 +00001210 VG_(percentify)(L2_total_m, (Ir_total.a + D_total.a), 1, l1+1, buf1);
1211 VG_(percentify)(L2_total_mr, (Ir_total.a + Dr_total.a), 1, l2+1, buf2);
1212 VG_(percentify)(L2_total_mw, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001213 VG_(message)(Vg_UserMsg, "L2 miss rate: %s (%s + %s )", buf1, buf2,buf3);
njnd3bef4f2005-10-15 17:46:18 +00001214
njn4f9c9342002-04-29 16:03:24 +00001215
nethercote9313ac42004-07-06 21:54:20 +00001216 // Various stats
njn4f9c9342002-04-29 16:03:24 +00001217 if (VG_(clo_verbosity) > 1) {
njnd3bef4f2005-10-15 17:46:18 +00001218 Int debug_lookups = full_debugs + fn_debugs +
1219 file_line_debugs + no_debugs;
1220
njn4f9c9342002-04-29 16:03:24 +00001221 VG_(message)(Vg_DebugMsg, "");
njnd3bef4f2005-10-15 17:46:18 +00001222 VG_(message)(Vg_DebugMsg, "cachegrind: distinct files: %d", distinct_files);
1223 VG_(message)(Vg_DebugMsg, "cachegrind: distinct fns: %d", distinct_fns);
1224 VG_(message)(Vg_DebugMsg, "cachegrind: distinct lines: %d", distinct_lines);
1225 VG_(message)(Vg_DebugMsg, "cachegrind: distinct instrs:%d", distinct_instrs);
1226 VG_(message)(Vg_DebugMsg, "cachegrind: debug lookups : %d", debug_lookups);
1227 VG_(message)(Vg_DebugMsg, "cachegrind: with full info:%3d%% (%d)",
1228 full_debugs * 100 / debug_lookups, full_debugs);
1229 VG_(message)(Vg_DebugMsg, "cachegrind: with file/line info:%3d%% (%d)",
1230 file_line_debugs * 100 / debug_lookups, file_line_debugs);
1231 VG_(message)(Vg_DebugMsg, "cachegrind: with fn name info:%3d%% (%d)",
1232 fn_debugs * 100 / debug_lookups, fn_debugs);
1233 VG_(message)(Vg_DebugMsg, "cachegrind: with zero info:%3d%% (%d)",
1234 no_debugs * 100 / debug_lookups, no_debugs);
njnd3bef4f2005-10-15 17:46:18 +00001235 VG_(message)(Vg_DebugMsg, "cachegrind: string table size: %u",
1236 VG_(OSet_Size)(stringTable));
1237 VG_(message)(Vg_DebugMsg, "cachegrind: CC table size: %u",
1238 VG_(OSet_Size)(CC_table));
1239 VG_(message)(Vg_DebugMsg, "cachegrind: InstrInfo table size: %u",
1240 VG_(OSet_Size)(instrInfoTable));
njn4f9c9342002-04-29 16:03:24 +00001241 }
njn25e49d8e72002-09-23 09:36:25 +00001242 VGP_POPCC(VgpCacheResults);
njn4f9c9342002-04-29 16:03:24 +00001243}
1244
nethercote9313ac42004-07-06 21:54:20 +00001245/*--------------------------------------------------------------------*/
1246/*--- Discarding BB info ---*/
1247/*--------------------------------------------------------------------*/
sewardj18d75132002-05-16 11:06:21 +00001248
sewardja3a29a52005-10-12 16:16:03 +00001249// Called when a translation is removed from the translation cache for
1250// any reason at all: to free up space, because the guest code was
1251// unmapped or modified, or for any arbitrary reason.
sewardj4ba057c2005-10-18 12:04:18 +00001252static
1253void cg_discard_basic_block_info ( Addr64 orig_addr64, VexGuestExtents vge )
sewardj18d75132002-05-16 11:06:21 +00001254{
njnd3bef4f2005-10-15 17:46:18 +00001255 BB_info* bbInfo;
sewardj4ba057c2005-10-18 12:04:18 +00001256 Addr orig_addr = (Addr)orig_addr64;
njn4294fd42002-06-05 14:41:10 +00001257
sewardj5155dec2005-10-12 10:09:23 +00001258 tl_assert(vge.n_used > 0);
1259
1260 if (DEBUG_CG)
sewardj4ba057c2005-10-18 12:04:18 +00001261 VG_(printf)( "discard_basic_block_info: %p, %p, %llu\n",
1262 (void*)(Addr)orig_addr,
sewardj5155dec2005-10-12 10:09:23 +00001263 (void*)(Addr)vge.base[0], (ULong)vge.len[0]);
njn4294fd42002-06-05 14:41:10 +00001264
sewardj4ba057c2005-10-18 12:04:18 +00001265 // Get BB info, remove from table, free BB info. Simple! Note that we
1266 // use orig_addr, not the first instruction address in vge.
1267 bbInfo = VG_(OSet_Remove)(instrInfoTable, &orig_addr);
njn6a3009b2005-03-20 00:20:06 +00001268 tl_assert(NULL != bbInfo);
njnd3bef4f2005-10-15 17:46:18 +00001269 VG_(OSet_FreeNode)(instrInfoTable, bbInfo);
sewardj18d75132002-05-16 11:06:21 +00001270}
1271
1272/*--------------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001273/*--- Command line processing ---*/
1274/*--------------------------------------------------------------------*/
1275
njn0103de52005-10-10 16:49:01 +00001276static void parse_cache_opt ( cache_t* cache, Char* opt )
njn25e49d8e72002-09-23 09:36:25 +00001277{
njn0103de52005-10-10 16:49:01 +00001278 Int i = 0, i2, i3;
njn25e49d8e72002-09-23 09:36:25 +00001279
nethercote9313ac42004-07-06 21:54:20 +00001280 // Option argument looks like "65536,2,64".
1281 // Find commas, replace with NULs to make three independent
1282 // strings, then extract numbers, put NULs back. Yuck.
njn25e49d8e72002-09-23 09:36:25 +00001283 while (VG_(isdigit)(opt[i])) i++;
1284 if (',' == opt[i]) {
1285 opt[i++] = '\0';
1286 i2 = i;
1287 } else goto bad;
1288 while (VG_(isdigit)(opt[i])) i++;
1289 if (',' == opt[i]) {
1290 opt[i++] = '\0';
1291 i3 = i;
1292 } else goto bad;
1293 while (VG_(isdigit)(opt[i])) i++;
1294 if ('\0' != opt[i]) goto bad;
1295
nethercote9313ac42004-07-06 21:54:20 +00001296 cache->size = (Int)VG_(atoll)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001297 cache->assoc = (Int)VG_(atoll)(opt + i2);
1298 cache->line_size = (Int)VG_(atoll)(opt + i3);
1299
nethercote9313ac42004-07-06 21:54:20 +00001300 opt[i2-1] = ',';
1301 opt[i3-1] = ',';
njn25e49d8e72002-09-23 09:36:25 +00001302 return;
1303
1304 bad:
nethercote9313ac42004-07-06 21:54:20 +00001305 VG_(bad_option)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001306}
1307
njn51d827b2005-05-09 01:02:08 +00001308static Bool cg_process_cmd_line_option(Char* arg)
njn25e49d8e72002-09-23 09:36:25 +00001309{
nethercote9313ac42004-07-06 21:54:20 +00001310 // 5 is length of "--I1="
njn39c86652003-05-21 10:13:39 +00001311 if (VG_CLO_STREQN(5, arg, "--I1="))
nethercote9313ac42004-07-06 21:54:20 +00001312 parse_cache_opt(&clo_I1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001313 else if (VG_CLO_STREQN(5, arg, "--D1="))
nethercote9313ac42004-07-06 21:54:20 +00001314 parse_cache_opt(&clo_D1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001315 else if (VG_CLO_STREQN(5, arg, "--L2="))
nethercote9313ac42004-07-06 21:54:20 +00001316 parse_cache_opt(&clo_L2_cache, &arg[5]);
njn25e49d8e72002-09-23 09:36:25 +00001317 else
1318 return False;
1319
1320 return True;
1321}
1322
njn51d827b2005-05-09 01:02:08 +00001323static void cg_print_usage(void)
njn25e49d8e72002-09-23 09:36:25 +00001324{
njn3e884182003-04-15 13:03:23 +00001325 VG_(printf)(
njn25e49d8e72002-09-23 09:36:25 +00001326" --I1=<size>,<assoc>,<line_size> set I1 cache manually\n"
1327" --D1=<size>,<assoc>,<line_size> set D1 cache manually\n"
njn3e884182003-04-15 13:03:23 +00001328" --L2=<size>,<assoc>,<line_size> set L2 cache manually\n"
1329 );
1330}
1331
njn51d827b2005-05-09 01:02:08 +00001332static void cg_print_debug_usage(void)
njn3e884182003-04-15 13:03:23 +00001333{
1334 VG_(printf)(
1335" (none)\n"
1336 );
njn25e49d8e72002-09-23 09:36:25 +00001337}
1338
1339/*--------------------------------------------------------------------*/
1340/*--- Setup ---*/
1341/*--------------------------------------------------------------------*/
1342
njn51d827b2005-05-09 01:02:08 +00001343static void cg_post_clo_init(void)
njn25e49d8e72002-09-23 09:36:25 +00001344{
1345 cache_t I1c, D1c, L2c;
njn25e49d8e72002-09-23 09:36:25 +00001346
nethercoteb35a8b92004-09-11 16:45:27 +00001347 configure_caches(&I1c, &D1c, &L2c);
njn25e49d8e72002-09-23 09:36:25 +00001348
1349 cachesim_I1_initcache(I1c);
1350 cachesim_D1_initcache(D1c);
1351 cachesim_L2_initcache(L2c);
1352
njn31066fd2005-03-26 00:42:02 +00001353 VG_(register_profile_event)(VgpGetLineCC, "get-lineCC");
1354 VG_(register_profile_event)(VgpCacheSimulate, "cache-simulate");
1355 VG_(register_profile_event)(VgpCacheResults, "cache-results");
njn25e49d8e72002-09-23 09:36:25 +00001356}
1357
njn57ca7ab2005-06-21 23:44:58 +00001358static Char base_dir[VKI_PATH_MAX];
1359
njn51d827b2005-05-09 01:02:08 +00001360static void cg_pre_clo_init(void)
1361{
njn51d827b2005-05-09 01:02:08 +00001362 VG_(details_name) ("Cachegrind");
1363 VG_(details_version) (NULL);
1364 VG_(details_description) ("an I1/D1/L2 cache profiler");
1365 VG_(details_copyright_author)(
1366 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote et al.");
1367 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj5155dec2005-10-12 10:09:23 +00001368 VG_(details_avg_translation_sizeB) ( 245 );
njn51d827b2005-05-09 01:02:08 +00001369
1370 VG_(basic_tool_funcs) (cg_post_clo_init,
1371 cg_instrument,
1372 cg_fini);
1373
1374 VG_(needs_basic_block_discards)(cg_discard_basic_block_info);
1375 VG_(needs_command_line_options)(cg_process_cmd_line_option,
1376 cg_print_usage,
1377 cg_print_debug_usage);
1378
1379 /* Get working directory */
njn57ca7ab2005-06-21 23:44:58 +00001380 tl_assert( VG_(getcwd)(base_dir, VKI_PATH_MAX) );
njn51d827b2005-05-09 01:02:08 +00001381
1382 /* Block is big enough for dir name + cachegrind.out.<pid> */
1383 cachegrind_out_file = VG_(malloc)((VG_(strlen)(base_dir) + 32)*sizeof(Char));
1384 VG_(sprintf)(cachegrind_out_file, "%s/cachegrind.out.%d",
1385 base_dir, VG_(getpid)());
njn51d827b2005-05-09 01:02:08 +00001386
njnd3bef4f2005-10-15 17:46:18 +00001387 CC_table = VG_(OSet_Create)(offsetof(LineCC, loc),
1388 cmp_CodeLoc_LineCC,
1389 VG_(malloc), VG_(free));
sewardj4ba057c2005-10-18 12:04:18 +00001390 instrInfoTable = VG_(OSet_Create)(/*keyOff*/0,
njnd3bef4f2005-10-15 17:46:18 +00001391 NULL,
1392 VG_(malloc), VG_(free));
1393 stringTable = VG_(OSet_Create)(/*keyOff*/0,
1394 stringCmp,
1395 VG_(malloc), VG_(free));
njn51d827b2005-05-09 01:02:08 +00001396}
1397
sewardj45f4e7c2005-09-27 19:20:21 +00001398VG_DETERMINE_INTERFACE_VERSION(cg_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00001399
njn25e49d8e72002-09-23 09:36:25 +00001400/*--------------------------------------------------------------------*/
njnf69f9452005-07-03 17:53:11 +00001401/*--- end ---*/
sewardj18d75132002-05-16 11:06:21 +00001402/*--------------------------------------------------------------------*/
njnd3bef4f2005-10-15 17:46:18 +00001403