blob: f36d3743be71a1e0d649fe71567bd466fa58c790 [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"
njn81c00df2005-05-14 21:28:43 +000034#include "pub_tool_hashtable.h"
njn97405b22005-06-02 03:39:33 +000035#include "pub_tool_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000036#include "pub_tool_libcassert.h"
njneb8896b2005-06-04 20:03:55 +000037#include "pub_tool_libcfile.h"
njn36a20fa2005-06-03 03:08:39 +000038#include "pub_tool_libcprint.h"
njnf39e9a32005-06-12 02:43:17 +000039#include "pub_tool_libcproc.h"
njnf536bbb2005-06-13 04:21:38 +000040#include "pub_tool_machine.h"
njn717cde52005-05-10 02:47:21 +000041#include "pub_tool_mallocfree.h"
njn20242342005-05-16 23:31:24 +000042#include "pub_tool_options.h"
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
58#define FILE_LEN 256
59#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.
87// - hash(file, hash(fn, hash(line+CC)))
88// - Each hash table is separately chained.
89// - The array sizes below work fairly well for Konqueror.
90// - Lookups done by instr_addr, which is converted immediately to a source
91// location.
92// - Traversed for dumping stats at end in file/func/line hierarchy.
njn4f9c9342002-04-29 16:03:24 +000093
94#define N_FILE_ENTRIES 251
95#define N_FN_ENTRIES 53
nethercote9313ac42004-07-06 21:54:20 +000096#define N_LINE_ENTRIES 37
njn4f9c9342002-04-29 16:03:24 +000097
nethercote9313ac42004-07-06 21:54:20 +000098typedef struct _lineCC lineCC;
99struct _lineCC {
100 Int line;
101 CC Ir;
102 CC Dr;
103 CC Dw;
104 lineCC* next;
njn4f9c9342002-04-29 16:03:24 +0000105};
106
nethercote9313ac42004-07-06 21:54:20 +0000107typedef struct _fnCC fnCC;
108struct _fnCC {
109 Char* fn;
110 fnCC* next;
111 lineCC* lines[N_LINE_ENTRIES];
njn4f9c9342002-04-29 16:03:24 +0000112};
113
nethercote9313ac42004-07-06 21:54:20 +0000114typedef struct _fileCC fileCC;
115struct _fileCC {
116 Char* file;
117 fileCC* next;
118 fnCC* fns[N_FN_ENTRIES];
njn4f9c9342002-04-29 16:03:24 +0000119};
120
nethercote9313ac42004-07-06 21:54:20 +0000121// Top level of CC table. Auto-zeroed.
122static fileCC *CC_table[N_FILE_ENTRIES];
njn4f9c9342002-04-29 16:03:24 +0000123
nethercote9313ac42004-07-06 21:54:20 +0000124//------------------------------------------------------------
njnf69f9452005-07-03 17:53:11 +0000125// Primary data structure #2: Instr-info table
nethercote9313ac42004-07-06 21:54:20 +0000126// - Holds the cached info about each instr that is used for simulation.
127// - table(BB_start_addr, list(instr_info))
128// - For each BB, each instr_info in the list holds info about the
njn6a3009b2005-03-20 00:20:06 +0000129// instruction (instr_len, instr_addr, etc), plus a pointer to its line
nethercote9313ac42004-07-06 21:54:20 +0000130// CC. This node is what's passed to the simulation function.
131// - When BBs are discarded the relevant list(instr_details) is freed.
132
133typedef struct _instr_info instr_info;
134struct _instr_info {
nethercoteca1f2dc2004-07-21 08:49:02 +0000135 Addr instr_addr;
njn6a3009b2005-03-20 00:20:06 +0000136 UChar instr_len;
nethercoteca1f2dc2004-07-21 08:49:02 +0000137 lineCC* parent; // parent line-CC
nethercote9313ac42004-07-06 21:54:20 +0000138};
139
140typedef struct _BB_info BB_info;
141struct _BB_info {
142 BB_info* next; // next field
143 Addr BB_addr; // key
144 Int n_instrs;
145 instr_info instrs[0];
146};
147
148VgHashTable instr_info_table; // hash(Addr, BB_info)
149
150//------------------------------------------------------------
151// Stats
sewardj4f29ddf2002-05-03 22:29:04 +0000152static Int distinct_files = 0;
153static Int distinct_fns = 0;
nethercote9313ac42004-07-06 21:54:20 +0000154static Int distinct_lines = 0;
sewardj4f29ddf2002-05-03 22:29:04 +0000155static Int distinct_instrs = 0;
nethercote9313ac42004-07-06 21:54:20 +0000156
sewardj4f29ddf2002-05-03 22:29:04 +0000157static Int full_debug_BBs = 0;
158static Int file_line_debug_BBs = 0;
nethercote9313ac42004-07-06 21:54:20 +0000159static Int fn_debug_BBs = 0;
sewardj4f29ddf2002-05-03 22:29:04 +0000160static Int no_debug_BBs = 0;
njn4f9c9342002-04-29 16:03:24 +0000161
sewardj4f29ddf2002-05-03 22:29:04 +0000162static Int BB_retranslations = 0;
njn4f9c9342002-04-29 16:03:24 +0000163
nethercote9313ac42004-07-06 21:54:20 +0000164/*------------------------------------------------------------*/
165/*--- CC table operations ---*/
166/*------------------------------------------------------------*/
njn4294fd42002-06-05 14:41:10 +0000167
nethercote9313ac42004-07-06 21:54:20 +0000168static void get_debug_info(Addr instr_addr, Char file[FILE_LEN],
169 Char fn[FN_LEN], Int* line)
njn4f9c9342002-04-29 16:03:24 +0000170{
sewardj7cee6f92005-06-13 17:39:06 +0000171 Bool found_file_line = VG_(get_filename_linenum)(
172 instr_addr,
173 file, FILE_LEN,
174 NULL, 0, NULL,
175 line
176 );
nethercote9313ac42004-07-06 21:54:20 +0000177 Bool found_fn = VG_(get_fnname)(instr_addr, fn, FN_LEN);
njn4f9c9342002-04-29 16:03:24 +0000178
nethercote9313ac42004-07-06 21:54:20 +0000179 if (!found_file_line) {
180 VG_(strcpy)(file, "???");
181 *line = 0;
182 }
183 if (!found_fn) {
184 VG_(strcpy)(fn, "???");
185 }
186 if (found_file_line) {
187 if (found_fn) full_debug_BBs++;
188 else file_line_debug_BBs++;
189 } else {
190 if (found_fn) fn_debug_BBs++;
191 else no_debug_BBs++;
njn4f9c9342002-04-29 16:03:24 +0000192 }
193}
194
njn4f9c9342002-04-29 16:03:24 +0000195static UInt hash(Char *s, UInt table_size)
196{
njn0103de52005-10-10 16:49:01 +0000197 const Int hash_constant = 256;
198 Int hash_value = 0;
nethercote9313ac42004-07-06 21:54:20 +0000199 for ( ; *s; s++)
200 hash_value = (hash_constant * hash_value + *s) % table_size;
201 return hash_value;
njn4f9c9342002-04-29 16:03:24 +0000202}
203
nethercote9313ac42004-07-06 21:54:20 +0000204static __inline__
205fileCC* new_fileCC(Char filename[], fileCC* next)
nethercote09d853e2004-01-21 16:12:55 +0000206{
nethercote9313ac42004-07-06 21:54:20 +0000207 // Using calloc() zeroes the fns[] array
208 fileCC* cc = VG_(calloc)(1, sizeof(fileCC));
209 cc->file = VG_(strdup)(filename);
210 cc->next = next;
211 return cc;
nethercote09d853e2004-01-21 16:12:55 +0000212}
213
nethercote9313ac42004-07-06 21:54:20 +0000214static __inline__
215fnCC* new_fnCC(Char fn[], fnCC* next)
njn4f9c9342002-04-29 16:03:24 +0000216{
nethercote9313ac42004-07-06 21:54:20 +0000217 // Using calloc() zeroes the lines[] array
218 fnCC* cc = VG_(calloc)(1, sizeof(fnCC));
219 cc->fn = VG_(strdup)(fn);
220 cc->next = next;
221 return cc;
222}
njn4f9c9342002-04-29 16:03:24 +0000223
nethercote9313ac42004-07-06 21:54:20 +0000224static __inline__
225lineCC* new_lineCC(Int line, lineCC* next)
226{
227 // Using calloc() zeroes the Ir/Dr/Dw CCs and the instrs[] array
228 lineCC* cc = VG_(calloc)(1, sizeof(lineCC));
229 cc->line = line;
230 cc->next = next;
231 return cc;
232}
njn4f9c9342002-04-29 16:03:24 +0000233
nethercote9313ac42004-07-06 21:54:20 +0000234// Do a three step traversal: by file, then fn, then line.
235// In all cases prepends new nodes to their chain. Returns a pointer to the
236// line node, creates a new one if necessary.
njn6a3009b2005-03-20 00:20:06 +0000237static lineCC* get_lineCC(Addr origAddr)
nethercote9313ac42004-07-06 21:54:20 +0000238{
239 fileCC *curr_fileCC;
240 fnCC *curr_fnCC;
241 lineCC *curr_lineCC;
242 Char file[FILE_LEN], fn[FN_LEN];
243 Int line;
244 UInt file_hash, fn_hash, line_hash;
245
njn6a3009b2005-03-20 00:20:06 +0000246 get_debug_info(origAddr, file, fn, &line);
nethercote9313ac42004-07-06 21:54:20 +0000247
248 VGP_PUSHCC(VgpGetLineCC);
249
250 // level 1
251 file_hash = hash(file, N_FILE_ENTRIES);
252 curr_fileCC = CC_table[file_hash];
253 while (NULL != curr_fileCC && !VG_STREQ(file, curr_fileCC->file)) {
254 curr_fileCC = curr_fileCC->next;
njn4f9c9342002-04-29 16:03:24 +0000255 }
nethercote9313ac42004-07-06 21:54:20 +0000256 if (NULL == curr_fileCC) {
257 CC_table[file_hash] = curr_fileCC =
258 new_fileCC(file, CC_table[file_hash]);
njn4f9c9342002-04-29 16:03:24 +0000259 distinct_files++;
260 }
261
nethercote9313ac42004-07-06 21:54:20 +0000262 // level 2
263 fn_hash = hash(fn, N_FN_ENTRIES);
264 curr_fnCC = curr_fileCC->fns[fn_hash];
265 while (NULL != curr_fnCC && !VG_STREQ(fn, curr_fnCC->fn)) {
266 curr_fnCC = curr_fnCC->next;
njn4f9c9342002-04-29 16:03:24 +0000267 }
nethercote9313ac42004-07-06 21:54:20 +0000268 if (NULL == curr_fnCC) {
269 curr_fileCC->fns[fn_hash] = curr_fnCC =
270 new_fnCC(fn, curr_fileCC->fns[fn_hash]);
njn4f9c9342002-04-29 16:03:24 +0000271 distinct_fns++;
272 }
273
nethercote9313ac42004-07-06 21:54:20 +0000274 // level 3
275 line_hash = line % N_LINE_ENTRIES;
276 curr_lineCC = curr_fnCC->lines[line_hash];
277 while (NULL != curr_lineCC && line != curr_lineCC->line) {
278 curr_lineCC = curr_lineCC->next;
njn4f9c9342002-04-29 16:03:24 +0000279 }
nethercote9313ac42004-07-06 21:54:20 +0000280 if (NULL == curr_lineCC) {
281 curr_fnCC->lines[line_hash] = curr_lineCC =
282 new_lineCC(line, curr_fnCC->lines[line_hash]);
283 distinct_lines++;
njn4f9c9342002-04-29 16:03:24 +0000284 }
nethercote9313ac42004-07-06 21:54:20 +0000285
286 VGP_POPCC(VgpGetLineCC);
287 return curr_lineCC;
njn4f9c9342002-04-29 16:03:24 +0000288}
289
290/*------------------------------------------------------------*/
nethercote9313ac42004-07-06 21:54:20 +0000291/*--- Cache simulation functions ---*/
njn4f9c9342002-04-29 16:03:24 +0000292/*------------------------------------------------------------*/
293
njnaf839f52005-06-23 03:27:57 +0000294static VG_REGPARM(1)
nethercote9313ac42004-07-06 21:54:20 +0000295void log_1I_0D_cache_access(instr_info* n)
njn25e49d8e72002-09-23 09:36:25 +0000296{
sewardj5155dec2005-10-12 10:09:23 +0000297 //VG_(printf)("1I_0D : CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n",
298 // n, n->instr_addr, n->instr_len);
njn25e49d8e72002-09-23 09:36:25 +0000299 VGP_PUSHCC(VgpCacheSimulate);
njn6a3009b2005-03-20 00:20:06 +0000300 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000301 &n->parent->Ir.m1, &n->parent->Ir.m2);
302 n->parent->Ir.a++;
njn25e49d8e72002-09-23 09:36:25 +0000303 VGP_POPCC(VgpCacheSimulate);
304}
305
njnaf839f52005-06-23 03:27:57 +0000306static VG_REGPARM(2)
sewardj5155dec2005-10-12 10:09:23 +0000307void log_2I_0D_cache_access(instr_info* n, instr_info* n2)
njn25e49d8e72002-09-23 09:36:25 +0000308{
sewardj5155dec2005-10-12 10:09:23 +0000309 //VG_(printf)("2I_0D : CC1addr=0x%010lx, i1addr=0x%010lx, i1size=%lu\n"
310 // " CC2addr=0x%010lx, i2addr=0x%010lx, i2size=%lu\n",
311 // n, n->instr_addr, n->instr_len,
312 // n2, n2->instr_addr, n2->instr_len);
313 VGP_PUSHCC(VgpCacheSimulate);
314 cachesim_I1_doref(n->instr_addr, n->instr_len,
315 &n->parent->Ir.m1, &n->parent->Ir.m2);
316 n->parent->Ir.a++;
317 cachesim_I1_doref(n2->instr_addr, n2->instr_len,
318 &n2->parent->Ir.m1, &n2->parent->Ir.m2);
319 n2->parent->Ir.a++;
320 VGP_POPCC(VgpCacheSimulate);
321}
322
323static VG_REGPARM(3)
324void log_3I_0D_cache_access(instr_info* n, instr_info* n2, instr_info* n3)
325{
326 //VG_(printf)("3I_0D : CC1addr=0x%010lx, i1addr=0x%010lx, i1size=%lu\n"
327 // " CC2addr=0x%010lx, i2addr=0x%010lx, i2size=%lu\n"
328 // " CC3addr=0x%010lx, i3addr=0x%010lx, i3size=%lu\n",
329 // n, n->instr_addr, n->instr_len,
330 // n2, n2->instr_addr, n2->instr_len,
331 // n3, n3->instr_addr, n3->instr_len);
332 VGP_PUSHCC(VgpCacheSimulate);
333 cachesim_I1_doref(n->instr_addr, n->instr_len,
334 &n->parent->Ir.m1, &n->parent->Ir.m2);
335 n->parent->Ir.a++;
336 cachesim_I1_doref(n2->instr_addr, n2->instr_len,
337 &n2->parent->Ir.m1, &n2->parent->Ir.m2);
338 n2->parent->Ir.a++;
339 cachesim_I1_doref(n3->instr_addr, n3->instr_len,
340 &n3->parent->Ir.m1, &n3->parent->Ir.m2);
341 n3->parent->Ir.a++;
342 VGP_POPCC(VgpCacheSimulate);
343}
344
345static VG_REGPARM(3)
346void log_1I_1Dr_cache_access(instr_info* n, Addr data_addr, Word data_size)
347{
348 //VG_(printf)("1I_1Dr: CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n"
349 // " daddr=0x%010lx, dsize=%lu\n",
350 // n, n->instr_addr, n->instr_len, data_addr, data_size);
njn25e49d8e72002-09-23 09:36:25 +0000351 VGP_PUSHCC(VgpCacheSimulate);
njn6a3009b2005-03-20 00:20:06 +0000352 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000353 &n->parent->Ir.m1, &n->parent->Ir.m2);
354 n->parent->Ir.a++;
njn25e49d8e72002-09-23 09:36:25 +0000355
sewardj5155dec2005-10-12 10:09:23 +0000356 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000357 &n->parent->Dr.m1, &n->parent->Dr.m2);
358 n->parent->Dr.a++;
njn25e49d8e72002-09-23 09:36:25 +0000359 VGP_POPCC(VgpCacheSimulate);
360}
361
sewardj5155dec2005-10-12 10:09:23 +0000362static VG_REGPARM(3)
363void log_1I_1Dw_cache_access(instr_info* n, Addr data_addr, Word data_size)
njn25e49d8e72002-09-23 09:36:25 +0000364{
sewardj5155dec2005-10-12 10:09:23 +0000365 //VG_(printf)("1I_1Dw: CCaddr=0x%010lx, iaddr=0x%010lx, isize=%lu\n"
366 // " daddr=0x%010lx, dsize=%lu\n",
367 // n, n->instr_addr, n->instr_len, data_addr, data_size);
njn25e49d8e72002-09-23 09:36:25 +0000368 VGP_PUSHCC(VgpCacheSimulate);
njn6a3009b2005-03-20 00:20:06 +0000369 cachesim_I1_doref(n->instr_addr, n->instr_len,
nethercote9313ac42004-07-06 21:54:20 +0000370 &n->parent->Ir.m1, &n->parent->Ir.m2);
371 n->parent->Ir.a++;
372
sewardj5155dec2005-10-12 10:09:23 +0000373 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000374 &n->parent->Dw.m1, &n->parent->Dw.m2);
375 n->parent->Dw.a++;
njn25e49d8e72002-09-23 09:36:25 +0000376 VGP_POPCC(VgpCacheSimulate);
377}
378
njnaf839f52005-06-23 03:27:57 +0000379static VG_REGPARM(3)
sewardj5155dec2005-10-12 10:09:23 +0000380void log_0I_1Dr_cache_access(instr_info* n, Addr data_addr, Word data_size)
njn25e49d8e72002-09-23 09:36:25 +0000381{
sewardj5155dec2005-10-12 10:09:23 +0000382 //VG_(printf)("0I_1Dr: CCaddr=0x%010lx, daddr=0x%010lx, dsize=%lu\n",
383 // n, data_addr, data_size);
njn25e49d8e72002-09-23 09:36:25 +0000384 VGP_PUSHCC(VgpCacheSimulate);
sewardj5155dec2005-10-12 10:09:23 +0000385 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000386 &n->parent->Dr.m1, &n->parent->Dr.m2);
387 n->parent->Dr.a++;
sewardj5155dec2005-10-12 10:09:23 +0000388 VGP_POPCC(VgpCacheSimulate);
389}
390
391static VG_REGPARM(3)
392void log_0I_1Dw_cache_access(instr_info* n, Addr data_addr, Word data_size)
393{
394 //VG_(printf)("0I_1Dw: CCaddr=0x%010lx, daddr=0x%010lx, dsize=%lu\n",
395 // n, data_addr, data_size);
396 VGP_PUSHCC(VgpCacheSimulate);
397 cachesim_D1_doref(data_addr, data_size,
nethercote9313ac42004-07-06 21:54:20 +0000398 &n->parent->Dw.m1, &n->parent->Dw.m2);
399 n->parent->Dw.a++;
njn25e49d8e72002-09-23 09:36:25 +0000400 VGP_POPCC(VgpCacheSimulate);
401}
402
nethercote9313ac42004-07-06 21:54:20 +0000403/*------------------------------------------------------------*/
sewardj5155dec2005-10-12 10:09:23 +0000404/*--- Instrumentation types and structures ---*/
405/*------------------------------------------------------------*/
406
407/* Maintain an ordered list of memory events which are outstanding, in
408 the sense that no IR has yet been generated to do the relevant
409 helper calls. The BB is scanned top to bottom and memory events
410 are added to the end of the list, merging with the most recent
411 notified event where possible (Dw immediately following Dr and
412 having the same size and EA can be merged).
413
414 This merging is done so that for architectures which have
415 load-op-store instructions (x86, amd64), the insn is treated as if
416 it makes just one memory reference (a modify), rather than two (a
417 read followed by a write at the same address).
418
419 At various points the list will need to be flushed, that is, IR
420 generated from it. That must happen before any possible exit from
421 the block (the end, or an IRStmt_Exit). Flushing also takes place
422 when there is no space to add a new event.
423
424 If we require the simulation statistics to be up to date with
425 respect to possible memory exceptions, then the list would have to
426 be flushed before each memory reference. That would however lose
427 performance by inhibiting event-merging during flushing.
428
429 Flushing the list consists of walking it start to end and emitting
430 instrumentation IR for each event, in the order in which they
431 appear. It may be possible to emit a single call for two adjacent
432 events in order to reduce the number of helper function calls made.
433 For example, it could well be profitable to handle two adjacent Ir
434 events with a single helper call. */
435
436typedef
437 IRExpr
438 IRAtom;
439
440typedef
441 enum { Event_Ir=0, Event_Dr=1, Event_Dw=2, Event_Dm=3 }
442 EventKind;
443
444typedef
445 struct {
446 EventKind ekind;
447 Int size; /* ALL */
448 Addr64 iaddr; /* ALL. For Dr/Dw/Dm is & of parent insn. */
449 IRAtom* dataEA; /* Dr/Dw/Dm only */ /* IR ATOM ONLY */
450 }
451 Event;
452
453/* Up to this many unnotified events are allowed. Number is
454 arbitrary. Larger numbers allow more event merging to occur, but
455 potentially induce more spilling due to extending live ranges of
456 address temporaries. */
457#define N_EVENTS 16
458
459
460/* A struct which holds all the running state during instrumentation.
461 Mostly to avoid passing loads of parameters everywhere. */
462typedef
463 struct {
464 /* The current outstanding-memory-event list. */
465 Event events[N_EVENTS];
466 Int events_used;
467
468 /* The array of instr_info bins for the BB. */
469 BB_info* bbInfo;
470
471 /* Number instr_info bins 'used' so far. */
472 Int bbInfo_i;
473
474 /* Not sure what this is for (jrs 20051009) */
475 Bool bbSeenBefore;
476
477 /* The output BB being constructed. */
478 IRBB* bbOut;
479 }
480 CgState;
481
482
483static Int index3 ( EventKind k1, EventKind k2, EventKind k3 )
484{
485 Int i1 = k1;
486 Int i2 = k2;
487 Int i3 = k3;
488 Int r;
489 tl_assert(i1 >= 0 && i1 < 4);
490 tl_assert(i2 >= 0 && i2 < 4);
491 tl_assert(i3 >= 0 && i3 < 4);
492 r = 16*i1 + 4*i2 + i3;
493 tl_assert(r >= 0 && r < 64);
494 return r;
495}
496
497static void show3 ( Int idx )
498{
499 HChar* names = "IRWM";
500 Int i1 = (idx >> 4) & 3;
501 Int i2 = (idx >> 2) & 3;
502 Int i3 = idx & 3;
503 VG_(printf)("%c%c%c", names[i1], names[i2], names[i3]);
504}
505
506static Int trigrams[64];
507
508
509/*------------------------------------------------------------*/
510/*--- Instrumentation main ---*/
nethercote9313ac42004-07-06 21:54:20 +0000511/*------------------------------------------------------------*/
512
nethercote564b2b02004-08-07 15:54:53 +0000513static
sewardj5155dec2005-10-12 10:09:23 +0000514BB_info* get_BB_info(IRBB* bbIn, Addr origAddr, /*OUT*/Bool* bbSeenBefore)
nethercote9313ac42004-07-06 21:54:20 +0000515{
njn4bd67b52005-08-11 00:47:10 +0000516 Int i, n_instrs;
517 IRStmt* st;
518 BB_info* bbInfo;
nethercote9313ac42004-07-06 21:54:20 +0000519
njn6a3009b2005-03-20 00:20:06 +0000520 // Count number of original instrs in BB
521 n_instrs = 0;
522 for (i = 0; i < bbIn->stmts_used; i++) {
523 st = bbIn->stmts[i];
524 if (Ist_IMark == st->tag) n_instrs++;
nethercote9313ac42004-07-06 21:54:20 +0000525 }
526
527 // Get the BB_info
njn4bd67b52005-08-11 00:47:10 +0000528 bbInfo = (BB_info*)VG_(HT_lookup)(instr_info_table, origAddr);
njn6a3009b2005-03-20 00:20:06 +0000529 *bbSeenBefore = ( NULL == bbInfo ? False : True );
530 if (*bbSeenBefore) {
nethercote9313ac42004-07-06 21:54:20 +0000531 // BB must have been translated before, but flushed from the TT
njn6a3009b2005-03-20 00:20:06 +0000532 tl_assert(bbInfo->n_instrs == n_instrs );
nethercote9313ac42004-07-06 21:54:20 +0000533 BB_retranslations++;
534 } else {
535 // BB never translated before (at this address, at least; could have
536 // been unloaded and then reloaded elsewhere in memory)
njn6a3009b2005-03-20 00:20:06 +0000537 bbInfo = VG_(calloc)(1, sizeof(BB_info) + n_instrs*sizeof(instr_info));
538 bbInfo->BB_addr = origAddr;
539 bbInfo->n_instrs = n_instrs;
540 VG_(HT_add_node)( instr_info_table, (VgHashNode*)bbInfo );
nethercote9313ac42004-07-06 21:54:20 +0000541 distinct_instrs++;
542 }
njn6a3009b2005-03-20 00:20:06 +0000543 return bbInfo;
nethercote9313ac42004-07-06 21:54:20 +0000544}
njn6a3009b2005-03-20 00:20:06 +0000545
nethercote9313ac42004-07-06 21:54:20 +0000546
nethercote564b2b02004-08-07 15:54:53 +0000547static
sewardj5155dec2005-10-12 10:09:23 +0000548void init_instr_info( instr_info* n, Bool bbSeenBefore,
549 Addr instr_addr, Int instr_len )
nethercote9313ac42004-07-06 21:54:20 +0000550{
njn6a3009b2005-03-20 00:20:06 +0000551 if (bbSeenBefore) {
njnca82cc02004-11-22 17:18:48 +0000552 tl_assert( n->instr_addr == instr_addr );
njn6a3009b2005-03-20 00:20:06 +0000553 tl_assert( n->instr_len == instr_len );
njn6a3009b2005-03-20 00:20:06 +0000554 // Don't check that (n->parent == parent)... it's conceivable that
nethercote9313ac42004-07-06 21:54:20 +0000555 // the debug info might change; the other asserts should be enough to
556 // detect anything strange.
557 } else {
njn6a3009b2005-03-20 00:20:06 +0000558 lineCC* parent = get_lineCC(instr_addr);
nethercote9313ac42004-07-06 21:54:20 +0000559 n->instr_addr = instr_addr;
njn6a3009b2005-03-20 00:20:06 +0000560 n->instr_len = instr_len;
nethercote9313ac42004-07-06 21:54:20 +0000561 n->parent = parent;
562 }
563}
564
sewardj5155dec2005-10-12 10:09:23 +0000565static void showEvent ( Event* ev )
nethercote9313ac42004-07-06 21:54:20 +0000566{
sewardj5155dec2005-10-12 10:09:23 +0000567 switch (ev->ekind) {
568 case Event_Ir:
569 VG_(printf)("Ir %d 0x%llx\n", ev->size, ev->iaddr);
570 break;
571 case Event_Dr:
572 VG_(printf)("Dr %d 0x%llx EA=", ev->size, ev->iaddr);
573 ppIRExpr(ev->dataEA);
574 VG_(printf)("\n");
575 break;
576 case Event_Dw:
577 VG_(printf)("Dw %d 0x%llx EA=", ev->size, ev->iaddr);
578 ppIRExpr(ev->dataEA);
579 VG_(printf)("\n");
580 break;
581 case Event_Dm:
582 VG_(printf)("Dm %d 0x%llx EA=", ev->size, ev->iaddr);
583 ppIRExpr(ev->dataEA);
584 VG_(printf)("\n");
585 break;
586 default:
587 tl_assert(0);
588 break;
589 }
njn6a3009b2005-03-20 00:20:06 +0000590}
591
sewardj5155dec2005-10-12 10:09:23 +0000592/* Reserve instr_info for the first mention of a new insn. */
593
594static instr_info* reserve_instr_info ( CgState* cgs )
njn6a3009b2005-03-20 00:20:06 +0000595{
sewardj5155dec2005-10-12 10:09:23 +0000596 instr_info* i_node;
597 tl_assert(cgs->bbInfo_i >= 0);
598 tl_assert(cgs->bbInfo_i < cgs->bbInfo->n_instrs);
599 i_node = &cgs->bbInfo->instrs[ cgs->bbInfo_i ];
600 cgs->bbInfo_i++;
601 return i_node;
602}
sewardj17a56bf2005-03-21 01:35:02 +0000603
sewardj17a56bf2005-03-21 01:35:02 +0000604
sewardj5155dec2005-10-12 10:09:23 +0000605/* Find the most recently allocated instr_info. */
sewardj17a56bf2005-03-21 01:35:02 +0000606
sewardj5155dec2005-10-12 10:09:23 +0000607static instr_info* find_most_recent_instr_info ( CgState* cgs )
608{
609 tl_assert(cgs->bbInfo_i >= 0);
610 tl_assert(cgs->bbInfo_i <= cgs->bbInfo->n_instrs);
611 if (cgs->bbInfo_i == 0)
612 return NULL;
613 else
614 return &cgs->bbInfo->instrs[ cgs->bbInfo_i - 1 ];
615}
njn016712a2005-04-04 02:52:16 +0000616
njn6a3009b2005-03-20 00:20:06 +0000617
sewardj5155dec2005-10-12 10:09:23 +0000618/* Generate code for all outstanding memory events, and mark the queue
619 empty. Code is generated into cgs->bbOut, and this activity
620 'consumes' slots in cgs->bbInfo. */
njn6a3009b2005-03-20 00:20:06 +0000621
sewardj5155dec2005-10-12 10:09:23 +0000622static void flushEvents ( CgState* cgs )
623{
624 Int i, regparms;
625 Char* helperName;
626 void* helperAddr;
627 IRExpr** argv;
628 IRExpr* i_node_expr;
629 IRExpr* i_node2_expr;
630 IRExpr* i_node3_expr;
631 IRDirty* di;
632 instr_info* i_node;
633 instr_info* i_node2;
634 instr_info* i_node3;
njn6a3009b2005-03-20 00:20:06 +0000635
sewardj5155dec2005-10-12 10:09:23 +0000636 for (i = 0; i < cgs->events_used-2; i++)
637 trigrams [ index3( cgs->events[i].ekind, cgs->events[i+1].ekind,cgs->events[i+2].ekind ) ]++;
njn6a3009b2005-03-20 00:20:06 +0000638
sewardj5155dec2005-10-12 10:09:23 +0000639 i = 0;
640 while (i < cgs->events_used) {
njn6a3009b2005-03-20 00:20:06 +0000641
sewardj5155dec2005-10-12 10:09:23 +0000642 helperName = NULL;
643 helperAddr = NULL;
644 argv = NULL;
645 regparms = 0;
646
647 /* generate IR to notify event i and possibly the ones
648 immediately following it. */
649 tl_assert(i >= 0 && i < cgs->events_used);
650 if (DEBUG_CG) {
651 VG_(printf)(" flush ");
652 showEvent( &cgs->events[i] );
njn4f9c9342002-04-29 16:03:24 +0000653 }
sewardj5155dec2005-10-12 10:09:23 +0000654
655 /* For any event we find the relevant instr_info. The following
656 assumes that Event_Ir is the first event to refer to any
657 specific insn, and so a new entry in the cgs->bbInfo->instrs
658 is allocated. All other events (Dr,Dw,Dm) must refer to the
659 most recently encountered IMark and so we use the
660 most-recently allocated instrs[] entry, which must exist. */
661
662 if (cgs->events[i].ekind == Event_Ir) {
663 /* allocate an instr_info and fill in its addr/size. */
664 i_node = reserve_instr_info( cgs );
665 tl_assert(i_node);
666 init_instr_info( i_node, cgs->bbSeenBefore,
667 (Addr)cgs->events[i].iaddr, /* i addr */
668 cgs->events[i].size /* i size */);
669 } else {
670 /* use the most-recently allocated i_node but don't mess with
671 its internals */
672 i_node = find_most_recent_instr_info( cgs );
673 /* it must actually exist */
674 tl_assert(i_node);
675 /* it must match the declared parent instruction of this
676 event. */
677 tl_assert(i_node->instr_addr == cgs->events[i].iaddr);
678 }
679
680 i_node_expr = mkIRExpr_HWord( (HWord)i_node );
681
682 /* Decide on helper fn to call and args to pass it, and advance
683 i appropriately. */
684 switch (cgs->events[i].ekind) {
685 case Event_Ir:
686 /* Merge with a following Dr/Dm if it is from this insn. */
687 if (i < cgs->events_used-1
688 && cgs->events[i+1].iaddr == cgs->events[i].iaddr
689 && (cgs->events[i+1].ekind == Event_Dr
690 || cgs->events[i+1].ekind == Event_Dm)) {
691 helperName = "log_1I_1Dr_cache_access";
692 helperAddr = &log_1I_1Dr_cache_access;
693 argv = mkIRExprVec_3( i_node_expr,
694 cgs->events[i+1].dataEA,
695 mkIRExpr_HWord( cgs->events[i+1].size ) );
696 regparms = 3;
697 i += 2;
698 }
699 /* Merge with a following Dw if it is from this insn. */
700 else
701 if (i < cgs->events_used-1
702 && cgs->events[i+1].iaddr == cgs->events[i].iaddr
703 && cgs->events[i+1].ekind == Event_Dw) {
704 helperName = "log_1I_1Dw_cache_access";
705 helperAddr = &log_1I_1Dw_cache_access;
706 argv = mkIRExprVec_3( i_node_expr,
707 cgs->events[i+1].dataEA,
708 mkIRExpr_HWord( cgs->events[i+1].size ) );
709 regparms = 3;
710 i += 2;
711 }
712 /* Merge with two following Irs if possible. */
713 else
714 if (i < cgs->events_used-2
715 && cgs->events[i+1].ekind == Event_Ir
716 && cgs->events[i+2].ekind == Event_Ir) {
717 helperName = "log_3I_0D_cache_access";
718 helperAddr = &log_3I_0D_cache_access;
719
720 i_node2 = reserve_instr_info( cgs );
721 tl_assert(i_node2);
722 init_instr_info( i_node2, cgs->bbSeenBefore,
723 (Addr)cgs->events[i+1].iaddr, /* i addr */
724 cgs->events[i+1].size /* i size */);
725 i_node2_expr = mkIRExpr_HWord( (HWord)i_node2 );
726
727 i_node3 = reserve_instr_info( cgs );
728 tl_assert(i_node3);
729 init_instr_info( i_node3, cgs->bbSeenBefore,
730 (Addr)cgs->events[i+2].iaddr, /* i addr */
731 cgs->events[i+2].size /* i size */);
732 i_node3_expr = mkIRExpr_HWord( (HWord)i_node3 );
733
734 argv = mkIRExprVec_3( i_node_expr, i_node2_expr, i_node3_expr );
735 regparms = 3;
736 i += 3;
737 }
738 /* Merge with a following Ir if possible. */
739 else
740 if (i < cgs->events_used-1
741 && cgs->events[i+1].ekind == Event_Ir) {
742 helperName = "log_2I_0D_cache_access";
743 helperAddr = &log_2I_0D_cache_access;
744 i_node2 = reserve_instr_info( cgs );
745 tl_assert(i_node2);
746 init_instr_info( i_node2, cgs->bbSeenBefore,
747 (Addr)cgs->events[i+1].iaddr, /* i addr */
748 cgs->events[i+1].size /* i size */);
749 i_node2_expr = mkIRExpr_HWord( (HWord)i_node2 );
750 argv = mkIRExprVec_2( i_node_expr, i_node2_expr );
751 regparms = 2;
752 i += 2;
753 }
754 /* No merging possible; emit as-is. */
755 else {
756 helperName = "log_1I_0D_cache_access";
757 helperAddr = &log_1I_0D_cache_access;
758 argv = mkIRExprVec_1( i_node_expr );
759 regparms = 1;
760 i++;
761 }
762 break;
763 case Event_Dr:
764 case Event_Dm:
765 helperName = "log_0I_1Dr_cache_access";
766 helperAddr = &log_0I_1Dr_cache_access;
767 argv = mkIRExprVec_3( i_node_expr,
768 cgs->events[i].dataEA,
769 mkIRExpr_HWord( cgs->events[i].size ) );
770 regparms = 3;
771 i++;
772 break;
773 case Event_Dw:
774 helperName = "log_0I_1Dw_cache_access";
775 helperAddr = &log_0I_1Dw_cache_access;
776 argv = mkIRExprVec_3( i_node_expr,
777 cgs->events[i].dataEA,
778 mkIRExpr_HWord( cgs->events[i].size ) );
779 regparms = 3;
780 i++;
781 break;
782 default:
783 tl_assert(0);
784 }
785
786 /* Add the helper. */
787 tl_assert(helperName);
788 tl_assert(helperAddr);
789 tl_assert(argv);
790 di = unsafeIRDirty_0_N( regparms, helperName, helperAddr, argv);
791 addStmtToIRBB( cgs->bbOut, IRStmt_Dirty(di) );
njn4f9c9342002-04-29 16:03:24 +0000792 }
793
sewardj5155dec2005-10-12 10:09:23 +0000794 cgs->events_used = 0;
njn4f9c9342002-04-29 16:03:24 +0000795}
njn14d01ce2004-11-26 11:30:14 +0000796
sewardj5155dec2005-10-12 10:09:23 +0000797
798static void addEvent_Ir ( CgState* cgs, Int size, Addr64 iaddr )
799{
800 Event* evt;
801 tl_assert(size >= 0 && size <= MIN_LINE_SIZE);
802 if (cgs->events_used == N_EVENTS)
803 flushEvents(cgs);
804 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
805 /* If vex fails to decode an insn, the size will be zero, but that
806 can't really be true -- the cpu couldn't have determined the
807 insn was undecodable without looking at it. Hence: */
808 if (size == 0)
809 size = 1;
810 evt = &cgs->events[cgs->events_used];
811 evt->ekind = Event_Ir;
812 evt->size = size;
813 evt->iaddr = iaddr;
814 evt->dataEA = NULL; /*paranoia*/
815 cgs->events_used++;
816}
817
818static void addEvent_Dr ( CgState* cgs, Int size, Addr64 iaddr, IRAtom* ea )
819{
820 Event* evt;
821 tl_assert(isIRAtom(ea));
822 tl_assert(size >= 1 && size <= MIN_LINE_SIZE);
823 if (cgs->events_used == N_EVENTS)
824 flushEvents(cgs);
825 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
826 evt = &cgs->events[cgs->events_used];
827 evt->ekind = Event_Dr;
828 evt->size = size;
829 evt->iaddr = iaddr;
830 evt->dataEA = ea;
831 cgs->events_used++;
832}
833
834static void addEvent_Dw ( CgState* cgs, Int size, Addr64 iaddr, IRAtom* ea )
835{
836 tl_assert(isIRAtom(ea));
837 tl_assert(size >= 1 && size <= MIN_LINE_SIZE);
838
839 /* Is it possible to merge this write into an immediately preceding
840 read? */
841 if (cgs->events_used > 0
842 && cgs->events[cgs->events_used-1].ekind == Event_Dr
843 && cgs->events[cgs->events_used-1].size == size
844 && cgs->events[cgs->events_used-1].iaddr == iaddr
845 && eqIRAtom(cgs->events[cgs->events_used-1].dataEA, ea)) {
846 cgs->events[cgs->events_used-1].ekind = Event_Dm;
847 return;
848 }
849
850 /* No. Add as normal. */
851 if (cgs->events_used == N_EVENTS)
852 flushEvents(cgs);
853 tl_assert(cgs->events_used >= 0 && cgs->events_used < N_EVENTS);
854 cgs->events[cgs->events_used].ekind = Event_Dw;
855 cgs->events[cgs->events_used].size = size;
856 cgs->events[cgs->events_used].iaddr = iaddr;
857 cgs->events[cgs->events_used].dataEA = ea;
858 cgs->events_used++;
859}
860
861////////////////////////////////////////////////////////////
862
863
njn51d827b2005-05-09 01:02:08 +0000864static IRBB* cg_instrument ( IRBB* bbIn, VexGuestLayout* layout,
865 IRType gWordTy, IRType hWordTy )
njn14d01ce2004-11-26 11:30:14 +0000866{
sewardj5155dec2005-10-12 10:09:23 +0000867 Int i;
868 IRStmt* st;
869 Addr64 cia; /* address of current insn */
870 CgState cgs;
871 IRTypeEnv* tyenv = bbIn->tyenv;
872
njn6a3009b2005-03-20 00:20:06 +0000873
sewardjd54babf2005-03-21 00:55:49 +0000874 if (gWordTy != hWordTy) {
875 /* We don't currently support this case. */
876 VG_(tool_panic)("host/guest word size mismatch");
877 }
878
njn6a3009b2005-03-20 00:20:06 +0000879 /* Set up BB */
sewardj5155dec2005-10-12 10:09:23 +0000880 cgs.bbOut = emptyIRBB();
881 cgs.bbOut->tyenv = dopyIRTypeEnv(tyenv);
njn6a3009b2005-03-20 00:20:06 +0000882
sewardj5155dec2005-10-12 10:09:23 +0000883 // Get the first statement, and initial cia from it
njn6a3009b2005-03-20 00:20:06 +0000884 i = 0;
885 tl_assert(bbIn->stmts_used > 0);
886 st = bbIn->stmts[0];
887 tl_assert(Ist_IMark == st->tag);
sewardj5155dec2005-10-12 10:09:23 +0000888 cia = st->Ist.IMark.addr;
njn6a3009b2005-03-20 00:20:06 +0000889
sewardj5155dec2005-10-12 10:09:23 +0000890 // Set up running state and get block info
891 cgs.events_used = 0;
892 cgs.bbInfo = get_BB_info(bbIn, (Addr)cia, &cgs.bbSeenBefore);
893 cgs.bbInfo_i = 0;
njn6a3009b2005-03-20 00:20:06 +0000894
sewardj5155dec2005-10-12 10:09:23 +0000895 if (DEBUG_CG)
896 VG_(printf)("\n\n---------- cg_instrument ----------\n");
njn6a3009b2005-03-20 00:20:06 +0000897
sewardj5155dec2005-10-12 10:09:23 +0000898 // Traverse the block, adding events and flushing as necessary.
899 for (i = 0; i < bbIn->stmts_used; i++) {
njn6a3009b2005-03-20 00:20:06 +0000900
sewardj5155dec2005-10-12 10:09:23 +0000901 st = bbIn->stmts[i];
902 tl_assert(isFlatIRStmt(st));
njnb3507ea2005-08-02 23:07:02 +0000903
sewardj5155dec2005-10-12 10:09:23 +0000904 switch (st->tag) {
905 case Ist_NoOp:
906 case Ist_AbiHint:
907 case Ist_Put:
908 case Ist_PutI:
909 case Ist_MFence:
910 break;
njn20677cc2005-08-12 23:47:51 +0000911
sewardj5155dec2005-10-12 10:09:23 +0000912 case Ist_IMark:
913 cia = st->Ist.IMark.addr;
914 addEvent_Ir( &cgs, st->Ist.IMark.len, cia );
915 break;
916
917 case Ist_Tmp: {
918 IRExpr* data = st->Ist.Tmp.data;
919 if (data->tag == Iex_Load) {
920 IRExpr* aexpr = data->Iex.Load.addr;
921 tl_assert( isIRAtom(aexpr) );
922 // Note also, endianness info is ignored. I guess
923 // that's not interesting.
924 addEvent_Dr( &cgs, sizeofIRType(data->Iex.Load.ty),
925 cia, aexpr );
926 }
927 break;
njnb3507ea2005-08-02 23:07:02 +0000928 }
929
sewardj5155dec2005-10-12 10:09:23 +0000930 case Ist_Store: {
931 IRExpr* data = st->Ist.Store.data;
932 IRExpr* aexpr = st->Ist.Store.addr;
933 tl_assert( isIRAtom(aexpr) );
934 addEvent_Dw( &cgs,
935 sizeofIRType(typeOfIRExpr(tyenv, data)),
936 cia, aexpr );
937 break;
938 }
njnb3507ea2005-08-02 23:07:02 +0000939
sewardj5155dec2005-10-12 10:09:23 +0000940 case Ist_Dirty: {
941 Int dataSize;
942 IRDirty* d = st->Ist.Dirty.details;
943 if (d->mFx != Ifx_None) {
944 /* This dirty helper accesses memory. Collect the
945 details. */
946 tl_assert(d->mAddr != NULL);
947 tl_assert(d->mSize != 0);
948 dataSize = d->mSize;
949 // Large (eg. 28B, 108B, 512B on x86) data-sized
950 // instructions will be done inaccurately, but they're
951 // very rare and this avoids errors from hitting more
952 // than two cache lines in the simulation.
953 if (dataSize > MIN_LINE_SIZE)
954 dataSize = MIN_LINE_SIZE;
955 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
956 addEvent_Dr( &cgs, dataSize, cia, d->mAddr );
957 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
958 addEvent_Dw( &cgs, dataSize, cia, d->mAddr );
959 } else {
960 tl_assert(d->mAddr == NULL);
961 tl_assert(d->mSize == 0);
962 }
963 break;
964 }
njn6a3009b2005-03-20 00:20:06 +0000965
sewardj5155dec2005-10-12 10:09:23 +0000966 case Ist_Exit:
967 /* We may never reach the next statement, so need to flush
968 all outstanding transactions now. */
969 flushEvents( &cgs );
970 break;
971
972 default:
973 tl_assert(0);
974 break;
njnb3507ea2005-08-02 23:07:02 +0000975 }
njn6a3009b2005-03-20 00:20:06 +0000976
sewardj5155dec2005-10-12 10:09:23 +0000977 /* Copy the original statement */
978 addStmtToIRBB( cgs.bbOut, st );
njn6a3009b2005-03-20 00:20:06 +0000979
sewardj5155dec2005-10-12 10:09:23 +0000980 if (DEBUG_CG) {
981 ppIRStmt(st);
982 VG_(printf)("\n");
983 }
984 }
985
986 /* At the end of the bb. Flush outstandings. */
987 tl_assert(isIRAtom(bbIn->next));
988 flushEvents( &cgs );
989
990 /* copy where-next stuff. */
991 cgs.bbOut->next = dopyIRExpr(bbIn->next);
992 cgs.bbOut->jumpkind = bbIn->jumpkind;
993
994 /* done. stay sane ... */
995 tl_assert(cgs.bbInfo_i == cgs.bbInfo->n_instrs);
996
997 if (DEBUG_CG) {
998 VG_(printf)( "goto {");
999 ppIRJumpKind(bbIn->jumpkind);
1000 VG_(printf)( "} ");
1001 ppIRExpr( bbIn->next );
1002 VG_(printf)( "}\n");
1003 }
1004
1005 return cgs.bbOut;
njn14d01ce2004-11-26 11:30:14 +00001006}
njn4f9c9342002-04-29 16:03:24 +00001007
1008/*------------------------------------------------------------*/
nethercoteb35a8b92004-09-11 16:45:27 +00001009/*--- Cache configuration ---*/
njn4f9c9342002-04-29 16:03:24 +00001010/*------------------------------------------------------------*/
1011
sewardjb5f6f512005-03-10 23:59:00 +00001012#define UNDEFINED_CACHE { -1, -1, -1 }
njn25e49d8e72002-09-23 09:36:25 +00001013
1014static cache_t clo_I1_cache = UNDEFINED_CACHE;
1015static cache_t clo_D1_cache = UNDEFINED_CACHE;
1016static cache_t clo_L2_cache = UNDEFINED_CACHE;
1017
njn7cf0bd32002-06-08 13:36:03 +00001018/* Checks cache config is ok; makes it so if not. */
sewardj07133bf2002-06-13 10:25:56 +00001019static
njna1d1a642004-11-26 18:36:02 +00001020void check_cache(cache_t* cache, Char *name)
njn7cf0bd32002-06-08 13:36:03 +00001021{
1022 /* First check they're all powers of two */
sewardj07133bf2002-06-13 10:25:56 +00001023 if (-1 == VG_(log2)(cache->size)) {
njn7cf0bd32002-06-08 13:36:03 +00001024 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +00001025 "error: %s size of %dB not a power of two; aborting.",
1026 name, cache->size);
1027 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +00001028 }
1029
sewardj07133bf2002-06-13 10:25:56 +00001030 if (-1 == VG_(log2)(cache->assoc)) {
njn7cf0bd32002-06-08 13:36:03 +00001031 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +00001032 "error: %s associativity of %d not a power of two; aborting.",
1033 name, cache->assoc);
1034 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +00001035 }
1036
sewardj07133bf2002-06-13 10:25:56 +00001037 if (-1 == VG_(log2)(cache->line_size)) {
njn7cf0bd32002-06-08 13:36:03 +00001038 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +00001039 "error: %s line size of %dB not a power of two; aborting.",
1040 name, cache->line_size);
1041 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +00001042 }
1043
njn6a3009b2005-03-20 00:20:06 +00001044 // Then check line size >= 16 -- any smaller and a single instruction could
1045 // straddle three cache lines, which breaks a simulation assertion and is
1046 // stupid anyway.
njn7cf0bd32002-06-08 13:36:03 +00001047 if (cache->line_size < MIN_LINE_SIZE) {
1048 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +00001049 "error: %s line size of %dB too small; aborting.",
1050 name, cache->line_size);
1051 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +00001052 }
1053
1054 /* Then check cache size > line size (causes seg faults if not). */
1055 if (cache->size <= cache->line_size) {
1056 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +00001057 "error: %s cache size of %dB <= line size of %dB; aborting.",
1058 name, cache->size, cache->line_size);
1059 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +00001060 }
1061
1062 /* Then check assoc <= (size / line size) (seg faults otherwise). */
1063 if (cache->assoc > (cache->size / cache->line_size)) {
1064 VG_(message)(Vg_UserMsg,
njna1d1a642004-11-26 18:36:02 +00001065 "warning: %s associativity > (size / line size); aborting.", name);
1066 VG_(exit)(1);
njn7cf0bd32002-06-08 13:36:03 +00001067 }
1068}
1069
sewardj07133bf2002-06-13 10:25:56 +00001070static
nethercoteb35a8b92004-09-11 16:45:27 +00001071void configure_caches(cache_t* I1c, cache_t* D1c, cache_t* L2c)
njn7cf0bd32002-06-08 13:36:03 +00001072{
nethercote9313ac42004-07-06 21:54:20 +00001073#define DEFINED(L) (-1 != L.size || -1 != L.assoc || -1 != L.line_size)
1074
nethercoteb35a8b92004-09-11 16:45:27 +00001075 Int n_clos = 0;
nethercote9313ac42004-07-06 21:54:20 +00001076
nethercoteb35a8b92004-09-11 16:45:27 +00001077 // Count how many were defined on the command line.
1078 if (DEFINED(clo_I1_cache)) { n_clos++; }
1079 if (DEFINED(clo_D1_cache)) { n_clos++; }
1080 if (DEFINED(clo_L2_cache)) { n_clos++; }
njn7cf0bd32002-06-08 13:36:03 +00001081
njna1d1a642004-11-26 18:36:02 +00001082 // Set the cache config (using auto-detection, if supported by the
1083 // architecture)
njnaf839f52005-06-23 03:27:57 +00001084 VG_(configure_caches)( I1c, D1c, L2c, (3 == n_clos) );
sewardjb1a77a42002-07-13 13:31:20 +00001085
nethercote9313ac42004-07-06 21:54:20 +00001086 // Then replace with any defined on the command line.
nethercoteb35a8b92004-09-11 16:45:27 +00001087 if (DEFINED(clo_I1_cache)) { *I1c = clo_I1_cache; }
1088 if (DEFINED(clo_D1_cache)) { *D1c = clo_D1_cache; }
1089 if (DEFINED(clo_L2_cache)) { *L2c = clo_L2_cache; }
njn7cf0bd32002-06-08 13:36:03 +00001090
nethercote9313ac42004-07-06 21:54:20 +00001091 // Then check values and fix if not acceptable.
njna1d1a642004-11-26 18:36:02 +00001092 check_cache(I1c, "I1");
1093 check_cache(D1c, "D1");
1094 check_cache(L2c, "L2");
njn7cf0bd32002-06-08 13:36:03 +00001095
1096 if (VG_(clo_verbosity) > 1) {
1097 VG_(message)(Vg_UserMsg, "Cache configuration used:");
1098 VG_(message)(Vg_UserMsg, " I1: %dB, %d-way, %dB lines",
1099 I1c->size, I1c->assoc, I1c->line_size);
1100 VG_(message)(Vg_UserMsg, " D1: %dB, %d-way, %dB lines",
1101 D1c->size, D1c->assoc, D1c->line_size);
1102 VG_(message)(Vg_UserMsg, " L2: %dB, %d-way, %dB lines",
1103 L2c->size, L2c->assoc, L2c->line_size);
1104 }
nethercote9313ac42004-07-06 21:54:20 +00001105#undef CMD_LINE_DEFINED
njn7cf0bd32002-06-08 13:36:03 +00001106}
1107
njn4f9c9342002-04-29 16:03:24 +00001108/*------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +00001109/*--- cg_fini() and related function ---*/
njn4f9c9342002-04-29 16:03:24 +00001110/*------------------------------------------------------------*/
1111
nethercote9313ac42004-07-06 21:54:20 +00001112// Total reads/writes/misses. Calculated during CC traversal at the end.
1113// All auto-zeroed.
1114static CC Ir_total;
1115static CC Dr_total;
1116static CC Dw_total;
1117
1118static Char* cachegrind_out_file;
1119
nethercote9313ac42004-07-06 21:54:20 +00001120static void fprint_lineCC(Int fd, lineCC* n)
njn4f9c9342002-04-29 16:03:24 +00001121{
nethercote9313ac42004-07-06 21:54:20 +00001122 Char buf[512];
1123 VG_(sprintf)(buf, "%u %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
1124 n->line,
1125 n->Ir.a, n->Ir.m1, n->Ir.m2,
1126 n->Dr.a, n->Dr.m1, n->Dr.m2,
1127 n->Dw.a, n->Dw.m1, n->Dw.m2);
1128 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1129
1130 Ir_total.a += n->Ir.a; Ir_total.m1 += n->Ir.m1; Ir_total.m2 += n->Ir.m2;
1131 Dr_total.a += n->Dr.a; Dr_total.m1 += n->Dr.m1; Dr_total.m2 += n->Dr.m2;
1132 Dw_total.a += n->Dw.a; Dw_total.m1 += n->Dw.m1; Dw_total.m2 += n->Dw.m2;
1133}
1134
1135static void fprint_CC_table_and_calc_totals(void)
1136{
1137 Int fd;
sewardj92645592005-07-23 09:18:34 +00001138 SysRes sres;
nethercote9313ac42004-07-06 21:54:20 +00001139 Char buf[512];
1140 fileCC *curr_fileCC;
1141 fnCC *curr_fnCC;
1142 lineCC *curr_lineCC;
1143 Int i, j, k;
njn4f9c9342002-04-29 16:03:24 +00001144
njn25e49d8e72002-09-23 09:36:25 +00001145 VGP_PUSHCC(VgpCacheResults);
njn13f02932003-04-30 20:23:58 +00001146
sewardj92645592005-07-23 09:18:34 +00001147 sres = VG_(open)(cachegrind_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
1148 VKI_S_IRUSR|VKI_S_IWUSR);
1149 if (sres.isError) {
nethercote9313ac42004-07-06 21:54:20 +00001150 // If the file can't be opened for whatever reason (conflict
1151 // between multiple cachegrinded processes?), give up now.
njnee0e6a32005-04-24 00:21:01 +00001152 VG_(message)(Vg_UserMsg,
njn02bc4b82005-05-15 17:28:26 +00001153 "error: can't open cache simulation output file '%s'",
njnee0e6a32005-04-24 00:21:01 +00001154 cachegrind_out_file );
1155 VG_(message)(Vg_UserMsg,
1156 " ... so simulation results will be missing.");
sewardj0744b6c2002-12-11 00:45:42 +00001157 return;
sewardj92645592005-07-23 09:18:34 +00001158 } else {
1159 fd = sres.val;
sewardj0744b6c2002-12-11 00:45:42 +00001160 }
njn4f9c9342002-04-29 16:03:24 +00001161
nethercote9313ac42004-07-06 21:54:20 +00001162 // "desc:" lines (giving I1/D1/L2 cache configuration). The spaces after
1163 // the 2nd colon makes cg_annotate's output look nicer.
1164 VG_(sprintf)(buf, "desc: I1 cache: %s\n"
1165 "desc: D1 cache: %s\n"
1166 "desc: L2 cache: %s\n",
1167 I1.desc_line, D1.desc_line, L2.desc_line);
njn7cf0bd32002-06-08 13:36:03 +00001168 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
njn4f9c9342002-04-29 16:03:24 +00001169
nethercote9313ac42004-07-06 21:54:20 +00001170 // "cmd:" line
njn4f9c9342002-04-29 16:03:24 +00001171 VG_(strcpy)(buf, "cmd:");
1172 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
sewardj45f4e7c2005-09-27 19:20:21 +00001173 if (VG_(args_the_exename)) {
1174 VG_(write)(fd, " ", 1);
1175 VG_(write)(fd, VG_(args_the_exename),
1176 VG_(strlen)( VG_(args_the_exename) ));
1177 }
1178 for (i = 0; i < VG_(args_for_client).used; i++) {
1179 if (VG_(args_for_client).strs[i]) {
1180 VG_(write)(fd, " ", 1);
1181 VG_(write)(fd, VG_(args_for_client).strs[i],
1182 VG_(strlen)(VG_(args_for_client).strs[i]));
1183 }
njn4f9c9342002-04-29 16:03:24 +00001184 }
nethercote9313ac42004-07-06 21:54:20 +00001185 // "events:" line
njn4f9c9342002-04-29 16:03:24 +00001186 VG_(sprintf)(buf, "\nevents: Ir I1mr I2mr Dr D1mr D2mr Dw D1mw D2mw\n");
1187 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1188
nethercote9313ac42004-07-06 21:54:20 +00001189 // Six loops here: three for the hash table arrays, and three for the
1190 // chains hanging off the hash table arrays.
njn4f9c9342002-04-29 16:03:24 +00001191 for (i = 0; i < N_FILE_ENTRIES; i++) {
nethercote9313ac42004-07-06 21:54:20 +00001192 curr_fileCC = CC_table[i];
1193 while (curr_fileCC != NULL) {
1194 VG_(sprintf)(buf, "fl=%s\n", curr_fileCC->file);
njn4f9c9342002-04-29 16:03:24 +00001195 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1196
1197 for (j = 0; j < N_FN_ENTRIES; j++) {
nethercote9313ac42004-07-06 21:54:20 +00001198 curr_fnCC = curr_fileCC->fns[j];
1199 while (curr_fnCC != NULL) {
1200 VG_(sprintf)(buf, "fn=%s\n", curr_fnCC->fn);
njn4f9c9342002-04-29 16:03:24 +00001201 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1202
nethercote9313ac42004-07-06 21:54:20 +00001203 for (k = 0; k < N_LINE_ENTRIES; k++) {
1204 curr_lineCC = curr_fnCC->lines[k];
1205 while (curr_lineCC != NULL) {
1206 fprint_lineCC(fd, curr_lineCC);
1207 curr_lineCC = curr_lineCC->next;
njn4f9c9342002-04-29 16:03:24 +00001208 }
1209 }
nethercote9313ac42004-07-06 21:54:20 +00001210 curr_fnCC = curr_fnCC->next;
njn4f9c9342002-04-29 16:03:24 +00001211 }
1212 }
nethercote9313ac42004-07-06 21:54:20 +00001213 curr_fileCC = curr_fileCC->next;
njn4f9c9342002-04-29 16:03:24 +00001214 }
1215 }
1216
nethercote9313ac42004-07-06 21:54:20 +00001217 // Summary stats must come after rest of table, since we calculate them
1218 // during traversal. */
njn4f9c9342002-04-29 16:03:24 +00001219 VG_(sprintf)(buf, "summary: "
nethercote9313ac42004-07-06 21:54:20 +00001220 "%llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
njn4f9c9342002-04-29 16:03:24 +00001221 Ir_total.a, Ir_total.m1, Ir_total.m2,
1222 Dr_total.a, Dr_total.m1, Dr_total.m2,
1223 Dw_total.a, Dw_total.m1, Dw_total.m2);
1224 VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
1225 VG_(close)(fd);
1226}
1227
njn607adfc2003-09-30 14:15:44 +00001228static UInt ULong_width(ULong n)
njn4f9c9342002-04-29 16:03:24 +00001229{
njn607adfc2003-09-30 14:15:44 +00001230 UInt w = 0;
1231 while (n > 0) {
1232 n = n / 10;
1233 w++;
njn4f9c9342002-04-29 16:03:24 +00001234 }
njn607adfc2003-09-30 14:15:44 +00001235 return w + (w-1)/3; // add space for commas
njn4f9c9342002-04-29 16:03:24 +00001236}
1237
njn51d827b2005-05-09 01:02:08 +00001238static void cg_fini(Int exitcode)
njn4f9c9342002-04-29 16:03:24 +00001239{
njn0103de52005-10-10 16:49:01 +00001240 static Char buf1[128], buf2[128], buf3[128], fmt [128];
njn607adfc2003-09-30 14:15:44 +00001241
njn4f9c9342002-04-29 16:03:24 +00001242 CC D_total;
njn1d021fa2002-05-02 13:56:34 +00001243 ULong L2_total_m, L2_total_mr, L2_total_mw,
1244 L2_total, L2_total_r, L2_total_w;
njn4f9c9342002-04-29 16:03:24 +00001245 Int l1, l2, l3;
1246 Int p;
1247
nethercote9313ac42004-07-06 21:54:20 +00001248 fprint_CC_table_and_calc_totals();
njn4f9c9342002-04-29 16:03:24 +00001249
njn7cf0bd32002-06-08 13:36:03 +00001250 if (VG_(clo_verbosity) == 0)
1251 return;
1252
njn4f9c9342002-04-29 16:03:24 +00001253 /* I cache results. Use the I_refs value to determine the first column
1254 * width. */
njn607adfc2003-09-30 14:15:44 +00001255 l1 = ULong_width(Ir_total.a);
1256 l2 = ULong_width(Dr_total.a);
1257 l3 = ULong_width(Dw_total.a);
njn4f9c9342002-04-29 16:03:24 +00001258
njn607adfc2003-09-30 14:15:44 +00001259 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001260 VG_(sprintf)(fmt, "%%s %%,%dllu", l1);
njn607adfc2003-09-30 14:15:44 +00001261
1262 VG_(message)(Vg_UserMsg, fmt, "I refs: ", Ir_total.a);
1263 VG_(message)(Vg_UserMsg, fmt, "I1 misses: ", Ir_total.m1);
1264 VG_(message)(Vg_UserMsg, fmt, "L2i misses: ", Ir_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001265
1266 p = 100;
1267
njn25e49d8e72002-09-23 09:36:25 +00001268 if (0 == Ir_total.a) Ir_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001269 VG_(percentify)(Ir_total.m1, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001270 VG_(message)(Vg_UserMsg, "I1 miss rate: %s", buf1);
1271
njn856c54e2005-06-26 18:43:40 +00001272 VG_(percentify)(Ir_total.m2, Ir_total.a, 2, l1+1, buf1);
njn4f9c9342002-04-29 16:03:24 +00001273 VG_(message)(Vg_UserMsg, "L2i miss rate: %s", buf1);
1274 VG_(message)(Vg_UserMsg, "");
1275
1276 /* D cache results. Use the D_refs.rd and D_refs.wr values to determine the
1277 * width of columns 2 & 3. */
1278 D_total.a = Dr_total.a + Dw_total.a;
1279 D_total.m1 = Dr_total.m1 + Dw_total.m1;
1280 D_total.m2 = Dr_total.m2 + Dw_total.m2;
1281
njn607adfc2003-09-30 14:15:44 +00001282 /* Make format string, getting width right for numbers */
njn99cb9e32005-09-25 17:59:16 +00001283 VG_(sprintf)(fmt, "%%s %%,%dllu (%%,%dllu rd + %%,%dllu wr)", l1, l2, l3);
njn4f9c9342002-04-29 16:03:24 +00001284
njn607adfc2003-09-30 14:15:44 +00001285 VG_(message)(Vg_UserMsg, fmt, "D refs: ",
1286 D_total.a, Dr_total.a, Dw_total.a);
1287 VG_(message)(Vg_UserMsg, fmt, "D1 misses: ",
1288 D_total.m1, Dr_total.m1, Dw_total.m1);
1289 VG_(message)(Vg_UserMsg, fmt, "L2d misses: ",
1290 D_total.m2, Dr_total.m2, Dw_total.m2);
njn4f9c9342002-04-29 16:03:24 +00001291
1292 p = 10;
1293
njn25e49d8e72002-09-23 09:36:25 +00001294 if (0 == D_total.a) D_total.a = 1;
1295 if (0 == Dr_total.a) Dr_total.a = 1;
1296 if (0 == Dw_total.a) Dw_total.a = 1;
njn856c54e2005-06-26 18:43:40 +00001297 VG_(percentify)( D_total.m1, D_total.a, 1, l1+1, buf1);
1298 VG_(percentify)(Dr_total.m1, Dr_total.a, 1, l2+1, buf2);
1299 VG_(percentify)(Dw_total.m1, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001300 VG_(message)(Vg_UserMsg, "D1 miss rate: %s (%s + %s )", buf1, buf2,buf3);
1301
njn856c54e2005-06-26 18:43:40 +00001302 VG_(percentify)( D_total.m2, D_total.a, 1, l1+1, buf1);
1303 VG_(percentify)(Dr_total.m2, Dr_total.a, 1, l2+1, buf2);
1304 VG_(percentify)(Dw_total.m2, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001305 VG_(message)(Vg_UserMsg, "L2d miss rate: %s (%s + %s )", buf1, buf2,buf3);
1306 VG_(message)(Vg_UserMsg, "");
1307
1308 /* L2 overall results */
njn1d021fa2002-05-02 13:56:34 +00001309
1310 L2_total = Dr_total.m1 + Dw_total.m1 + Ir_total.m1;
1311 L2_total_r = Dr_total.m1 + Ir_total.m1;
1312 L2_total_w = Dw_total.m1;
njn607adfc2003-09-30 14:15:44 +00001313 VG_(message)(Vg_UserMsg, fmt, "L2 refs: ",
1314 L2_total, L2_total_r, L2_total_w);
njn1d021fa2002-05-02 13:56:34 +00001315
njn4f9c9342002-04-29 16:03:24 +00001316 L2_total_m = Dr_total.m2 + Dw_total.m2 + Ir_total.m2;
1317 L2_total_mr = Dr_total.m2 + Ir_total.m2;
1318 L2_total_mw = Dw_total.m2;
njn607adfc2003-09-30 14:15:44 +00001319 VG_(message)(Vg_UserMsg, fmt, "L2 misses: ",
1320 L2_total_m, L2_total_mr, L2_total_mw);
njn4f9c9342002-04-29 16:03:24 +00001321
njn856c54e2005-06-26 18:43:40 +00001322 VG_(percentify)(L2_total_m, (Ir_total.a + D_total.a), 1, l1+1, buf1);
1323 VG_(percentify)(L2_total_mr, (Ir_total.a + Dr_total.a), 1, l2+1, buf2);
1324 VG_(percentify)(L2_total_mw, Dw_total.a, 1, l3+1, buf3);
njn4f9c9342002-04-29 16:03:24 +00001325 VG_(message)(Vg_UserMsg, "L2 miss rate: %s (%s + %s )", buf1, buf2,buf3);
1326
1327
nethercote9313ac42004-07-06 21:54:20 +00001328 // Various stats
njn4f9c9342002-04-29 16:03:24 +00001329 if (VG_(clo_verbosity) > 1) {
njn0103de52005-10-10 16:49:01 +00001330 Int BB_lookups = full_debug_BBs + fn_debug_BBs +
njn4f9c9342002-04-29 16:03:24 +00001331 file_line_debug_BBs + no_debug_BBs;
1332
1333 VG_(message)(Vg_DebugMsg, "");
1334 VG_(message)(Vg_DebugMsg, "Distinct files: %d", distinct_files);
1335 VG_(message)(Vg_DebugMsg, "Distinct fns: %d", distinct_fns);
nethercote9313ac42004-07-06 21:54:20 +00001336 VG_(message)(Vg_DebugMsg, "Distinct lines: %d", distinct_lines);
1337 VG_(message)(Vg_DebugMsg, "Distinct instrs: %d", distinct_instrs);
njn4f9c9342002-04-29 16:03:24 +00001338 VG_(message)(Vg_DebugMsg, "BB lookups: %d", BB_lookups);
1339 VG_(message)(Vg_DebugMsg, "With full debug info:%3d%% (%d)",
1340 full_debug_BBs * 100 / BB_lookups,
1341 full_debug_BBs);
1342 VG_(message)(Vg_DebugMsg, "With file/line debug info:%3d%% (%d)",
1343 file_line_debug_BBs * 100 / BB_lookups,
1344 file_line_debug_BBs);
1345 VG_(message)(Vg_DebugMsg, "With fn name debug info:%3d%% (%d)",
nethercote9313ac42004-07-06 21:54:20 +00001346 fn_debug_BBs * 100 / BB_lookups,
1347 fn_debug_BBs);
njn4f9c9342002-04-29 16:03:24 +00001348 VG_(message)(Vg_DebugMsg, "With no debug info:%3d%% (%d)",
1349 no_debug_BBs * 100 / BB_lookups,
1350 no_debug_BBs);
1351 VG_(message)(Vg_DebugMsg, "BBs Retranslated: %d", BB_retranslations);
njn4f9c9342002-04-29 16:03:24 +00001352 }
njn25e49d8e72002-09-23 09:36:25 +00001353 VGP_POPCC(VgpCacheResults);
sewardj5155dec2005-10-12 10:09:23 +00001354
1355 if (0) { Int i;
1356 for (i = 0; i < 64; i++) {
1357 show3(i); VG_(printf)(" %5d\n", trigrams[i] );
1358 }
1359 }
njn4f9c9342002-04-29 16:03:24 +00001360}
1361
nethercote9313ac42004-07-06 21:54:20 +00001362/*--------------------------------------------------------------------*/
1363/*--- Discarding BB info ---*/
1364/*--------------------------------------------------------------------*/
sewardj18d75132002-05-16 11:06:21 +00001365
nethercote9313ac42004-07-06 21:54:20 +00001366// Called when a translation is invalidated due to code unloading.
sewardj5155dec2005-10-12 10:09:23 +00001367static void cg_discard_basic_block_info ( VexGuestExtents vge )
sewardj18d75132002-05-16 11:06:21 +00001368{
sewardj5155dec2005-10-12 10:09:23 +00001369 VgHashNode* bbInfo;
njn4294fd42002-06-05 14:41:10 +00001370
sewardj5155dec2005-10-12 10:09:23 +00001371 tl_assert(vge.n_used > 0);
1372
1373 if (DEBUG_CG)
1374 VG_(printf)( "discard_basic_block_info: %p, %llu\n",
1375 (void*)(Addr)vge.base[0], (ULong)vge.len[0]);
njn4294fd42002-06-05 14:41:10 +00001376
nethercote9313ac42004-07-06 21:54:20 +00001377 // Get BB info, remove from table, free BB info. Simple!
sewardj5155dec2005-10-12 10:09:23 +00001378 bbInfo = VG_(HT_remove)(instr_info_table, (UWord)vge.base[0]);
njn6a3009b2005-03-20 00:20:06 +00001379 tl_assert(NULL != bbInfo);
sewardj5155dec2005-10-12 10:09:23 +00001380
njn6a3009b2005-03-20 00:20:06 +00001381 VG_(free)(bbInfo);
sewardj18d75132002-05-16 11:06:21 +00001382}
1383
1384/*--------------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001385/*--- Command line processing ---*/
1386/*--------------------------------------------------------------------*/
1387
njn0103de52005-10-10 16:49:01 +00001388static void parse_cache_opt ( cache_t* cache, Char* opt )
njn25e49d8e72002-09-23 09:36:25 +00001389{
njn0103de52005-10-10 16:49:01 +00001390 Int i = 0, i2, i3;
njn25e49d8e72002-09-23 09:36:25 +00001391
nethercote9313ac42004-07-06 21:54:20 +00001392 // Option argument looks like "65536,2,64".
1393 // Find commas, replace with NULs to make three independent
1394 // strings, then extract numbers, put NULs back. Yuck.
njn25e49d8e72002-09-23 09:36:25 +00001395 while (VG_(isdigit)(opt[i])) i++;
1396 if (',' == opt[i]) {
1397 opt[i++] = '\0';
1398 i2 = i;
1399 } else goto bad;
1400 while (VG_(isdigit)(opt[i])) i++;
1401 if (',' == opt[i]) {
1402 opt[i++] = '\0';
1403 i3 = i;
1404 } else goto bad;
1405 while (VG_(isdigit)(opt[i])) i++;
1406 if ('\0' != opt[i]) goto bad;
1407
nethercote9313ac42004-07-06 21:54:20 +00001408 cache->size = (Int)VG_(atoll)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001409 cache->assoc = (Int)VG_(atoll)(opt + i2);
1410 cache->line_size = (Int)VG_(atoll)(opt + i3);
1411
nethercote9313ac42004-07-06 21:54:20 +00001412 opt[i2-1] = ',';
1413 opt[i3-1] = ',';
njn25e49d8e72002-09-23 09:36:25 +00001414 return;
1415
1416 bad:
nethercote9313ac42004-07-06 21:54:20 +00001417 VG_(bad_option)(opt);
njn25e49d8e72002-09-23 09:36:25 +00001418}
1419
njn51d827b2005-05-09 01:02:08 +00001420static Bool cg_process_cmd_line_option(Char* arg)
njn25e49d8e72002-09-23 09:36:25 +00001421{
nethercote9313ac42004-07-06 21:54:20 +00001422 // 5 is length of "--I1="
njn39c86652003-05-21 10:13:39 +00001423 if (VG_CLO_STREQN(5, arg, "--I1="))
nethercote9313ac42004-07-06 21:54:20 +00001424 parse_cache_opt(&clo_I1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001425 else if (VG_CLO_STREQN(5, arg, "--D1="))
nethercote9313ac42004-07-06 21:54:20 +00001426 parse_cache_opt(&clo_D1_cache, &arg[5]);
njn39c86652003-05-21 10:13:39 +00001427 else if (VG_CLO_STREQN(5, arg, "--L2="))
nethercote9313ac42004-07-06 21:54:20 +00001428 parse_cache_opt(&clo_L2_cache, &arg[5]);
njn25e49d8e72002-09-23 09:36:25 +00001429 else
1430 return False;
1431
1432 return True;
1433}
1434
njn51d827b2005-05-09 01:02:08 +00001435static void cg_print_usage(void)
njn25e49d8e72002-09-23 09:36:25 +00001436{
njn3e884182003-04-15 13:03:23 +00001437 VG_(printf)(
njn25e49d8e72002-09-23 09:36:25 +00001438" --I1=<size>,<assoc>,<line_size> set I1 cache manually\n"
1439" --D1=<size>,<assoc>,<line_size> set D1 cache manually\n"
njn3e884182003-04-15 13:03:23 +00001440" --L2=<size>,<assoc>,<line_size> set L2 cache manually\n"
1441 );
1442}
1443
njn51d827b2005-05-09 01:02:08 +00001444static void cg_print_debug_usage(void)
njn3e884182003-04-15 13:03:23 +00001445{
1446 VG_(printf)(
1447" (none)\n"
1448 );
njn25e49d8e72002-09-23 09:36:25 +00001449}
1450
1451/*--------------------------------------------------------------------*/
1452/*--- Setup ---*/
1453/*--------------------------------------------------------------------*/
1454
njn51d827b2005-05-09 01:02:08 +00001455static void cg_post_clo_init(void)
njn25e49d8e72002-09-23 09:36:25 +00001456{
1457 cache_t I1c, D1c, L2c;
njn25e49d8e72002-09-23 09:36:25 +00001458
nethercoteb35a8b92004-09-11 16:45:27 +00001459 configure_caches(&I1c, &D1c, &L2c);
njn25e49d8e72002-09-23 09:36:25 +00001460
1461 cachesim_I1_initcache(I1c);
1462 cachesim_D1_initcache(D1c);
1463 cachesim_L2_initcache(L2c);
1464
njn31066fd2005-03-26 00:42:02 +00001465 VG_(register_profile_event)(VgpGetLineCC, "get-lineCC");
1466 VG_(register_profile_event)(VgpCacheSimulate, "cache-simulate");
1467 VG_(register_profile_event)(VgpCacheResults, "cache-results");
njn25e49d8e72002-09-23 09:36:25 +00001468}
1469
njn57ca7ab2005-06-21 23:44:58 +00001470static Char base_dir[VKI_PATH_MAX];
1471
njn51d827b2005-05-09 01:02:08 +00001472static void cg_pre_clo_init(void)
1473{
njn51d827b2005-05-09 01:02:08 +00001474 VG_(details_name) ("Cachegrind");
1475 VG_(details_version) (NULL);
1476 VG_(details_description) ("an I1/D1/L2 cache profiler");
1477 VG_(details_copyright_author)(
1478 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote et al.");
1479 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj5155dec2005-10-12 10:09:23 +00001480 VG_(details_avg_translation_sizeB) ( 245 );
njn51d827b2005-05-09 01:02:08 +00001481
1482 VG_(basic_tool_funcs) (cg_post_clo_init,
1483 cg_instrument,
1484 cg_fini);
1485
1486 VG_(needs_basic_block_discards)(cg_discard_basic_block_info);
1487 VG_(needs_command_line_options)(cg_process_cmd_line_option,
1488 cg_print_usage,
1489 cg_print_debug_usage);
1490
1491 /* Get working directory */
njn57ca7ab2005-06-21 23:44:58 +00001492 tl_assert( VG_(getcwd)(base_dir, VKI_PATH_MAX) );
njn51d827b2005-05-09 01:02:08 +00001493
1494 /* Block is big enough for dir name + cachegrind.out.<pid> */
1495 cachegrind_out_file = VG_(malloc)((VG_(strlen)(base_dir) + 32)*sizeof(Char));
1496 VG_(sprintf)(cachegrind_out_file, "%s/cachegrind.out.%d",
1497 base_dir, VG_(getpid)());
njn51d827b2005-05-09 01:02:08 +00001498
njnf69f9452005-07-03 17:53:11 +00001499 instr_info_table = VG_(HT_construct)( 4999 ); // prime, biggish
njn51d827b2005-05-09 01:02:08 +00001500}
1501
sewardj45f4e7c2005-09-27 19:20:21 +00001502VG_DETERMINE_INTERFACE_VERSION(cg_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00001503
njn25e49d8e72002-09-23 09:36:25 +00001504/*--------------------------------------------------------------------*/
njnf69f9452005-07-03 17:53:11 +00001505/*--- end ---*/
sewardj18d75132002-05-16 11:06:21 +00001506/*--------------------------------------------------------------------*/