blob: ec493c7656b4d2977b8431f15853ee75997c525c [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
803 // Check size. XXX: broken for client requests!
804 tl_assert(VG_MIN_INSTR_SZB <= isize && isize <= VG_MAX_INSTR_SZB);
805
806 // Get space for and init the inode, record it as the current one.
807 // Subsequent Dr/Dw/Dm events from the same instruction will
808 // also use it.
809 curr_inode = setup_InstrInfo(&cgs, cia, isize);
810
811 addEvent_Ir( &cgs, curr_inode );
sewardj5155dec2005-10-12 10:09:23 +0000812 break;
813
814 case Ist_Tmp: {
815 IRExpr* data = st->Ist.Tmp.data;
816 if (data->tag == Iex_Load) {
817 IRExpr* aexpr = data->Iex.Load.addr;
sewardj5155dec2005-10-12 10:09:23 +0000818 // Note also, endianness info is ignored. I guess
819 // that's not interesting.
njnfd9f6222005-10-16 00:17:37 +0000820 addEvent_Dr( &cgs, curr_inode, sizeofIRType(data->Iex.Load.ty),
821 aexpr );
sewardj5155dec2005-10-12 10:09:23 +0000822 }
823 break;
njnb3507ea2005-08-02 23:07:02 +0000824 }
825
sewardj5155dec2005-10-12 10:09:23 +0000826 case Ist_Store: {
827 IRExpr* data = st->Ist.Store.data;
828 IRExpr* aexpr = st->Ist.Store.addr;
njnfd9f6222005-10-16 00:17:37 +0000829 addEvent_Dw( &cgs, curr_inode,
830 sizeofIRType(typeOfIRExpr(tyenv, data)), aexpr );
sewardj5155dec2005-10-12 10:09:23 +0000831 break;
832 }
njnb3507ea2005-08-02 23:07:02 +0000833
sewardj5155dec2005-10-12 10:09:23 +0000834 case Ist_Dirty: {
835 Int dataSize;
836 IRDirty* d = st->Ist.Dirty.details;
837 if (d->mFx != Ifx_None) {
njnfd9f6222005-10-16 00:17:37 +0000838 /* This dirty helper accesses memory. Collect the details. */
sewardj5155dec2005-10-12 10:09:23 +0000839 tl_assert(d->mAddr != NULL);
840 tl_assert(d->mSize != 0);
841 dataSize = d->mSize;
842 // Large (eg. 28B, 108B, 512B on x86) data-sized
843 // instructions will be done inaccurately, but they're
844 // very rare and this avoids errors from hitting more
845 // than two cache lines in the simulation.
846 if (dataSize > MIN_LINE_SIZE)
847 dataSize = MIN_LINE_SIZE;
848 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
njnfd9f6222005-10-16 00:17:37 +0000849 addEvent_Dr( &cgs, curr_inode, dataSize, d->mAddr );
sewardj5155dec2005-10-12 10:09:23 +0000850 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
njnfd9f6222005-10-16 00:17:37 +0000851 addEvent_Dw( &cgs, curr_inode, dataSize, d->mAddr );
sewardj5155dec2005-10-12 10:09:23 +0000852 } else {
853 tl_assert(d->mAddr == NULL);
854 tl_assert(d->mSize == 0);
855 }
856 break;
857 }
njn6a3009b2005-03-20 00:20:06 +0000858
sewardj5155dec2005-10-12 10:09:23 +0000859 case Ist_Exit:
860 /* We may never reach the next statement, so need to flush
861 all outstanding transactions now. */
862 flushEvents( &cgs );
863 break;
864
865 default:
866 tl_assert(0);
867 break;
njnb3507ea2005-08-02 23:07:02 +0000868 }
njn6a3009b2005-03-20 00:20:06 +0000869
sewardj5155dec2005-10-12 10:09:23 +0000870 /* Copy the original statement */
871 addStmtToIRBB( cgs.bbOut, st );
njn6a3009b2005-03-20 00:20:06 +0000872
sewardj5155dec2005-10-12 10:09:23 +0000873 if (DEBUG_CG) {
874 ppIRStmt(st);
875 VG_(printf)("\n");
876 }
877 }
878
879 /* At the end of the bb. Flush outstandings. */
sewardj5155dec2005-10-12 10:09:23 +0000880 flushEvents( &cgs );
881
sewardj5155dec2005-10-12 10:09:23 +0000882 /* done. stay sane ... */
883 tl_assert(cgs.bbInfo_i == cgs.bbInfo->n_instrs);
884
885 if (DEBUG_CG) {
886 VG_(printf)( "goto {");
887 ppIRJumpKind(bbIn->jumpkind);
888 VG_(printf)( "} ");
889 ppIRExpr( bbIn->next );
890 VG_(printf)( "}\n");
891 }
892
893 return cgs.bbOut;
njn14d01ce2004-11-26 11:30:14 +0000894}
njn4f9c9342002-04-29 16:03:24 +0000895
896/*------------------------------------------------------------*/
nethercoteb35a8b92004-09-11 16:45:27 +0000897/*--- Cache configuration ---*/
njn4f9c9342002-04-29 16:03:24 +0000898/*------------------------------------------------------------*/
899
sewardjb5f6f512005-03-10 23:59:00 +0000900#define UNDEFINED_CACHE { -1, -1, -1 }
njn25e49d8e72002-09-23 09:36:25 +0000901
902static cache_t clo_I1_cache = UNDEFINED_CACHE;
903static cache_t clo_D1_cache = UNDEFINED_CACHE;
904static cache_t clo_L2_cache = UNDEFINED_CACHE;
905
njn7cf0bd32002-06-08 13:36:03 +0000906/* Checks cache config is ok; makes it so if not. */
sewardj07133bf2002-06-13 10:25:56 +0000907static
njna1d1a642004-11-26 18:36:02 +0000908void check_cache(cache_t* cache, Char *name)
njn7cf0bd32002-06-08 13:36:03 +0000909{
910 /* First check they're all powers of two */
sewardj07133bf2002-06-13 10:25:56 +0000911 if (-1 == VG_(log2)(cache->size)) {
njn7cf0bd32002-06-08 13:36:03 +0000912 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000913 "error: %s size of %dB not a power of two; aborting.",
914 name, cache->size);
915 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000916 }
917
sewardj07133bf2002-06-13 10:25:56 +0000918 if (-1 == VG_(log2)(cache->assoc)) {
njn7cf0bd32002-06-08 13:36:03 +0000919 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000920 "error: %s associativity of %d not a power of two; aborting.",
921 name, cache->assoc);
922 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000923 }
924
sewardj07133bf2002-06-13 10:25:56 +0000925 if (-1 == VG_(log2)(cache->line_size)) {
njn7cf0bd32002-06-08 13:36:03 +0000926 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000927 "error: %s line size of %dB not a power of two; aborting.",
928 name, cache->line_size);
929 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000930 }
931
njn6a3009b2005-03-20 00:20:06 +0000932 // Then check line size >= 16 -- any smaller and a single instruction could
933 // straddle three cache lines, which breaks a simulation assertion and is
934 // stupid anyway.
njn7cf0bd32002-06-08 13:36:03 +0000935 if (cache->line_size < MIN_LINE_SIZE) {
936 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000937 "error: %s line size of %dB too small; aborting.",
938 name, cache->line_size);
939 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000940 }
941
942 /* Then check cache size > line size (causes seg faults if not). */
943 if (cache->size <= cache->line_size) {
944 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000945 "error: %s cache size of %dB <= line size of %dB; aborting.",
946 name, cache->size, cache->line_size);
947 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000948 }
949
950 /* Then check assoc <= (size / line size) (seg faults otherwise). */
951 if (cache->assoc > (cache->size / cache->line_size)) {
952 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +0000953 "warning: %s associativity > (size / line size); aborting.", name);
954 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +0000955 }
956}
957
sewardj07133bf2002-06-13 10:25:56 +0000958static
nethercoteb35a8b92004-09-11 16:45:27 +0000959void configure_caches(cache_t* I1c, cache_t* D1c, cache_t* L2c)
njn7cf0bd32002-06-08 13:36:03 +0000960{
nethercote9313ac42004-07-06 21:54:20 +0000961#define DEFINED(L) (-1 != L.size || -1 != L.assoc || -1 != L.line_size)
962
nethercoteb35a8b92004-09-11 16:45:27 +0000963 Int n_clos = 0;
nethercote9313ac42004-07-06 21:54:20 +0000964
nethercoteb35a8b92004-09-11 16:45:27 +0000965 // Count how many were defined on the command line.
966 if (DEFINED(clo_I1_cache)) { n_clos++; }
967 if (DEFINED(clo_D1_cache)) { n_clos++; }
968 if (DEFINED(clo_L2_cache)) { n_clos++; }
njn7cf0bd32002-06-08 13:36:03 +0000969
njna1d1a642004-11-26 18:36:02 +0000970 // Set the cache config (using auto-detection, if supported by the
971 // architecture)
njnaf839f52005-06-23 03:27:57 +0000972 VG_(configure_caches)( I1c, D1c, L2c, (3 == n_clos) );
sewardjb1a77a42002-07-13 13:31:20 +0000973
nethercote9313ac42004-07-06 21:54:20 +0000974 // Then replace with any defined on the command line.
nethercoteb35a8b92004-09-11 16:45:27 +0000975 if (DEFINED(clo_I1_cache)) { *I1c = clo_I1_cache; }
976 if (DEFINED(clo_D1_cache)) { *D1c = clo_D1_cache; }
977 if (DEFINED(clo_L2_cache)) { *L2c = clo_L2_cache; }
njn7cf0bd32002-06-08 13:36:03 +0000978
nethercote9313ac42004-07-06 21:54:20 +0000979 // Then check values and fix if not acceptable.
njna1d1a642004-11-26 18:36:02 +0000980 check_cache(I1c, "I1");
981 check_cache(D1c, "D1");
982 check_cache(L2c, "L2");
njn7cf0bd32002-06-08 13:36:03 +0000983
984 if (VG_(clo_verbosity) > 1) {
985 VG_(message)(Vg_UserMsg, "Cache configuration used:");
986 VG_(message)(Vg_UserMsg, " I1: %dB, %d-way, %dB lines",
987 I1c->size, I1c->assoc, I1c->line_size);
988 VG_(message)(Vg_UserMsg, " D1: %dB, %d-way, %dB lines",
989 D1c->size, D1c->assoc, D1c->line_size);
990 VG_(message)(Vg_UserMsg, " L2: %dB, %d-way, %dB lines",
991 L2c->size, L2c->assoc, L2c->line_size);
992 }
nethercote9313ac42004-07-06 21:54:20 +0000993#undef CMD_LINE_DEFINED
njn7cf0bd32002-06-08 13:36:03 +0000994}
995
njn4f9c9342002-04-29 16:03:24 +0000996/*------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +0000997/*--- cg_fini() and related function ---*/
njn4f9c9342002-04-29 16:03:24 +0000998/*------------------------------------------------------------*/
999
nethercote9313ac42004-07-06 21:54:20 +00001000// Total reads/writes/misses. Calculated during CC traversal at the end.
1001// All auto-zeroed.
1002static CC Ir_total;
1003static CC Dr_total;
1004static CC Dw_total;
1005
1006static Char* cachegrind_out_file;
1007
nethercote9313ac42004-07-06 21:54:20 +00001008static void fprint_CC_table_and_calc_totals(void)
1009{
njnd3bef4f2005-10-15 17:46:18 +00001010 Int i, fd;
sewardj92645592005-07-23 09:18:34 +00001011 SysRes sres;
njnd3bef4f2005-10-15 17:46:18 +00001012 Char buf[512], *currFile = NULL, *currFn = NULL;
1013 LineCC* lineCC;
njn4f9c9342002-04-29 16:03:24 +00001014
njn25e49d8e72002-09-23 09:36:25 +00001015 VGP_PUSHCC(VgpCacheResults);
njn13f02932003-04-30 20:23:58 +00001016
sewardj92645592005-07-23 09:18:34 +00001017 sres = VG_(open)(cachegrind_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
1018 VKI_S_IRUSR|VKI_S_IWUSR);
1019 if (sres.isError) {
nethercote9313ac42004-07-06 21:54:20 +00001020 // If the file can't be opened for whatever reason (conflict
1021 // between multiple cachegrinded processes?), give up now.
njnee0e6a32005-04-24 00:21:01 +00001022 VG_(message)(Vg_UserMsg,
njn02bc4b82005-05-15 17:28:26 +00001023 "error: can't open cache simulation output file '%s'",
njnee0e6a32005-04-24 00:21:01 +00001024 cachegrind_out_file );
1025 VG_(message)(Vg_UserMsg,
1026 " ... so simulation results will be missing.");
sewardj0744b6c2002-12-11 00:45:42 +00001027 return;
sewardj92645592005-07-23 09:18:34 +00001028 } else {
1029 fd = sres.val;
sewardj0744b6c2002-12-11 00:45:42 +00001030 }
njn4f9c9342002-04-29 16:03:24 +00001031
nethercote9313ac42004-07-06 21:54:20 +00001032 // "desc:" lines (giving I1/D1/L2 cache configuration). The spaces after
1033 // the 2nd colon makes cg_annotate's output look nicer.
1034 VG_(sprintf)(buf, "desc: I1 cache: %s\n"
1035 "desc: D1 cache: %s\n"
1036 "desc: L2 cache: %s\n",
1037 I1.desc_line, D1.desc_line, L2.desc_line);
njn7cf0bd32002-06-08 13:36:03 +00001038 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njn4f9c9342002-04-29 16:03:24 +00001039
nethercote9313ac42004-07-06 21:54:20 +00001040 // "cmd:" line
njn4f9c9342002-04-29 16:03:24 +00001041 VG_(strcpy)(buf, "cmd:");
1042 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
sewardj45f4e7c2005-09-27 19:20:21 +00001043 if (VG_(args_the_exename)) {
1044 VG_(write)(fd, " ", 1);
1045 VG_(write)(fd, VG_(args_the_exename),
1046 VG_(strlen)( VG_(args_the_exename) ));
1047 }
1048 for (i = 0; i < VG_(args_for_client).used; i++) {
1049 if (VG_(args_for_client).strs[i]) {
1050 VG_(write)(fd, " ", 1);
1051 VG_(write)(fd, VG_(args_for_client).strs[i],
1052 VG_(strlen)(VG_(args_for_client).strs[i]));
1053 }
njn4f9c9342002-04-29 16:03:24 +00001054 }
nethercote9313ac42004-07-06 21:54:20 +00001055 // "events:" line
njn4f9c9342002-04-29 16:03:24 +00001056 VG_(sprintf)(buf, "\nevents: Ir I1mr I2mr Dr D1mr D2mr Dw D1mw D2mw\n");
1057 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1058
njnd3bef4f2005-10-15 17:46:18 +00001059 // Traverse every lineCC
1060 VG_(OSet_ResetIter)(CC_table);
1061 while ( (lineCC = VG_(OSet_Next)(CC_table)) ) {
1062 // If we've hit a new file, print a "fl=" line. Note that because
1063 // each string is stored exactly once in the string table, we can use
1064 // pointer comparison rather than strcmp() to test for equality, which
1065 // is good because most of the time the comparisons are equal and so
1066 // the whole strings would have to be traversed.
1067 if ( lineCC->loc.file != currFile ) {
1068 currFile = lineCC->loc.file;
1069 VG_(sprintf)(buf, "fl=%s\n", currFile);
njn4f9c9342002-04-29 16:03:24 +00001070 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njnd3bef4f2005-10-15 17:46:18 +00001071 distinct_files++;
njn4f9c9342002-04-29 16:03:24 +00001072 }
njnd3bef4f2005-10-15 17:46:18 +00001073 // If we've hit a new function, print a "fn=" line.
1074 if ( lineCC->loc.fn != currFn ) {
1075 currFn = lineCC->loc.fn;
1076 VG_(sprintf)(buf, "fn=%s\n", currFn);
1077 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1078 distinct_fns++;
1079 }
1080
1081 // Print the LineCC
1082 VG_(sprintf)(buf, "%u %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
1083 lineCC->loc.line,
1084 lineCC->Ir.a, lineCC->Ir.m1, lineCC->Ir.m2,
1085 lineCC->Dr.a, lineCC->Dr.m1, lineCC->Dr.m2,
1086 lineCC->Dw.a, lineCC->Dw.m1, lineCC->Dw.m2);
1087 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1088
1089 // Update summary stats
1090 Ir_total.a += lineCC->Ir.a;
1091 Ir_total.m1 += lineCC->Ir.m1;
1092 Ir_total.m2 += lineCC->Ir.m2;
1093 Dr_total.a += lineCC->Dr.a;
1094 Dr_total.m1 += lineCC->Dr.m1;
1095 Dr_total.m2 += lineCC->Dr.m2;
1096 Dw_total.a += lineCC->Dw.a;
1097 Dw_total.m1 += lineCC->Dw.m1;
1098 Dw_total.m2 += lineCC->Dw.m2;
1099
1100 distinct_lines++;
njn4f9c9342002-04-29 16:03:24 +00001101 }
1102
nethercote9313ac42004-07-06 21:54:20 +00001103 // Summary stats must come after rest of table, since we calculate them
1104 // during traversal. */
njn4f9c9342002-04-29 16:03:24 +00001105 VG_(sprintf)(buf, "summary: "
nethercote9313ac42004-07-06 21:54:20 +00001106 "%llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
njn4f9c9342002-04-29 16:03:24 +00001107 Ir_total.a, Ir_total.m1, Ir_total.m2,
1108 Dr_total.a, Dr_total.m1, Dr_total.m2,
1109 Dw_total.a, Dw_total.m1, Dw_total.m2);
1110 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1111 VG_(close)(fd);
1112}
1113
njn607adfc2003-09-30 14:15:44 +00001114static UInt ULong_width(ULong n)
njn4f9c9342002-04-29 16:03:24 +00001115{
njn607adfc2003-09-30 14:15:44 +00001116 UInt w = 0;
1117 while (n > 0) {
1118 n = n / 10;
1119 w++;
njn4f9c9342002-04-29 16:03:24 +00001120 }
sewardj46c59b12005-11-01 02:20:19 +00001121 if (w == 0) w = 1;
njn607adfc2003-09-30 14:15:44 +00001122 return w + (w-1)/3; // add space for commas
njn4f9c9342002-04-29 16:03:24 +00001123}
1124
njn51d827b2005-05-09 01:02:08 +00001125static void cg_fini(Int exitcode)
njn4f9c9342002-04-29 16:03:24 +00001126{
njn0103de52005-10-10 16:49:01 +00001127 static Char buf1[128], buf2[128], buf3[128], fmt [128];
njn607adfc2003-09-30 14:15:44 +00001128
njn4f9c9342002-04-29 16:03:24 +00001129 CC D_total;
njn1d021fa2002-05-02 13:56:34 +00001130 ULong L2_total_m, L2_total_mr, L2_total_mw,
1131 L2_total, L2_total_r, L2_total_w;
njn4f9c9342002-04-29 16:03:24 +00001132 Int l1, l2, l3;
1133 Int p;
1134
nethercote9313ac42004-07-06 21:54:20 +00001135 fprint_CC_table_and_calc_totals();
njn4f9c9342002-04-29 16:03:24 +00001136
njn7cf0bd32002-06-08 13:36:03 +00001137 if (VG_(clo_verbosity) == 0)
1138 return;
1139
njn4f9c9342002-04-29 16:03:24 +00001140 /* I cache results. Use the I_refs value to determine the first column
1141 * width. */
njn607adfc2003-09-30 14:15:44 +00001142 l1 = ULong_width(Ir_total.a);
1143 l2 = ULong_width(Dr_total.a);
1144 l3 = ULong_width(Dw_total.a);
njn4f9c9342002-04-29 16:03:24 +00001145
njn607adfc2003-09-30 14:15:44 +00001146 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001147 VG_(sprintf)(fmt, "%%s %%,%dllu", l1);
njnd3bef4f2005-10-15 17:46:18 +00001148
njn607adfc2003-09-30 14:15:44 +00001149 VG_(message)(Vg_UserMsg, fmt, "I refs: ", Ir_total.a);
1150 VG_(message)(Vg_UserMsg, fmt, "I1 misses: ", Ir_total.m1);
1151 VG_(message)(Vg_UserMsg, fmt, "L2i misses: ", Ir_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001152
1153 p = 100;
1154
njn25e49d8e72002-09-23 09:36:25 +00001155 if (0 == Ir_total.a) Ir_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001156 VG_(percentify)(Ir_total.m1, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001157 VG_(message)(Vg_UserMsg, "I1 miss rate: %s", buf1);
njnd3bef4f2005-10-15 17:46:18 +00001158
njn856c54e2005-06-26 18:43:40 +00001159 VG_(percentify)(Ir_total.m2, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001160 VG_(message)(Vg_UserMsg, "L2i miss rate: %s", buf1);
1161 VG_(message)(Vg_UserMsg, "");
1162
1163 /* D cache results. Use the D_refs.rd and D_refs.wr values to determine the
1164 * width of columns 2 & 3. */
1165 D_total.a = Dr_total.a + Dw_total.a;
1166 D_total.m1 = Dr_total.m1 + Dw_total.m1;
1167 D_total.m2 = Dr_total.m2 + Dw_total.m2;
njnd3bef4f2005-10-15 17:46:18 +00001168
njn607adfc2003-09-30 14:15:44 +00001169 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001170 VG_(sprintf)(fmt, "%%s %%,%dllu (%%,%dllu rd + %%,%dllu wr)", l1, l2, l3);
njn4f9c9342002-04-29 16:03:24 +00001171
njn607adfc2003-09-30 14:15:44 +00001172 VG_(message)(Vg_UserMsg, fmt, "D refs: ",
1173 D_total.a, Dr_total.a, Dw_total.a);
1174 VG_(message)(Vg_UserMsg, fmt, "D1 misses: ",
1175 D_total.m1, Dr_total.m1, Dw_total.m1);
1176 VG_(message)(Vg_UserMsg, fmt, "L2d misses: ",
1177 D_total.m2, Dr_total.m2, Dw_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001178
1179 p = 10;
njnd3bef4f2005-10-15 17:46:18 +00001180
njn25e49d8e72002-09-23 09:36:25 +00001181 if (0 == D_total.a) D_total.a = 1;
1182 if (0 == Dr_total.a) Dr_total.a = 1;
1183 if (0 == Dw_total.a) Dw_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001184 VG_(percentify)( D_total.m1, D_total.a, 1, l1+1, buf1);
1185 VG_(percentify)(Dr_total.m1, Dr_total.a, 1, l2+1, buf2);
1186 VG_(percentify)(Dw_total.m1, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001187 VG_(message)(Vg_UserMsg, "D1 miss rate: %s (%s + %s )", buf1, buf2,buf3);
1188
njn856c54e2005-06-26 18:43:40 +00001189 VG_(percentify)( D_total.m2, D_total.a, 1, l1+1, buf1);
1190 VG_(percentify)(Dr_total.m2, Dr_total.a, 1, l2+1, buf2);
1191 VG_(percentify)(Dw_total.m2, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001192 VG_(message)(Vg_UserMsg, "L2d miss rate: %s (%s + %s )", buf1, buf2,buf3);
1193 VG_(message)(Vg_UserMsg, "");
1194
1195 /* L2 overall results */
njn1d021fa2002-05-02 13:56:34 +00001196
1197 L2_total = Dr_total.m1 + Dw_total.m1 + Ir_total.m1;
1198 L2_total_r = Dr_total.m1 + Ir_total.m1;
1199 L2_total_w = Dw_total.m1;
njn607adfc2003-09-30 14:15:44 +00001200 VG_(message)(Vg_UserMsg, fmt, "L2 refs: ",
1201 L2_total, L2_total_r, L2_total_w);
njn1d021fa2002-05-02 13:56:34 +00001202
njn4f9c9342002-04-29 16:03:24 +00001203 L2_total_m = Dr_total.m2 + Dw_total.m2 + Ir_total.m2;
1204 L2_total_mr = Dr_total.m2 + Ir_total.m2;
1205 L2_total_mw = Dw_total.m2;
njn607adfc2003-09-30 14:15:44 +00001206 VG_(message)(Vg_UserMsg, fmt, "L2 misses: ",
1207 L2_total_m, L2_total_mr, L2_total_mw);
njn4f9c9342002-04-29 16:03:24 +00001208
njn856c54e2005-06-26 18:43:40 +00001209 VG_(percentify)(L2_total_m, (Ir_total.a + D_total.a), 1, l1+1, buf1);
1210 VG_(percentify)(L2_total_mr, (Ir_total.a + Dr_total.a), 1, l2+1, buf2);
1211 VG_(percentify)(L2_total_mw, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001212 VG_(message)(Vg_UserMsg, "L2 miss rate: %s (%s + %s )", buf1, buf2,buf3);
njnd3bef4f2005-10-15 17:46:18 +00001213
njn4f9c9342002-04-29 16:03:24 +00001214
nethercote9313ac42004-07-06 21:54:20 +00001215 // Various stats
njn4f9c9342002-04-29 16:03:24 +00001216 if (VG_(clo_verbosity) > 1) {
njnd3bef4f2005-10-15 17:46:18 +00001217 Int debug_lookups = full_debugs + fn_debugs +
1218 file_line_debugs + no_debugs;
1219
njn4f9c9342002-04-29 16:03:24 +00001220 VG_(message)(Vg_DebugMsg, "");
njnd3bef4f2005-10-15 17:46:18 +00001221 VG_(message)(Vg_DebugMsg, "cachegrind: distinct files: %d", distinct_files);
1222 VG_(message)(Vg_DebugMsg, "cachegrind: distinct fns: %d", distinct_fns);
1223 VG_(message)(Vg_DebugMsg, "cachegrind: distinct lines: %d", distinct_lines);
1224 VG_(message)(Vg_DebugMsg, "cachegrind: distinct instrs:%d", distinct_instrs);
1225 VG_(message)(Vg_DebugMsg, "cachegrind: debug lookups : %d", debug_lookups);
1226 VG_(message)(Vg_DebugMsg, "cachegrind: with full info:%3d%% (%d)",
1227 full_debugs * 100 / debug_lookups, full_debugs);
1228 VG_(message)(Vg_DebugMsg, "cachegrind: with file/line info:%3d%% (%d)",
1229 file_line_debugs * 100 / debug_lookups, file_line_debugs);
1230 VG_(message)(Vg_DebugMsg, "cachegrind: with fn name info:%3d%% (%d)",
1231 fn_debugs * 100 / debug_lookups, fn_debugs);
1232 VG_(message)(Vg_DebugMsg, "cachegrind: with zero info:%3d%% (%d)",
1233 no_debugs * 100 / debug_lookups, no_debugs);
njnd3bef4f2005-10-15 17:46:18 +00001234 VG_(message)(Vg_DebugMsg, "cachegrind: string table size: %u",
1235 VG_(OSet_Size)(stringTable));
1236 VG_(message)(Vg_DebugMsg, "cachegrind: CC table size: %u",
1237 VG_(OSet_Size)(CC_table));
1238 VG_(message)(Vg_DebugMsg, "cachegrind: InstrInfo table size: %u",
1239 VG_(OSet_Size)(instrInfoTable));
njn4f9c9342002-04-29 16:03:24 +00001240 }
njn25e49d8e72002-09-23 09:36:25 +00001241 VGP_POPCC(VgpCacheResults);
njn4f9c9342002-04-29 16:03:24 +00001242}
1243
nethercote9313ac42004-07-06 21:54:20 +00001244/*--------------------------------------------------------------------*/
1245/*--- Discarding BB info ---*/
1246/*--------------------------------------------------------------------*/
sewardj18d75132002-05-16 11:06:21 +00001247
sewardja3a29a52005-10-12 16:16:03 +00001248// Called when a translation is removed from the translation cache for
1249// any reason at all: to free up space, because the guest code was
1250// unmapped or modified, or for any arbitrary reason.
sewardj4ba057c2005-10-18 12:04:18 +00001251static
1252void cg_discard_basic_block_info ( Addr64 orig_addr64, VexGuestExtents vge )
sewardj18d75132002-05-16 11:06:21 +00001253{
njnd3bef4f2005-10-15 17:46:18 +00001254 BB_info* bbInfo;
sewardj4ba057c2005-10-18 12:04:18 +00001255 Addr orig_addr = (Addr)orig_addr64;
njn4294fd42002-06-05 14:41:10 +00001256
sewardj5155dec2005-10-12 10:09:23 +00001257 tl_assert(vge.n_used > 0);
1258
1259 if (DEBUG_CG)
sewardj4ba057c2005-10-18 12:04:18 +00001260 VG_(printf)( "discard_basic_block_info: %p, %p, %llu\n",
1261 (void*)(Addr)orig_addr,
sewardj5155dec2005-10-12 10:09:23 +00001262 (void*)(Addr)vge.base[0], (ULong)vge.len[0]);
njn4294fd42002-06-05 14:41:10 +00001263
sewardj4ba057c2005-10-18 12:04:18 +00001264 // Get BB info, remove from table, free BB info. Simple! Note that we
1265 // use orig_addr, not the first instruction address in vge.
1266 bbInfo = VG_(OSet_Remove)(instrInfoTable, &orig_addr);
njn6a3009b2005-03-20 00:20:06 +00001267 tl_assert(NULL != bbInfo);
njnd3bef4f2005-10-15 17:46:18 +00001268 VG_(OSet_FreeNode)(instrInfoTable, bbInfo);
sewardj18d75132002-05-16 11:06:21 +00001269}
1270
1271/*--------------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001272/*--- Command line processing ---*/
1273/*--------------------------------------------------------------------*/
1274
njn0103de52005-10-10 16:49:01 +00001275static void parse_cache_opt ( cache_t* cache, Char* opt )
njn25e49d8e72002-09-23 09:36:25 +00001276{
njn0103de52005-10-10 16:49:01 +00001277 Int i = 0, i2, i3;
njn25e49d8e72002-09-23 09:36:25 +00001278
nethercote9313ac42004-07-06 21:54:20 +00001279 // Option argument looks like "65536,2,64".
1280 // Find commas, replace with NULs to make three independent
1281 // strings, then extract numbers, put NULs back. Yuck.
njn25e49d8e72002-09-23 09:36:25 +00001282 while (VG_(isdigit)(opt[i])) i++;
1283 if (',' == opt[i]) {
1284 opt[i++] = '\0';
1285 i2 = i;
1286 } else goto bad;
1287 while (VG_(isdigit)(opt[i])) i++;
1288 if (',' == opt[i]) {
1289 opt[i++] = '\0';
1290 i3 = i;
1291 } else goto bad;
1292 while (VG_(isdigit)(opt[i])) i++;
1293 if ('\0' != opt[i]) goto bad;
1294
nethercote9313ac42004-07-06 21:54:20 +00001295 cache->size = (Int)VG_(atoll)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001296 cache->assoc = (Int)VG_(atoll)(opt + i2);
1297 cache->line_size = (Int)VG_(atoll)(opt + i3);
1298
nethercote9313ac42004-07-06 21:54:20 +00001299 opt[i2-1] = ',';
1300 opt[i3-1] = ',';
njn25e49d8e72002-09-23 09:36:25 +00001301 return;
1302
1303 bad:
nethercote9313ac42004-07-06 21:54:20 +00001304 VG_(bad_option)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001305}
1306
njn51d827b2005-05-09 01:02:08 +00001307static Bool cg_process_cmd_line_option(Char* arg)
njn25e49d8e72002-09-23 09:36:25 +00001308{
nethercote9313ac42004-07-06 21:54:20 +00001309 // 5 is length of "--I1="
njn39c86652003-05-21 10:13:39 +00001310 if (VG_CLO_STREQN(5, arg, "--I1="))
nethercote9313ac42004-07-06 21:54:20 +00001311 parse_cache_opt(&clo_I1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001312 else if (VG_CLO_STREQN(5, arg, "--D1="))
nethercote9313ac42004-07-06 21:54:20 +00001313 parse_cache_opt(&clo_D1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001314 else if (VG_CLO_STREQN(5, arg, "--L2="))
nethercote9313ac42004-07-06 21:54:20 +00001315 parse_cache_opt(&clo_L2_cache, &arg[5]);
njn25e49d8e72002-09-23 09:36:25 +00001316 else
1317 return False;
1318
1319 return True;
1320}
1321
njn51d827b2005-05-09 01:02:08 +00001322static void cg_print_usage(void)
njn25e49d8e72002-09-23 09:36:25 +00001323{
njn3e884182003-04-15 13:03:23 +00001324 VG_(printf)(
njn25e49d8e72002-09-23 09:36:25 +00001325" --I1=<size>,<assoc>,<line_size> set I1 cache manually\n"
1326" --D1=<size>,<assoc>,<line_size> set D1 cache manually\n"
njn3e884182003-04-15 13:03:23 +00001327" --L2=<size>,<assoc>,<line_size> set L2 cache manually\n"
1328 );
1329}
1330
njn51d827b2005-05-09 01:02:08 +00001331static void cg_print_debug_usage(void)
njn3e884182003-04-15 13:03:23 +00001332{
1333 VG_(printf)(
1334" (none)\n"
1335 );
njn25e49d8e72002-09-23 09:36:25 +00001336}
1337
1338/*--------------------------------------------------------------------*/
1339/*--- Setup ---*/
1340/*--------------------------------------------------------------------*/
1341
njn51d827b2005-05-09 01:02:08 +00001342static void cg_post_clo_init(void)
njn25e49d8e72002-09-23 09:36:25 +00001343{
1344 cache_t I1c, D1c, L2c;
njn25e49d8e72002-09-23 09:36:25 +00001345
nethercoteb35a8b92004-09-11 16:45:27 +00001346 configure_caches(&I1c, &D1c, &L2c);
njn25e49d8e72002-09-23 09:36:25 +00001347
1348 cachesim_I1_initcache(I1c);
1349 cachesim_D1_initcache(D1c);
1350 cachesim_L2_initcache(L2c);
1351
njn31066fd2005-03-26 00:42:02 +00001352 VG_(register_profile_event)(VgpGetLineCC, "get-lineCC");
1353 VG_(register_profile_event)(VgpCacheSimulate, "cache-simulate");
1354 VG_(register_profile_event)(VgpCacheResults, "cache-results");
njn25e49d8e72002-09-23 09:36:25 +00001355}
1356
njn57ca7ab2005-06-21 23:44:58 +00001357static Char base_dir[VKI_PATH_MAX];
1358
njn51d827b2005-05-09 01:02:08 +00001359static void cg_pre_clo_init(void)
1360{
njn51d827b2005-05-09 01:02:08 +00001361 VG_(details_name) ("Cachegrind");
1362 VG_(details_version) (NULL);
1363 VG_(details_description) ("an I1/D1/L2 cache profiler");
1364 VG_(details_copyright_author)(
1365 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote et al.");
1366 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj5155dec2005-10-12 10:09:23 +00001367 VG_(details_avg_translation_sizeB) ( 245 );
njn51d827b2005-05-09 01:02:08 +00001368
1369 VG_(basic_tool_funcs) (cg_post_clo_init,
1370 cg_instrument,
1371 cg_fini);
1372
1373 VG_(needs_basic_block_discards)(cg_discard_basic_block_info);
1374 VG_(needs_command_line_options)(cg_process_cmd_line_option,
1375 cg_print_usage,
1376 cg_print_debug_usage);
1377
1378 /* Get working directory */
njn57ca7ab2005-06-21 23:44:58 +00001379 tl_assert( VG_(getcwd)(base_dir, VKI_PATH_MAX) );
njn51d827b2005-05-09 01:02:08 +00001380
1381 /* Block is big enough for dir name + cachegrind.out.<pid> */
1382 cachegrind_out_file = VG_(malloc)((VG_(strlen)(base_dir) + 32)*sizeof(Char));
1383 VG_(sprintf)(cachegrind_out_file, "%s/cachegrind.out.%d",
1384 base_dir, VG_(getpid)());
njn51d827b2005-05-09 01:02:08 +00001385
njnd3bef4f2005-10-15 17:46:18 +00001386 CC_table = VG_(OSet_Create)(offsetof(LineCC, loc),
1387 cmp_CodeLoc_LineCC,
1388 VG_(malloc), VG_(free));
sewardj4ba057c2005-10-18 12:04:18 +00001389 instrInfoTable = VG_(OSet_Create)(/*keyOff*/0,
njnd3bef4f2005-10-15 17:46:18 +00001390 NULL,
1391 VG_(malloc), VG_(free));
1392 stringTable = VG_(OSet_Create)(/*keyOff*/0,
1393 stringCmp,
1394 VG_(malloc), VG_(free));
njn51d827b2005-05-09 01:02:08 +00001395}
1396
sewardj45f4e7c2005-09-27 19:20:21 +00001397VG_DETERMINE_INTERFACE_VERSION(cg_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00001398
njn25e49d8e72002-09-23 09:36:25 +00001399/*--------------------------------------------------------------------*/
njnf69f9452005-07-03 17:53:11 +00001400/*--- end ---*/
sewardj18d75132002-05-16 11:06:21 +00001401/*--------------------------------------------------------------------*/
njnd3bef4f2005-10-15 17:46:18 +00001402